/* ─────────────────────────────────────────────────────────────────────────
   Dashboard — premium rebuild (Step 5)
   Adapts premium-updates/view-dashboard.jsx to the existing
   window.MFDashboard({ profile, onSignOut, onEditBrand }) API.
   GuestPreviewView and MesasView are kept verbatim (Firebase + real QRs).
   ───────────────────────────────────────────────────────────────────────── */

const { useState: usD, useEffect: useEffD } = React;

function useMobileD() {
  const [m, setM] = usD(() => window.innerWidth < 768);
  useEffD(() => {
    const fn = () => setM(window.innerWidth < 768);
    window.addEventListener('resize', fn);
    return () => window.removeEventListener('resize', fn);
  }, []);
  return m;
}

/* ── Firestore hooks for live dashboard data ─────────────────────────── */

/** Maps firebase-bridge kitchen statuses to our dashboard status labels */
const KITCHEN_STATUS_MAP = {
  open:    'ordering',
  sent:    'kitchen',
  pending: 'kitchen',
  kitchen: 'kitchen',
  ready:   'ready',
  served:  'ready',
  paid:    'paying',
};

const EVENT_TYPE_META = {
  'order.sent':      { icon: 'fork',    tone: 'accent', label: (p) => `Mesa ${p.tableId} envió ${p.itemCount || ''} platos` },
  'order.status':    { icon: 'flame',   tone: 'sage',   label: (p) => `Mesa ${p.tableId}: ${p.status === 'ready' ? 'listo para servir' : p.status === 'kitchen' ? 'en cocina' : p.status === 'served' ? 'servido' : p.status || ''}` },
  'order.paid':      { icon: 'bell',    tone: 'mu',     label: (p) => `Mesa ${p.tableId} cerró cuenta${p.total ? ' · $' + Number(p.total).toLocaleString('es-MX') : ''}` },
  'bill.requested':  { icon: 'receipt', tone: 'warn',   label: (p) => `Mesa ${p.tableId} solicita cuenta${p.mode ? ' · ' + p.mode : ''}` },
  'help.requested':  { icon: 'bell',    tone: 'warn',   label: (p) => `Mesa ${p.tableId} llama al mesero` },
  'item.added':      { icon: 'fork',    tone: 'accent', label: (p) => `Nuevo plato en mesa ${p.tableId}` },
  'eta.extended':    { icon: 'flame',   tone: 'mu',     label: (p) => `Mesa ${p.tableId}: +${p.added || '?'} min al tiempo` },
  'eta.message':     { icon: 'flame',   tone: 'mu',     label: (p) => `Mensaje de cocina para mesa ${p.tableId}` },
};

function toDateD(v) {
  if (!v) return new Date();
  if (v instanceof Date) return v;
  if (v.toDate) return v.toDate();
  if (v.seconds != null) return new Date(v.seconds * 1000);
  return new Date(v);
}

/** Live table sessions → active tables for LiveOpsBlock */
function useLiveTablesD(restaurantId) {
  const [tables, setTables] = usD([]);
  const [loading, setLoading] = usD(true);

  useEffD(() => {
    if (!restaurantId || typeof firebase === 'undefined') {
      setLoading(false);
      return;
    }
    try {
      const db = firebase.firestore();
      const unsub = db.collection('restaurants').doc(restaurantId)
        .collection('tableSessions').onSnapshot(snap => {
          const live = snap.docs.map(d => {
            const s = d.data();
            const items = s.items || [];
            const total = items.reduce((sum, it) => sum + (it.price || 0) * (it.qty || 1), 0);
            const pax = (s.diners || []).length || 1;
            const openedAt = toDateD(s.openedAt);
            const status = s.status === 'paid' ? 'paying'
              : (KITCHEN_STATUS_MAP[s.kitchenStatus] || KITCHEN_STATUS_MAP[s.status] || 'ordering');
            return {
              id: d.id,
              pax,
              status,
              total,
              ts: openedAt.toLocaleTimeString('es-MX', { hour: '2-digit', minute: '2-digit' }),
              openedAt,
              hasItems: items.length > 0,
              helpRequest: !!s.helpRequest,
              paymentRequest: s.paymentRequest || null,
            };
          })
          // Only show tables that are actually in use (have items or diners)
          .filter(t => t.hasItems || t.status !== 'ordering');
          setTables(live);
          setLoading(false);
        }, () => { setLoading(false); });
      return unsub;
    } catch (_) { setLoading(false); }
  }, [restaurantId]);

  return { tables, loading };
}

/** Today's order history → tickets, revenue, avg ticket, avg time */
function useTodayStatsD(restaurantId) {
  const [stats, setStats] = usD({
    ticketsToday: 0, revenueToday: 0, avgTicket: 0,
    avgTimeMin: 0, ordersRaw: [],
  });
  const [loading, setLoading] = usD(true);

  useEffD(() => {
    if (!restaurantId || typeof firebase === 'undefined') {
      setLoading(false);
      return;
    }
    try {
      const db = firebase.firestore();
      const since = new Date(); since.setHours(0, 0, 0, 0);
      const ref = db.collection('restaurants').doc(restaurantId)
        .collection('orderHistory')
        .where('closedAt', '>=', firebase.firestore.Timestamp.fromDate(since))
        .orderBy('closedAt', 'desc')
        .limit(200);

      const unsub = ref.onSnapshot(snap => {
        const orders = snap.docs.map(d => ({ id: d.id, ...d.data() }));
        const ticketsToday = orders.length;
        const revenueToday = orders.reduce((s, o) => s + (o.total || 0), 0);
        const avgTicket = ticketsToday > 0 ? Math.round(revenueToday / ticketsToday) : 0;
        setStats({ ticketsToday, revenueToday, avgTicket, avgTimeMin: 0, ordersRaw: orders });
        setLoading(false);
      }, () => {
        // Index might be missing — try without filter
        db.collection('restaurants').doc(restaurantId)
          .collection('orderHistory').orderBy('closedAt', 'desc').limit(100).get()
          .then(snap => {
            const cutoff = since.getTime();
            const orders = snap.docs.map(d => ({ id: d.id, ...d.data() }))
              .filter(o => toDateD(o.closedAt).getTime() >= cutoff);
            const ticketsToday = orders.length;
            const revenueToday = orders.reduce((s, o) => s + (o.total || 0), 0);
            const avgTicket = ticketsToday > 0 ? Math.round(revenueToday / ticketsToday) : 0;
            setStats({ ticketsToday, revenueToday, avgTicket, avgTimeMin: 0, ordersRaw: orders });
            setLoading(false);
          }).catch(() => setLoading(false));
      });
      return unsub;
    } catch (_) { setLoading(false); }
  }, [restaurantId]);

  return { stats, loading };
}

/** Recent Firestore events → activity feed */
function useRecentEventsD(restaurantId, limit = 8) {
  const [events, setEvents] = usD([]);
  const [loading, setLoading] = usD(true);

  useEffD(() => {
    if (!restaurantId || typeof firebase === 'undefined') {
      setLoading(false);
      return;
    }
    try {
      const db = firebase.firestore();
      const unsub = db.collection('restaurants').doc(restaurantId)
        .collection('events').orderBy('at', 'desc').limit(limit)
        .onSnapshot(snap => {
          const mapped = snap.docs.map(d => {
            const raw = d.data();
            const meta = EVENT_TYPE_META[raw.type] || { icon: 'activity', tone: 'mu', label: () => raw.type };
            const at = toDateD(raw.at);
            const secsAgo = Math.max(0, Math.floor((Date.now() - at.getTime()) / 1000));
            let timeLabel;
            if (secsAgo < 60) timeLabel = `Hace ${secsAgo} s`;
            else if (secsAgo < 3600) timeLabel = `Hace ${Math.floor(secsAgo / 60)} min`;
            else timeLabel = `Hace ${Math.floor(secsAgo / 3600)}h`;
            return {
              id: d.id,
              icon: meta.icon,
              tone: meta.tone,
              title: meta.label(raw),
              sub: raw.tableId ? `Mesa ${raw.tableId}` : '',
              time: timeLabel,
            };
          });
          setEvents(mapped);
          setLoading(false);
        }, () => { setEvents([]); setLoading(false); });
      return unsub;
    } catch (_) { setLoading(false); }
  }, [restaurantId, limit]);

  return { events, loading };
}

/* ── Brand shape bridge ──────────────────────────────────────────────── */
function normalizeBrand(profile, restaurantId) {
  const raw = profile.brand || window.MF_BRAND;
  const rawMenu = profile.menu || window.MF_MENU;
  const nameStr = typeof raw.name === 'object'
    ? (raw.name.es || raw.name.en || 'Restaurante')
    : (raw.name || 'Restaurante');
  const taglineStr = typeof raw.tagline === 'object'
    ? (raw.tagline.es || raw.tagline.en || '')
    : (raw.tagline || '');
  const p = raw.palette || {};
  const accent     = p.gold      || '#C8451F';
  const accentDeep = p.goldDeep  || '#8A2E0F';
  const accentSoft = p.goldLight || '#F5C4B0';
  const accentTint = p.goldPale  || '#FDF0EB';
  const id = restaurantId || window.factorySlug?.(nameStr) || 'mi-restaurante';
  const categories = (rawMenu.categories || []).map(c => ({
    id: c.id,
    name: typeof c.name === 'object' ? (c.name.es || c.name.en || '') : (c.name || ''),
  }));
  const items = (rawMenu.items || []).map(it => ({
    ...it,
    cat: it.cat || it.category,
    name: typeof it.name === 'object' ? (it.name.es || it.name.en || '') : (it.name || ''),
    desc: it.desc
      ? (typeof it.desc === 'object' ? (it.desc.es || '') : it.desc)
      : (it.description
        ? (typeof it.description === 'object' ? (it.description.es || '') : it.description)
        : ''),
    tags: it.tags || [],
    img: it.img || null,
    price: it.price || 0,
  }));
  return {
    id,
    name:      nameStr,
    tagline:   taglineStr,
    subtitle:  raw.subtitle || '',
    location:  raw.subtitle || '',
    founded:   raw.founded  || '',
    hours:     raw.hours    || 'Lun – Dom · 13:00 – 22:00',
    quote:     taglineStr   || 'Sabor que cuenta historias.',
    cover:     raw.cover    || null,
    accent, accentDeep, accentSoft, accentTint,
    palette:   p,
    categories, items,
    logoUrl:   profile.logoUrl || null,
  };
}

/* ── Guest mini-phone (backward compat) ──────────────────────────────── */
function GuestMiniPhone({ brand, menu }) {
  const p = brand.palette || {};
  const cats = menu?.categories || [];
  const items = menu?.items || [];
  const firstCat = cats[0]?.id;
  const shown = (firstCat ? items.filter(it => (it.cat || it.category) === firstCat) : items).slice(0, 3);
  const bg   = p.bg   || '#0b0805';
  const s2   = p.s2   || '#1f1a11';
  const gold = p.gold || '#c49a3c';
  const tx   = p.tx   || '#f0e8d8';
  const mu   = p.mu   || '#a09070';
  const line = p.line || 'rgba(255,255,255,0.07)';
  const tagline = typeof brand.tagline === 'object' ? (brand.tagline.es || '') : (brand.tagline || '');
  return (
    <div style={{ width: 180, height: 310, background: bg, borderRadius: 18, overflow: 'hidden', display: 'flex', flexDirection: 'column', fontFamily: 'var(--sans)', boxShadow: '0 0 0 1px rgba(255,255,255,0.09)' }}>
      <div style={{ padding: '10px 12px 8px', textAlign: 'center', borderBottom: `1px solid ${line}` }}>
        <div style={{ fontSize: 7.5, letterSpacing: '0.18em', textTransform: 'uppercase', color: gold, fontWeight: 600 }}>{tagline}</div>
        <div style={{ fontSize: 13, color: tx, fontFamily: 'var(--serif)', fontStyle: 'italic', marginTop: 2 }}>{brand.name}</div>
      </div>
      {cats.length > 0 && (
        <div style={{ display: 'flex', gap: 4, padding: '5px 10px', overflowX: 'auto', borderBottom: `1px solid ${line}` }}>
          {cats.slice(0, 5).map((c, i) => (
            <span key={c.id} style={{ padding: '2px 7px', borderRadius: 999, fontSize: 8, whiteSpace: 'nowrap', background: i === 0 ? gold : 'transparent', color: i === 0 ? bg : mu, border: `1px solid ${i === 0 ? gold : line}` }}>
              {typeof c.name === 'object' ? c.name.es : c.name}
            </span>
          ))}
        </div>
      )}
      <div style={{ flex: 1, padding: '2px 10px', overflowY: 'hidden' }}>
        {(shown.length ? shown : items.slice(0, 3)).map((it, i, arr) => {
          const name = typeof it.name === 'object' ? (it.name.es || '') : (it.name || '');
          return (
            <div key={it.id || i} style={{ display: 'flex', alignItems: 'center', gap: 7, padding: '6px 0', borderBottom: i < arr.length - 1 ? `1px solid ${line}` : 'none' }}>
              {it.emoji && <div style={{ width: 26, height: 26, borderRadius: 5, background: s2, display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 12, flexShrink: 0 }}>{it.emoji}</div>}
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontSize: 10, color: tx, fontWeight: 500, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{name}</div>
                <div style={{ fontSize: 9, color: mu }}>${it.price}</div>
              </div>
              <div style={{ width: 16, height: 16, borderRadius: '50%', background: gold, display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 10, fontWeight: 700, color: bg, flexShrink: 0 }}>+</div>
            </div>
          );
        })}
      </div>
      <div style={{ padding: '7px 10px 9px', borderTop: `1px solid ${line}` }}>
        <div style={{ background: gold, borderRadius: 6, padding: '5px', textAlign: 'center', fontSize: 9, fontWeight: 700, color: bg }}>Ver carrito →</div>
      </div>
    </div>
  );
}

/* ── Skeleton value ─────────────────────────────────────────────────── */
function SkeletonVal({ width = 48 }) {
  return (
    <span style={{
      display: 'inline-block', width, height: '0.85em',
      background: 'var(--line-2)', borderRadius: 4,
      verticalAlign: 'middle', opacity: 0.6,
      animation: 'mf-pulse 1.4s ease-in-out infinite',
    }} />
  );
}

/* ── Sidebar ──────────────────────────────────────────────────────────── */
function DashboardSidebar({ tab, setTab, brand, user, onSignOut, liveCount, goTo }) {
  const sections = [
    { group: 'Tu casa', items: [
      { id: 'home',      label: 'Inicio',    icon: 'home'     },
      { id: 'menu',      label: 'Menú',       icon: 'fork'     },
      { id: 'brand',     label: 'Marca',      icon: 'palette'  },
      { id: 'qr',        label: 'QR & Mesas', icon: 'qr'       },
    ]},
    { group: 'Operaciones', items: [
      { id: 'live',      label: 'Sala',       icon: 'activity', badge: liveCount > 0 ? liveCount : null },
      { id: 'comensal',  label: 'Pantalla',   icon: 'eye'      },
      { id: 'analytics', label: 'Métricas',   icon: 'layers'   },
      { id: 'console',   label: 'Consola',    icon: 'arrow',   external: true },
    ]},
    { group: 'Cuenta', items: [
      { id: 'team',      label: 'Equipo',     icon: 'users'    },
      { id: 'settings',  label: 'Ajustes',    icon: 'settings' },
    ]},
  ];
  return (
    <aside style={{ position: 'sticky', top: 0, height: '100vh', padding: '32px 20px', background: 'var(--paper-2)', display: 'flex', flexDirection: 'column', overflowY: 'auto' }}>
      {/* Brand chip */}
      <div style={{ padding: '12px 14px', background: 'var(--paper)', borderRadius: 'var(--r-md)', border: '1px solid var(--line)', display: 'flex', alignItems: 'center', gap: 12, marginBottom: 28 }}>
        {brand.logoUrl ? (
          <img src={brand.logoUrl} style={{ width: 32, height: 32, borderRadius: 8, objectFit: 'contain', background: brand.palette?.bg || '#0a0a0a', padding: 3 }} />
        ) : (
          <div style={{ width: 32, height: 32, borderRadius: 8, background: brand.palette?.bg || '#0a0a0a', color: brand.palette?.gold || brand.accent, display: 'grid', placeItems: 'center', fontFamily: 'var(--serif)', fontStyle: 'italic', fontSize: 18, flexShrink: 0 }}>
            {brand.name[0]}
          </div>
        )}
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 13, fontWeight: 500, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{brand.name}</div>
          <div className="mono" style={{ fontSize: 10, color: 'var(--mu)' }}>{brand.id}.menu.app</div>
        </div>
        <window.MFIcon name="chevD" size={12} style={{ color: 'var(--mu)', flexShrink: 0 }} />
      </div>

      {/* Nav */}
      <nav style={{ flex: 1, display: 'flex', flexDirection: 'column', gap: 26 }}>
        {sections.map(sec => (
          <div key={sec.group}>
            <div style={{ fontSize: 10, letterSpacing: '0.2em', textTransform: 'uppercase', fontWeight: 600, color: 'var(--mu-2)', marginBottom: 10, padding: '0 12px' }}>
              {sec.group}
            </div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
              {sec.items.map(it => (
                <button key={it.id} onClick={() => it.external ? goTo('admin') : setTab(it.id)} style={{
                  display: 'flex', alignItems: 'center', gap: 12,
                  padding: '9px 12px', borderRadius: 8,
                  background: !it.external && tab === it.id ? 'var(--paper)' : 'transparent',
                  border: !it.external && tab === it.id ? '1px solid var(--line)' : '1px solid transparent',
                  color: !it.external && tab === it.id ? 'var(--ink)' : 'var(--ink-2)',
                  fontSize: 13, fontWeight: !it.external && tab === it.id ? 500 : 400,
                  textAlign: 'left', transition: 'all 160ms',
                }}>
                  <window.MFIcon name={it.icon} size={15} style={{ color: !it.external && tab === it.id ? 'var(--accent)' : 'var(--mu)', flexShrink: 0 }} />
                  <span style={{ flex: 1 }}>{it.label}</span>
                  {it.external && <window.MFIcon name="arrowUR" size={11} style={{ color: 'var(--mu)', flexShrink: 0 }} />}
                  {!it.external && it.badge && (
                    <span style={{ background: 'var(--accent)', color: '#fff', fontSize: 10, fontWeight: 600, padding: '2px 6px', borderRadius: 999 }}>
                      {it.badge}
                    </span>
                  )}
                </button>
              ))}
            </div>
          </div>
        ))}
      </nav>

      {/* Status footer */}
      <div style={{ padding: 14, background: 'var(--paper)', borderRadius: 'var(--r-md)', border: '1px solid var(--line)', marginTop: 24 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 6 }}>
          <window.MFLiveDot color="var(--sage-deep)" />
          <span style={{ fontSize: 11, color: 'var(--mu)', letterSpacing: '0.06em' }}>Menú activo</span>
        </div>
        <div className="mono" style={{ fontSize: 11, color: 'var(--ink)' }}>{brand.id}.menu.app</div>
        <a onClick={() => setTab('comensal')} style={{ fontSize: 11, color: 'var(--accent)', display: 'inline-flex', alignItems: 'center', gap: 4, marginTop: 8, cursor: 'pointer' }}>
          Ver pantalla <window.MFIcon name="arrowUR" size={11} />
        </a>
      </div>

      {/* User footer */}
      {(user || onSignOut) && (
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '12px 6px 0' }}>
          <div style={{ width: 28, height: 28, borderRadius: '50%', background: 'var(--ink)', color: 'var(--paper)', display: 'grid', placeItems: 'center', fontSize: 10, fontWeight: 600, flexShrink: 0 }}>
            {(user?.name || user?.email || 'U').slice(0, 2).toUpperCase()}
          </div>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 12, fontWeight: 500, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{user?.name || user?.email || 'Usuario'}</div>
            {user?.name && user?.email && <div style={{ fontSize: 10, color: 'var(--mu)', overflow: 'hidden', textOverflow: 'ellipsis' }}>{user.email}</div>}
          </div>
          {onSignOut && <button onClick={onSignOut} title="Cerrar sesión" style={{ color: 'var(--mu)', fontSize: 14, padding: 4, lineHeight: 1, flexShrink: 0 }}>⎋</button>}
        </div>
      )}
    </aside>
  );
}

/* ── DashHome ─────────────────────────────────────────────────────────── */
function DashHome({ brand, goTo, isMobile, restaurantId }) {
  const p = isMobile ? '20px 16px 90px' : '40px 56px 80px';
  return (
    <div style={{ padding: p }}>
      <DashHeader brand={brand} isMobile={isMobile} />
      <SetupChecklist brand={brand} isMobile={isMobile} restaurantId={restaurantId} goTo={goTo} />
      <div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr' : '1.4fr 1fr', gap: isMobile ? 16 : 32, marginTop: isMobile ? 20 : 40 }}>
        <LiveOpsBlock brand={brand} goTo={goTo} isMobile={isMobile} restaurantId={restaurantId} />
        <BrandShowcaseBlock brand={brand} goTo={goTo} />
      </div>
      <KPIRow isMobile={isMobile} restaurantId={restaurantId} />
      <div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr' : '1fr 1.4fr', gap: isMobile ? 16 : 32, marginTop: isMobile ? 16 : 32 }}>
        <QRCard brand={brand} goTo={goTo} />
        <ActivityFeed isMobile={isMobile} restaurantId={restaurantId} goTo={goTo} />
      </div>
    </div>
  );
}

function AiComingSoonModal({ onClose }) {
  return (
    <div onClick={onClose} style={{
      position: 'fixed', inset: 0, zIndex: 400,
      background: 'rgba(10,8,5,0.55)', backdropFilter: 'blur(4px)',
      display: 'flex', alignItems: window.innerWidth >= 768 ? 'center' : 'flex-end', justifyContent: 'center',
    }}>
      <div onClick={e => e.stopPropagation()} style={{
        width: '100%', maxWidth: 440,
        background: 'var(--paper)',
        borderRadius: window.innerWidth >= 768 ? 'var(--r-lg)' : '20px 20px 0 0',
        padding: 32,
      }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 16 }}>
          <window.MFMarker label="Próximamente" />
          <button onClick={onClose} style={{ color: 'var(--mu)', padding: 4 }}><window.MFIcon name="x" size={14} /></button>
        </div>
        <h2 className="serif" style={{ fontSize: 24, fontStyle: 'italic', fontWeight: 400, marginBottom: 12 }}>IA para menús</h2>
        <p style={{ fontSize: 13, color: 'var(--mu)', lineHeight: 1.6 }}>
          Pronto podrás usar inteligencia artificial para mejorar las descripciones de tus platos, sugerir maridajes y optimizar tu carta para aumentar el ticket promedio.
        </p>
        <button className="btn" onClick={onClose} style={{ marginTop: 24, width: '100%', justifyContent: 'center' }}>Entendido</button>
      </div>
    </div>
  );
}

function DashHeader({ brand, isMobile }) {
  const [aiModal, setAiModal] = usD(false);
  const now = new Date();
  const hour = now.getHours();
  const greeting = hour < 12 ? 'Buenos días' : hour < 19 ? 'Buenas tardes' : 'Buenas noches';
  return (
    <>
    <div style={{ display: 'flex', alignItems: isMobile ? 'flex-start' : 'flex-end', justifyContent: 'space-between', marginBottom: isMobile ? 20 : 40, flexDirection: isMobile ? 'column' : 'row', gap: isMobile ? 16 : 0 }}>
      <div>
        <window.MFMarker label={now.toLocaleDateString('es-MX', { weekday: 'long', day: 'numeric', month: 'long' })} />
        <h1 className="display-md" style={{ marginTop: 14, fontWeight: 400, fontSize: isMobile ? 'clamp(28px, 8vw, 48px)' : undefined }}>
          {greeting},<br />
          <em style={{ color: 'var(--accent)' }}>{brand.name}.</em>
        </h1>
      </div>
      {!isMobile && (
        <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
          <button className="btn ghost sm"><window.MFIcon name="bell" size={14} /></button>
          <button className="btn sm" onClick={() => setAiModal(true)}><window.MFIcon name="sparkle" size={13} />Mejorar menú con IA</button>
        </div>
      )}
      {isMobile && (
        <button className="btn sm" style={{ alignSelf: 'flex-start' }} onClick={() => setAiModal(true)}>
          <window.MFIcon name="sparkle" size={13} />Mejorar con IA
        </button>
      )}
    </div>
    {aiModal && <AiComingSoonModal onClose={() => setAiModal(false)} />}
    </>
  );
}

function SetupChecklist({ brand, isMobile, restaurantId, goTo }) {
  const [posModal, setPosModal] = usD(false);
  const [posConnected, setPosConnected] = usD(() => !!localStorage.getItem('mf_pos_connected'));
  const [dismissed, setDismissed] = usD(() => !!localStorage.getItem('mf_checklist_dismissed'));

  if (dismissed) return null;

  const items = [
    {
      done: !!(brand.logoUrl || brand.accent),
      label: 'Logo y paleta cargados',
      hint: brand.accent ? 'Acento ' + brand.accent.toUpperCase() : 'Sin acento definido',
    },
    {
      done: !!(brand.name && brand.tagline && brand.hours),
      label: 'Identidad escrita',
      hint: [brand.name && 'nombre', brand.tagline && 'tagline', brand.hours && 'horario'].filter(Boolean).length + ' / 3 campos',
    },
    {
      done: (brand.items?.length || 0) >= 3,
      label: (brand.items?.length || 0) + ' platos publicados',
      hint: (brand.categories?.length || 0) + ' categorías',
      action: (brand.items?.length || 0) < 3 ? 'Añadir' : undefined,
    },
    { done: posConnected, label: 'Conecta tu POS', hint: 'Square · Toast · Loyverse', action: 'Conectar', onAction: () => setPosModal(true) },
    {
      done: (brand.items || []).some(it => it.img),
      label: 'Sube fotos reales',
      hint: (brand.items || []).filter(it => it.img).length + ' / ' + (brand.items?.length || 0) + ' con foto',
      action: 'Subir',
      onAction: () => goTo && goTo('menu'),
    },
  ];
  const pct = Math.round((items.filter(i => i.done).length / items.length) * 100);
  return (
    <div style={{ background: 'linear-gradient(180deg, var(--paper-2) 0%, var(--paper) 100%)', borderRadius: 'var(--r-lg)', border: '1px solid var(--line)', padding: 28, overflow: 'hidden' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 22 }}>
        <div>
          <div style={{ fontSize: 11, letterSpacing: '0.18em', textTransform: 'uppercase', fontWeight: 600, color: 'var(--mu)' }}>Tu casa al {pct}%</div>
          <h2 className="serif" style={{ fontSize: 24, fontStyle: 'italic', marginTop: 6, fontWeight: 400 }}>Cinco detalles para llegar al 100.</h2>
        </div>
        <button className="btn ghost sm" onClick={() => { localStorage.setItem('mf_checklist_dismissed', '1'); setDismissed(true); }}>Cerrar</button>
      </div>
      <div style={{ height: 2, background: 'var(--line)', borderRadius: 2, overflow: 'hidden', marginBottom: 22 }}>
        <div style={{ height: '100%', width: `${pct}%`, background: 'var(--accent)' }} />
      </div>
      {isMobile ? (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 0, border: '1px solid var(--line)', borderRadius: 'var(--r-md)', overflow: 'hidden' }}>
          {items.map((it, i) => (
            <div key={i} style={{ padding: '14px 16px', display: 'flex', alignItems: 'center', gap: 14, borderTop: i > 0 ? '1px solid var(--line)' : 'none', background: it.done ? 'transparent' : 'var(--paper)', opacity: it.done ? 0.7 : 1 }}>
              <div style={{ width: 22, height: 22, borderRadius: '50%', flexShrink: 0, background: it.done ? 'var(--accent)' : 'transparent', border: it.done ? 'none' : '1.5px dashed var(--line-3)', color: '#fff', display: 'grid', placeItems: 'center', fontSize: 11 }}>
                {it.done && <window.MFIcon name="check" size={12} />}
              </div>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontSize: 13, fontWeight: 500, textDecoration: it.done ? 'line-through' : 'none' }}>{it.label}</div>
                <div style={{ fontSize: 11, color: 'var(--mu)', marginTop: 2 }}>{it.hint}</div>
              </div>
              {it.action && !it.done && (
                <button onClick={it.onAction} style={{ fontSize: 11, color: 'var(--accent)', fontWeight: 600, flexShrink: 0, display: 'inline-flex', alignItems: 'center', gap: 4 }}>
                  {it.action} <window.MFIcon name="arrow" size={11} />
                </button>
              )}
            </div>
          ))}
        </div>
      ) : (
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(5, 1fr)', borderTop: '1px solid var(--line)', borderLeft: '1px solid var(--line)' }}>
          {items.map((it, i) => (
            <div key={i} style={{ padding: '18px 16px', borderRight: '1px solid var(--line)', borderBottom: '1px solid var(--line)', background: it.done ? 'transparent' : 'var(--paper)', opacity: it.done ? 0.7 : 1 }}>
              <div style={{ width: 22, height: 22, borderRadius: '50%', background: it.done ? 'var(--accent)' : 'transparent', border: it.done ? 'none' : '1.5px dashed var(--line-3)', color: '#fff', display: 'grid', placeItems: 'center', fontSize: 11, marginBottom: 14 }}>
                {it.done && <window.MFIcon name="check" size={12} />}
              </div>
              <div style={{ fontSize: 13, fontWeight: 500, lineHeight: 1.3, marginBottom: 4, textDecoration: it.done ? 'line-through' : 'none' }}>{it.label}</div>
              <div style={{ fontSize: 11, color: 'var(--mu)' }}>{it.hint}</div>
              {it.action && !it.done && (
                <button onClick={it.onAction} style={{ marginTop: 12, fontSize: 11, color: 'var(--accent)', fontWeight: 600, letterSpacing: '0.04em', display: 'inline-flex', alignItems: 'center', gap: 4 }}>
                  {it.action} <window.MFIcon name="arrow" size={11} />
                </button>
              )}
            </div>
          ))}
        </div>
      )}
      {posModal && <POSConnectModal onClose={() => { setPosModal(false); setPosConnected(!!localStorage.getItem('mf_pos_connected')); }} restaurantId={restaurantId || brand.id} />}
    </div>
  );
}

function LiveOpsBlock({ brand, goTo, isMobile, restaurantId }) {
  const { tables: liveTables, loading: tablesLoading } = useLiveTablesD(restaurantId);
  const { stats, loading: statsLoading } = useTodayStatsD(restaurantId);
  const [ackedBlock, setAckedBlock] = usD(() => new Set());

  const statusLabel = { kitchen: 'En cocina', ready: 'Listo', ordering: 'Ordenando', paying: 'Cobro' };

  // Format currency
  const fmt = (n) => n != null && n > 0 ? `$${Number(n).toLocaleString('es-MX')}` : '—';

  const tableCount = liveTables.length;
  const ticketsLabel = statsLoading ? <SkeletonVal /> : String(stats.ticketsToday);
  const revenueLabel = statsLoading ? <SkeletonVal /> : fmt(stats.revenueToday);
  const avgLabel     = statsLoading ? <SkeletonVal /> : fmt(stats.avgTicket);

  return (
    <div style={{ padding: 28, background: 'var(--ink)', color: 'var(--paper)', borderRadius: 'var(--r-lg)', overflow: 'hidden' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 24 }}>
        <div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 10, color: 'rgba(250,249,245,0.55)', letterSpacing: '0.18em', textTransform: 'uppercase', fontWeight: 600 }}>
            <window.MFLiveDot color="var(--sage)" /> En vivo · ahora
          </div>
          <div className="serif" style={{ fontSize: 26, fontStyle: 'italic', marginTop: 8, fontWeight: 400 }}>
            {tablesLoading ? <SkeletonVal width={80} /> : tableCount === 0 ? 'Sin mesas activas' : `${tableCount} mesa${tableCount !== 1 ? 's' : ''} activa${tableCount !== 1 ? 's' : ''}`}
          </div>
        </div>
        <button onClick={() => goTo('admin')} className="btn sm" title="Abre en una pestaña nueva" style={{ background: 'var(--paper)', color: 'var(--ink)', borderColor: 'var(--paper)' }}>
          Abrir consola <window.MFIcon name="arrowUR" size={12} />
        </button>
      </div>

      {(() => {
        const blockAlerts = liveTables.filter(t => t.helpRequest || t.paymentRequest);
        const visibleBlockAlerts = blockAlerts.filter(t => !ackedBlock.has(t.id));
        return visibleBlockAlerts.length > 0 ? (
          <div style={{ marginBottom: 12, padding: '10px 14px', background: 'rgba(245,166,35,0.12)', border: '1px solid rgba(245,166,35,0.35)', borderRadius: 'var(--r-md)', display: 'flex', alignItems: 'center', gap: 10 }}>
            <window.MFIcon name="bell" size={13} style={{ color: 'rgba(245,166,35,0.9)', flexShrink: 0 }} />
            <span style={{ fontSize: 12, fontWeight: 500, flex: 1, color: 'rgba(250,249,245,0.9)' }}>
              {visibleBlockAlerts.map(t => `Mesa ${t.id} · ${t.helpRequest ? 'llamó al mesero' : 'solicita cuenta'}`).join('   ·   ')}
            </span>
            <button onClick={() => setAckedBlock(prev => new Set([...prev, ...visibleBlockAlerts.map(t => t.id)]))}
              style={{ fontSize: 11, color: 'rgba(250,249,245,0.55)', flexShrink: 0 }}>
              Visto ✓
            </button>
          </div>
        ) : null;
      })()}
      {tableCount === 0 && !tablesLoading ? (
        <div style={{ padding: '28px 16px', textAlign: 'center', color: 'rgba(250,249,245,0.5)', fontSize: 13 }}>
          Las mesas aparecerán aquí cuando un comensal escanee el QR.
        </div>
      ) : (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 1, background: 'rgba(255,255,255,0.08)', borderRadius: 'var(--r-md)', overflow: 'hidden' }}>
          {liveTables.map(t => {
            const hasAlert = t.helpRequest || t.paymentRequest;
            return (
              <div key={t.id} style={{ display: 'grid', gridTemplateColumns: isMobile ? '60px 1fr 90px' : '70px 1fr 110px 80px 50px', gap: isMobile ? 10 : 16, alignItems: 'center', padding: '14px 16px', background: hasAlert ? 'rgba(245,166,35,0.1)' : 'var(--ink)', borderLeft: hasAlert ? '3px solid rgba(245,166,35,0.7)' : '3px solid transparent', transition: 'background 300ms' }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 5 }}>
                  <span className="mono" style={{ fontSize: 13, color: 'var(--paper)', fontWeight: 600 }}>{t.id}</span>
                  {hasAlert && <span style={{ width: 5, height: 5, borderRadius: '50%', background: 'rgba(245,166,35,0.9)', flexShrink: 0, display: 'inline-block' }} />}
                </div>
                <div>
                  <div style={{ fontSize: 12, color: 'rgba(250,249,245,0.9)' }}>{t.pax} persona{t.pax !== 1 ? 's' : ''}</div>
                  <div style={{ fontSize: 11, color: hasAlert ? 'rgba(245,166,35,0.8)' : 'rgba(250,249,245,0.45)', marginTop: 2 }}>
                    {t.helpRequest ? '🔔 Llamó al mesero' : t.paymentRequest ? '🧾 Solicita cuenta' : `Abrió ${t.ts}`}
                  </div>
                </div>
                <window.MFStatusPill status={t.status} label={statusLabel[t.status] || t.status} />
                {!isMobile && (
                  <span className="serif" style={{ fontSize: 14, textAlign: 'right', color: t.total ? 'var(--paper)' : 'rgba(250,249,245,0.4)' }}>
                    {t.total ? `$${t.total.toLocaleString('es-MX')}` : '—'}
                  </span>
                )}
                {!isMobile && <window.MFIcon name="chevR" size={14} style={{ color: 'rgba(250,249,245,0.4)', justifySelf: 'end' }} />}
              </div>
            );
          })}
        </div>
      )}

      <div style={{ marginTop: 20, paddingTop: 20, borderTop: '1px solid rgba(255,255,255,0.1)', display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)' }}>
        {[['Tickets hoy', ticketsLabel],['Ingreso', revenueLabel],['Ticket prom.', avgLabel]].map(([label,value]) => (
          <div key={label} style={{ padding: '0 16px', borderRight: '1px solid rgba(255,255,255,0.1)' }}>
            <div style={{ fontSize: 10, letterSpacing: '0.16em', textTransform: 'uppercase', fontWeight: 600, color: 'rgba(250,249,245,0.5)' }}>{label}</div>
            <div className="serif" style={{ fontSize: 24, marginTop: 4, fontStyle: 'italic' }}>{value}</div>
          </div>
        ))}
      </div>
    </div>
  );
}

function BrandShowcaseBlock({ brand, goTo }) {
  const bg = brand.cover
    ? `linear-gradient(180deg,rgba(0,0,0,0) 0%,rgba(0,0,0,0.55) 100%),url(${brand.cover}) center/cover`
    : `linear-gradient(135deg,${brand.accentDeep||'#3a2010'} 0%,${brand.accent||'#8a3a1a'} 100%)`;
  return (
    <div style={{ background: bg, borderRadius: 'var(--r-lg)', padding: 28, color: 'var(--paper)', display: 'flex', flexDirection: 'column', justifyContent: 'space-between', minHeight: 380, overflow: 'hidden' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
        {brand.logoUrl
          ? <img src={brand.logoUrl} style={{ width: 44, height: 44, borderRadius: 10, objectFit: 'contain', background: 'rgba(255,255,255,0.1)', padding: 4 }} />
          : <div style={{ fontFamily: 'var(--serif)', fontStyle: 'italic', fontSize: 20, color: 'rgba(255,255,255,0.9)' }}>{brand.name}</div>
        }
        <button onClick={() => goTo('guest')} className="btn sm" title="Abre en una pestaña nueva" style={{ background: 'rgba(250,249,245,0.92)', color: 'var(--ink)', borderColor: 'transparent' }}>
          <window.MFIcon name="eye" size={12} /> Ver vivo <window.MFIcon name="arrowUR" size={10} />
        </button>
      </div>
      <div>
        <div style={{ fontSize: 10, letterSpacing: '0.18em', textTransform: 'uppercase', fontWeight: 600, opacity: 0.8 }}>Tu menú público</div>
        <h3 className="serif" style={{ fontSize: 22, fontStyle: 'italic', marginTop: 8, fontWeight: 400, lineHeight: 1.2 }}>"{brand.quote}"</h3>
        <div style={{ marginTop: 14, fontSize: 11, opacity: 0.8, letterSpacing: '0.12em', textTransform: 'uppercase' }}>{brand.hours}</div>
        <div style={{ marginTop: 18, display: 'flex', gap: 18, fontSize: 12 }}>
          <span><span className="serif" style={{ fontSize: 18, fontStyle: 'italic' }}>{brand.items?.length||0}</span><span style={{ opacity: 0.6, marginLeft: 6 }}>platos</span></span>
          <span><span className="serif" style={{ fontSize: 18, fontStyle: 'italic' }}>{brand.categories?.length||0}</span><span style={{ opacity: 0.6, marginLeft: 6 }}>cat.</span></span>
          <span><span className="serif" style={{ fontSize: 18, fontStyle: 'italic' }}>2</span><span style={{ opacity: 0.6, marginLeft: 6 }}>idiomas</span></span>
        </div>
      </div>
    </div>
  );
}

function KPIRow({ isMobile, restaurantId }) {
  const { tables: liveTables } = useLiveTablesD(restaurantId);
  const { stats } = useTodayStatsD(restaurantId);

  const activeCount = liveTables.length;
  const fmt = (n) => n != null && n > 0 ? `$${Number(n).toLocaleString('es-MX')}` : '—';

  // Build hourly sparkline data from ordersRaw (buckets for hours 0–now)
  const currentHour = new Date().getHours();
  const hourlyTickets  = Array(currentHour + 1).fill(0);
  const hourlyRevenue  = Array(currentHour + 1).fill(0);
  (stats.ordersRaw || []).forEach(o => {
    const h = toDateD(o.closedAt).getHours();
    if (h <= currentHour) {
      hourlyTickets[h]++;
      hourlyRevenue[h] += (o.total || 0);
    }
  });
  // Cumulative sums for a nicer upward trend line
  const cumulativeTickets = hourlyTickets.reduce((acc, v, i) => { acc.push((acc[i-1]||0) + v); return acc; }, []);
  const cumulativeRevenue = hourlyRevenue.reduce((acc, v, i) => { acc.push((acc[i-1]||0) + v); return acc; }, []);
  // Need at least 2 points for a line; pad if needed
  const toSpark = (arr) => arr.length < 2 ? [...arr, ...Array(2 - arr.length).fill(0)] : arr;

  const kpis = [
    { label: 'Tickets hoy',      value: String(stats.ticketsToday || 0), sub: 'Pedidos cerrados hoy',      spark: toSpark(cumulativeTickets) },
    { label: 'Cuentas abiertas', value: String(activeCount),             sub: `${activeCount} mesa${activeCount !== 1 ? 's' : ''} en vivo`, spark: toSpark(hourlyTickets) },
    { label: 'Ticket promedio',  value: fmt(stats.avgTicket),             sub: 'Promedio de hoy',          spark: toSpark(cumulativeTickets) },
    { label: 'Ingreso hoy',     value: fmt(stats.revenueToday),          sub: 'Total facturado hoy',       spark: toSpark(cumulativeRevenue) },
  ];
  return (
    <div style={{ display: 'grid', gridTemplateColumns: isMobile ? 'repeat(2, 1fr)' : 'repeat(4, 1fr)', gap: isMobile ? 10 : 16, marginTop: isMobile ? 16 : 32 }}>
      {kpis.map(k => <KPICard key={k.label} {...k} isMobile={isMobile} />)}
    </div>
  );
}

function KPICard({ label, value, sub, spark, isMobile }) {
  const hasSpark = spark && spark.length > 1 && Math.max(...spark) > 0;
  let pts = '';
  if (hasSpark) {
    const max = Math.max(...spark), min = Math.min(...spark);
    pts = spark.map((y, i) => `${(i/(spark.length-1))*100},${30-((y-min)/(max-min||1))*28}`).join(' ');
  }
  return (
    <div className="card" style={{ padding: isMobile ? 16 : 22 }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
        <div>
          <div style={{ fontSize: 10, letterSpacing: '0.14em', textTransform: 'uppercase', fontWeight: 600, color: 'var(--mu)' }}>{label}</div>
          <div className="serif" style={{ fontSize: isMobile ? 22 : 28, marginTop: 6, fontStyle: 'italic', letterSpacing: '-0.01em' }}>{value}</div>
        </div>
        {!isMobile && hasSpark && (
          <svg width="60" height="30" viewBox="0 0 100 30" style={{ overflow: 'visible' }}>
            <polyline fill="none" stroke="var(--accent)" strokeWidth="1.5" points={pts} />
            <circle cx="100" cy={30-((spark[spark.length-1]-Math.min(...spark))/(Math.max(...spark)-Math.min(...spark)||1))*28} r="2.5" fill="var(--accent)" />
          </svg>
        )}
      </div>
      <div style={{ fontSize: 11, color: 'var(--mu)', marginTop: isMobile ? 6 : 14 }}>{sub}</div>
    </div>
  );
}

function FakeQR({ size = 100, brand, tableId }) {
  const canvasRef = React.useRef(null);
  
  React.useEffect(() => {
    if (window.QRCode && canvasRef.current) {
      // Si recibimos tableId, la URL es para esa mesa en particular. Si no, es la landing general.
      let url = `https://${brand.id}.menu.app`;
      if (tableId) {
        // Asumiendo que las mesas agregan el query ?table=M-01
        url += `?table=${tableId}`;
      }
      
      window.QRCode.toCanvas(canvasRef.current, url, {
        width: size,
        margin: 1,
        color: {
          dark: '#0f0f0e',
          light: '#faf9f5'
        }
      }, (error) => {
        if (error) console.error('Error generando QR:', error);
      });
    }
  }, [brand.id, size, tableId]);

  return (
    <div style={{ width: size, height: size, padding: 8, background: 'var(--paper)', borderRadius: 'var(--r-sm)', border: '1px solid var(--line-2)' }}>
      <canvas ref={canvasRef} style={{ display: 'block', width: '100%', height: '100%' }} />
    </div>
  );
}

function QRCard({ brand, goTo }) {
  return (
    <div style={{ padding: 28, background: 'var(--paper-2)', borderRadius: 'var(--r-lg)', border: '1px solid var(--line)' }}>
      <window.MFMarker label="QR & enlaces" />
      <h3 className="serif" style={{ fontSize: 22, fontStyle: 'italic', margin: '14px 0 18px', fontWeight: 400 }}>Comparte tu mesa.</h3>
      <div style={{ display: 'flex', gap: 18, alignItems: 'center' }}>
        <FakeQR size={108} brand={brand} />
        <div style={{ flex: 1 }}>
          <div style={{ fontSize: 11, letterSpacing: '0.12em', color: 'var(--mu)' }}>URL principal</div>
          <div className="mono" style={{ fontSize: 13, marginTop: 4, color: 'var(--ink)' }}>{brand.id}.menu.app</div>
          <div style={{ display: 'flex', gap: 8, marginTop: 14 }}>
            <button className="btn sm"><window.MFIcon name="download" size={12} />Descargar</button>
            <button className="btn ghost sm" onClick={() => goTo('qr')}>Mesas</button>
          </div>
        </div>
      </div>
    </div>
  );
}

function ActivityFeed({ restaurantId, goTo }) {
  const { events: liveEvents, loading } = useRecentEventsD(restaurantId);
  const dotColors = { sage: 'var(--sage-deep)', mu: 'var(--mu)', warn: 'var(--warn)', accent: 'var(--accent)' };

  const showEvents = liveEvents.length > 0 ? liveEvents : [];

  return (
    <div className="card" style={{ padding: 28 }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 18 }}>
        <window.MFMarker label="Actividad reciente" />
        {showEvents.length > 0 && <button className="btn ghost sm">Ver todo</button>}
      </div>

      {loading ? (
        <div style={{ padding: '24px 0', textAlign: 'center', color: 'var(--mu)', fontSize: 13 }}>Cargando…</div>
      ) : showEvents.length === 0 ? (
        <div style={{ padding: '32px 16px', textAlign: 'center' }}>
          <div style={{ fontSize: 24, marginBottom: 12 }}>🍽</div>
          <div style={{ fontSize: 14, fontWeight: 500, marginBottom: 6 }}>Sin actividad todavía</div>
          <div style={{ fontSize: 12, color: 'var(--mu)', maxWidth: 280, margin: '0 auto 20px' }}>
            Los eventos aparecen en tiempo real cuando un comensal escanea un QR y empieza a ordenar.
          </div>
          <button className="btn sm" onClick={() => goTo && goTo('qr')}>
            <window.MFIcon name="qr" size={12} /> Ir a mis QRs
          </button>
        </div>
      ) : (
        showEvents.map((e, i) => (
          <div key={e.id || i} style={{ display: 'grid', gridTemplateColumns: '36px 1fr 80px', gap: 14, alignItems: 'center', padding: '14px 0', borderTop: i > 0 ? '1px solid var(--line)' : 'none' }}>
            <div style={{ width: 32, height: 32, borderRadius: '50%', background: 'var(--paper-2)', display: 'grid', placeItems: 'center', color: dotColors[e.tone] || 'var(--mu)', border: '1px solid var(--line)' }}>
              <window.MFIcon name={e.icon || 'activity'} size={13} />
            </div>
            <div>
              <div style={{ fontSize: 13, fontWeight: 500 }}>{e.title}</div>
              {e.sub && <div style={{ fontSize: 11, color: 'var(--mu)', marginTop: 2 }}>{e.sub}</div>}
            </div>
            <div style={{ fontSize: 11, color: 'var(--mu-2)', textAlign: 'right' }}>{e.time}</div>
          </div>
        ))
      )}
    </div>
  );
}

/* ── Shared form primitives ──────────────────────────────────────────── */
const dashInputStyle = {
  width: '100%', padding: '10px 12px', boxSizing: 'border-box',
  border: '1px solid var(--line)', borderRadius: 10,
  background: 'var(--paper)', fontSize: 13, color: 'var(--ink)',
  fontFamily: 'var(--sans)', outline: 'none', lineHeight: 1.5,
};

function DashField({ label, children }) {
  return (
    <div>
      <div style={{ fontSize: 10, letterSpacing: '0.16em', textTransform: 'uppercase', fontWeight: 600, color: 'var(--mu)', marginBottom: 7 }}>{label}</div>
      {children}
    </div>
  );
}

function DashDivider({ label }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 12, marginTop: 4 }}>
      <div style={{ flex: 1, height: 1, background: 'var(--line)' }} />
      <span style={{ fontSize: 9, letterSpacing: '0.18em', textTransform: 'uppercase', fontWeight: 600, color: 'var(--mu)', whiteSpace: 'nowrap' }}>{label}</span>
      <div style={{ flex: 1, height: 1, background: 'var(--line)' }} />
    </div>
  );
}

/* ── Save-status chip — reflects the Firestore write lifecycle ─────────── */
function SaveStatus({ state, onRetry }) {
  if (!state) return null;
  const map = {
    saving: { label: 'Guardando…', color: 'var(--mu)',        bg: 'var(--paper-2)', icon: null },
    saved:  { label: 'Guardado',   color: 'var(--sage-deep)', bg: 'var(--sage)',    icon: 'check' },
    error:  { label: 'No se guardó', color: '#b91c1c',         bg: 'rgba(220,38,38,0.10)', icon: 'refresh' },
  };
  const s = map[state] || map.saving;
  return (
    <button
      type="button"
      onClick={state === 'error' ? onRetry : undefined}
      title={state === 'error' ? 'Reintentar' : undefined}
      style={{
        display: 'inline-flex', alignItems: 'center', gap: 6,
        height: 32, padding: '0 12px', borderRadius: 999,
        background: s.bg, color: s.color, fontSize: 12, fontWeight: 600,
        cursor: state === 'error' ? 'pointer' : 'default',
        border: '1px solid transparent',
      }}>
      {state === 'saving'
        ? <span style={{ width: 12, height: 12, borderRadius: '50%', border: '2px solid var(--line-2)', borderTopColor: 'var(--mu)', display: 'inline-block', animation: 'mf-spin 0.7s linear infinite' }} />
        : s.icon && <window.MFIcon name={s.icon} size={12} />}
      {s.label}
    </button>
  );
}

/* ── Reusable image uploader → Firebase Storage ──────────────────────────
   Upload a file (drag/drop or pick) or paste a URL. Returns the public URL
   via onChange. Used for dish photos and the guest-cover background. */
function ImageUploadField({ value, onChange, pathPrefix, aspect = '4 / 3', emptyHint }) {
  const [busy, setBusy]       = usD(false);
  const [err, setErr]         = usD('');
  const [showUrl, setShowUrl] = usD(false);
  const fileRef = React.useRef(null);

  const handleFile = async (file) => {
    if (!file) return;
    setErr('');
    setBusy(true);
    try {
      if (typeof window.MFUploadImage !== 'function') throw new Error('Almacenamiento no disponible. Recarga la página.');
      const url = await window.MFUploadImage(file, pathPrefix);
      onChange(url);
    } catch (e) {
      setErr(e.message || 'No se pudo subir la imagen');
    } finally {
      setBusy(false);
    }
  };

  return (
    <div>
      <div
        onClick={() => !busy && fileRef.current?.click()}
        onDragOver={e => e.preventDefault()}
        onDrop={e => { e.preventDefault(); if (!busy) handleFile(e.dataTransfer.files[0]); }}
        style={{
          position: 'relative', aspectRatio: aspect, width: '100%',
          borderRadius: 'var(--r-md)', overflow: 'hidden', cursor: busy ? 'wait' : 'pointer',
          border: value ? '1px solid var(--line)' : '1.5px dashed var(--line-2)',
          background: value ? `var(--paper-2) url(${value}) center/cover` : 'var(--paper-2)',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          transition: 'border-color 160ms',
        }}
        onMouseEnter={e => { if (!value) e.currentTarget.style.borderColor = 'var(--accent)'; }}
        onMouseLeave={e => { if (!value) e.currentTarget.style.borderColor = 'var(--line-2)'; }}
      >
        <input ref={fileRef} type="file" accept="image/*" hidden onChange={e => handleFile(e.target.files[0])} />

        {/* Empty prompt */}
        {!value && !busy && (
          <div style={{ textAlign: 'center', padding: 16, pointerEvents: 'none' }}>
            <div style={{ width: 40, height: 40, margin: '0 auto 8px', borderRadius: '50%', background: 'var(--paper)', border: '1px solid var(--line-2)', display: 'grid', placeItems: 'center' }}>
              <window.MFIcon name="image" size={16} style={{ color: 'var(--mu)' }} />
            </div>
            <div style={{ fontSize: 12, fontWeight: 600, color: 'var(--ink-2)' }}>Sube una imagen</div>
            <div style={{ fontSize: 11, color: 'var(--mu)', marginTop: 2 }}>{emptyHint || 'Arrastra o toca · JPG/PNG · máx 5 MB'}</div>
          </div>
        )}

        {/* Uploading overlay */}
        {busy && (
          <div style={{ position: 'absolute', inset: 0, display: 'grid', placeItems: 'center', background: 'rgba(250,249,245,0.82)', backdropFilter: 'blur(2px)' }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 10, color: 'var(--accent-deep)' }}>
              <span style={{ width: 16, height: 16, borderRadius: '50%', border: '2px solid var(--accent-tint)', borderTopColor: 'var(--accent)', display: 'inline-block', animation: 'mf-spin 0.7s linear infinite' }} />
              <span className="serif" style={{ fontSize: 15, fontStyle: 'italic' }}>Subiendo…</span>
            </div>
          </div>
        )}

        {/* Change/remove controls when an image is set */}
        {value && !busy && (
          <div style={{ position: 'absolute', top: 8, right: 8, display: 'flex', gap: 6 }}>
            <button type="button" title="Cambiar imagen" onClick={e => { e.stopPropagation(); fileRef.current?.click(); }}
              style={{ width: 32, height: 32, borderRadius: '50%', background: 'rgba(250,249,245,0.92)', backdropFilter: 'blur(8px)', display: 'grid', placeItems: 'center', boxShadow: 'var(--sh-1)' }}>
              <window.MFIcon name="edit" size={13} style={{ color: 'var(--ink)' }} />
            </button>
            <button type="button" title="Quitar imagen" onClick={e => { e.stopPropagation(); onChange(''); }}
              style={{ width: 32, height: 32, borderRadius: '50%', background: 'rgba(250,249,245,0.92)', backdropFilter: 'blur(8px)', display: 'grid', placeItems: 'center', boxShadow: 'var(--sh-1)' }}>
              <window.MFIcon name="x" size={13} style={{ color: 'var(--warn)' }} />
            </button>
          </div>
        )}
      </div>

      {err && (
        <div style={{ marginTop: 8, padding: '8px 12px', background: 'rgba(220,38,38,0.10)', color: '#b91c1c', borderRadius: 'var(--r-sm)', fontSize: 12 }}>
          {err}
        </div>
      )}

      {/* URL fallback (for power users / external hosting) */}
      <div style={{ marginTop: 8 }}>
        {!showUrl ? (
          <button type="button" onClick={() => setShowUrl(true)} style={{ fontSize: 11, color: 'var(--mu)', display: 'inline-flex', alignItems: 'center', gap: 5 }}>
            <window.MFIcon name="arrowUR" size={11} /> O pegar una URL
          </button>
        ) : (
          <input value={value || ''} onChange={e => onChange(e.target.value)} placeholder="https://…"
            style={{ ...dashInputStyle, fontSize: 12 }} />
        )}
      </div>
    </div>
  );
}

/* ── Dish create / edit modal ────────────────────────────────────────── */
function DishEditModal({ brand, item, onClose, onSave }) {
  const isNew = !item || !item.id;
  const [form, setForm] = usD(() => ({
    id: '', name: '', desc: '', price: '', emoji: '🍽️',
    cat: brand.categories[0]?.id || '', tags: [], allergens: [],
    img: '', prepTime: '', portionSize: '', spiciness: 'N/A', suggestedPairing: '',
    ...(item || {}),
    id: item?.id || '',
    price: String(item?.price ?? ''),
    allergens: item?.allergens || [],
    tags: item?.tags || [],
  }));
  const [saving, setSaving] = usD(false);
  const [saved,  setSaved]  = usD(false);

  const set = (k, v) => setForm(f => ({ ...f, [k]: v }));
  const toggleTag = (tag) => set('tags', form.tags.includes(tag) ? form.tags.filter(t => t !== tag) : [...form.tags, tag]);

  const handleSave = () => {
    if (!form.name.trim()) return;
    setSaving(true);
    const out = {
      ...form,
      id: form.id || ('item-' + Date.now()),
      price: parseFloat(form.price) || 0,
    };
    setTimeout(() => {
      onSave(out);
      setSaving(false);
      setSaved(true);
      setTimeout(onClose, 700);
    }, 350);
  };

  const tagOpts = [
    { key: 'v',     label: 'Vegetariano' },
    { key: 'gf',    label: 'Sin gluten'  },
    { key: 'crudo', label: 'Crudo'       },
    { key: 'firma', label: 'Plato firma' },
    { key: 'spicy', label: 'Picante'     },
  ];
  const spicyOpts   = ['N/A', 'Suave', 'Medio', 'Alto', 'Muy alto'];
  const portionOpts = ['', '1 persona', 'Para compartir', '2 personas', 'Media ración'];

  return (
    <div onClick={e => { if (e.target === e.currentTarget) onClose(); }} style={{
      position: 'fixed', inset: 0, zIndex: 300,
      background: 'rgba(10,8,5,0.55)', backdropFilter: 'blur(4px)',
      display: 'flex', alignItems: window.innerWidth >= 768 ? 'center' : 'flex-end', justifyContent: 'center',
    }}>
      <div style={{
        width: '100%', maxWidth: 620,
        background: 'var(--paper)',
        borderRadius: window.innerWidth >= 768 ? 'var(--r-lg)' : '20px 20px 0 0',
        maxHeight: window.innerWidth >= 768 ? '90vh' : '92vh',
        marginTop: window.innerWidth >= 768 ? 20 : 0,
        overflowY: 'auto', display: 'flex', flexDirection: 'column',
      }}>
        {/* Header */}
        <div style={{
          padding: '22px 24px 16px', display: 'flex', justifyContent: 'space-between', alignItems: 'center',
          position: 'sticky', top: 0, background: 'var(--paper)', zIndex: 1, borderBottom: '1px solid var(--line)',
        }}>
          <div>
            <window.MFMarker label={isNew ? 'Nuevo plato' : 'Editar plato'} />
            <h2 style={{ marginTop: 6, fontSize: 20, fontFamily: 'var(--serif)', fontStyle: 'italic', fontWeight: 400 }}>
              {isNew ? 'Añadir plato' : (form.name || 'Editar plato')}
            </h2>
          </div>
          <button onClick={onClose} style={{ width: 36, height: 36, borderRadius: '50%', background: 'var(--paper-2)', display: 'grid', placeItems: 'center' }}>
            <window.MFIcon name="x" size={14} />
          </button>
        </div>

        {/* Body */}
        <div style={{ padding: '20px 24px 0', flex: 1, display: 'flex', flexDirection: 'column', gap: 16 }}>

          <DashField label="Nombre del plato">
            <input value={form.name} onChange={e => set('name', e.target.value)}
              placeholder="Ej. Taco de cochinita pibil" style={dashInputStyle} />
          </DashField>

          <DashField label="Descripción">
            <textarea value={form.desc} onChange={e => set('desc', e.target.value)}
              placeholder="Una descripción breve y apetecible…" rows={2}
              style={{ ...dashInputStyle, resize: 'vertical' }} />
          </DashField>

          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
            <DashField label="Precio (MXN)">
              <input type="number" value={form.price} onChange={e => set('price', e.target.value)}
                placeholder="0.00" style={dashInputStyle} />
            </DashField>
            <DashField label="Categoría">
              <select value={form.cat} onChange={e => set('cat', e.target.value)} style={dashInputStyle}>
                {brand.categories.map(c => <option key={c.id} value={c.id}>{c.name}</option>)}
              </select>
            </DashField>
          </div>

          <DashField label="Foto del plato">
            <ImageUploadField
              value={form.img || ''}
              onChange={url => set('img', url)}
              pathPrefix={`restaurants/${brand.id || 'demo'}/items`}
              aspect="4 / 3"
              emptyHint="Arrastra o toca · una buena foto vende el plato"
            />
          </DashField>

          <DashField label="Emoji (respaldo si no hay foto)">
            <input value={form.emoji} onChange={e => set('emoji', e.target.value)}
              placeholder="🍽️" style={{ ...dashInputStyle, width: 80, textAlign: 'center', fontSize: 22 }} />
          </DashField>

          <DashDivider label="Metadata del plato" />

          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 12 }}>
            <DashField label="Tiempo de prep.">
              <input value={form.prepTime} onChange={e => set('prepTime', e.target.value)}
                placeholder="12-18 min" style={dashInputStyle} />
            </DashField>
            <DashField label="Porción">
              <select value={form.portionSize} onChange={e => set('portionSize', e.target.value)} style={dashInputStyle}>
                {portionOpts.map(o => <option key={o} value={o}>{o || '—'}</option>)}
              </select>
            </DashField>
            <DashField label="Nivel de picante">
              <select value={form.spiciness} onChange={e => set('spiciness', e.target.value)} style={dashInputStyle}>
                {spicyOpts.map(o => <option key={o} value={o}>{o}</option>)}
              </select>
            </DashField>
          </div>

          <DashField label="Alérgenos (separados por coma)">
            <input
              value={(form.allergens || []).join(', ')}
              onChange={e => set('allergens', e.target.value.split(',').map(s => s.trim()).filter(Boolean))}
              placeholder="gluten, lácteos, frutos secos…"
              style={dashInputStyle} />
          </DashField>

          <DashField label="Maridaje sugerido">
            <select value={form.suggestedPairing || ''} onChange={e => set('suggestedPairing', e.target.value)} style={dashInputStyle}>
              <option value="">Sin maridaje</option>
              {brand.items.filter(i => i.id !== form.id).map(i => (
                <option key={i.id} value={i.id}>{i.name}</option>
              ))}
            </select>
          </DashField>

          <DashField label="Etiquetas">
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
              {tagOpts.map(({ key, label }) => (
                <button key={key} onClick={() => toggleTag(key)} style={{
                  padding: '6px 14px', borderRadius: 999, fontSize: 12, fontWeight: 600, cursor: 'pointer',
                  background: form.tags.includes(key) ? 'var(--ink)' : 'var(--paper-2)',
                  color: form.tags.includes(key) ? 'var(--paper)' : 'var(--ink)',
                  border: '1px solid ' + (form.tags.includes(key) ? 'var(--ink)' : 'var(--line)'),
                  transition: 'all 150ms',
                }}>
                  {label}
                </button>
              ))}
            </div>
          </DashField>

          <div style={{ height: 8 }} />
        </div>

        {/* Footer */}
        <div style={{
          padding: '16px 24px calc(24px + env(safe-area-inset-bottom, 0px))',
          borderTop: '1px solid var(--line)', display: 'flex', gap: 10,
          position: 'sticky', bottom: 0, background: 'var(--paper)',
        }}>
          <button onClick={onClose} className="btn ghost" style={{ flex: 1 }}>Cancelar</button>
          <button onClick={handleSave} disabled={saving || saved} className="btn accent" style={{
            flex: 2, justifyContent: 'center',
            background: saved ? 'var(--sage-deep, #3A6E35)' : undefined,
            transition: 'background 200ms',
          }}>
            {saved ? '✓ Guardado' : saving ? 'Guardando…' : (isNew ? 'Añadir plato' : 'Guardar cambios')}
          </button>
        </div>
      </div>
    </div>
  );
}

/* ── Menu management ─────────────────────────────────────────────────── */
function DashMenuMgmt({ brand, isMobile }) {
  const cats = brand.categories || [];
  const [openCat,    setOpenCat]    = usD(cats[0]?.id || '');
  const [aiModal,    setAiModal]    = usD(false);
  const [localItems, setLocalItems] = usD(() => (brand.items || []).map(it => ({ ...it, active: it.active !== false })));
  const [editing,    setEditing]    = usD(null);
  const [saveState,  setSaveState]  = usD('');   // '' | 'saving' | 'saved' | 'error'
  const visible = localItems.filter(i => search
    ? i.name.toLowerCase().includes(search.toLowerCase())
    : i.cat === openCat
  );

  const [search, setSearch] = usD('');

  // Persist the full items array to Firestore where the guest app reads it live
  // (doc.menu.items). `active` is mirrored to `available` so the guest's sold-out
  // overlay and add-button reflect the toggle in real time.
  const persistItems = async (nextItems) => {
    const rid = brand.id;
    if (!rid || typeof firebase === 'undefined') return;
    setSaveState('saving');
    try {
      const itemsForSave = nextItems.map(it => ({ ...it, available: it.active !== false }));
      await firebase.firestore().collection('restaurants').doc(rid)
        .set({ menu: { items: itemsForSave } }, { merge: true });
      setSaveState('saved');
      setTimeout(() => setSaveState(s => s === 'saved' ? '' : s), 2200);
    } catch (e) {
      setSaveState('error');
    }
  };

  const toggleActive = (id) => setLocalItems(prev => {
    const next = prev.map(i => i.id === id ? { ...i, active: !i.active } : i);
    persistItems(next);
    return next;
  });

  const handleSaveItem = (saved) => {
    setLocalItems(prev => {
      const exists = prev.some(i => i.id === saved.id);
      const next = exists ? prev.map(i => i.id === saved.id ? saved : i) : [...prev, saved];
      persistItems(next);
      return next;
    });
  };
  const p = isMobile ? '20px 16px 90px' : '40px 56px 80px';
  return (
    <div style={{ padding: p }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: isMobile ? 'flex-start' : 'flex-end', marginBottom: isMobile ? 20 : 40, flexDirection: isMobile ? 'column' : 'row', gap: isMobile ? 12 : 0 }}>
        <div>
          <window.MFMarker label="Editor" />
          <h1 className="display-md" style={{ marginTop: 14, fontWeight: 400, fontSize: isMobile ? 'clamp(28px, 8vw, 48px)' : undefined }}>Tu carta</h1>
        </div>
        <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
          <SaveStatus state={saveState} onRetry={() => persistItems(localItems)} />
          {!isMobile && <button className="btn ghost" onClick={() => setAiModal(true)}><window.MFIcon name="sparkle" size={14} />Mejorar con IA</button>}
          <button className="btn accent" onClick={() => setEditing({})}><window.MFIcon name="plus" size={14} />Nuevo plato</button>
        </div>
      </div>

      <input
        value={search}
        onChange={e => setSearch(e.target.value)}
        placeholder="Buscar plato…"
        style={{ ...dashInputStyle, marginBottom: isMobile ? 12 : 20, maxWidth: isMobile ? '100%' : 280 }}
      />
      {isMobile ? (
        <>
          <div style={{ display: 'flex', gap: 8, overflowX: 'auto', paddingBottom: 12, marginBottom: 16 }}>
            {cats.map(c => (
              <button key={c.id} onClick={() => setOpenCat(c.id)} style={{
                padding: '8px 16px', borderRadius: 999, whiteSpace: 'nowrap', flexShrink: 0,
                background: openCat===c.id ? 'var(--ink)' : 'var(--paper-2)',
                color: openCat===c.id ? 'var(--paper)' : 'var(--ink)',
                border: '1px solid ' + (openCat===c.id ? 'var(--ink)' : 'var(--line)'),
                fontSize: 13, fontFamily: 'var(--serif)', fontStyle: 'italic',
              }}>
                {c.name} <span style={{ marginLeft: 4, fontSize: 11, fontStyle: 'normal', fontFamily: 'var(--sans)', opacity: 0.6 }}>{localItems.filter(i => i.cat===c.id).length}</span>
              </button>
            ))}
          </div>
          <div className="card" style={{ overflow: 'hidden' }}>
            {visible.length === 0 && (
              <div style={{ padding: '32px 20px', textAlign: 'center', color: 'var(--mu)', fontSize: 14 }}>Sin platos en esta categoría</div>
            )}
            {visible.map((it, idx) => (
              <div key={it.id} style={{ padding: '16px 16px', display: 'flex', gap: 14, alignItems: 'flex-start', borderTop: idx>0?'1px solid var(--line)':'none', opacity: it.active !== false ? 1 : 0.5, transition: 'opacity 200ms' }}>
                <div style={{ width: 44, height: 44, borderRadius: 8, flexShrink: 0, background: it.img?`url(${it.img}) center/cover`:'var(--paper-2)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 20 }}>
                  {!it.img && (it.emoji || '🍽')}
                </div>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', gap: 8 }}>
                    <span className="serif-italic" style={{ fontSize: 15 }}>{it.name}</span>
                    <span className="serif" style={{ fontSize: 14, color: 'var(--accent)', flexShrink: 0 }}>${it.price}</span>
                  </div>
                  <div style={{ fontSize: 12, color: 'var(--mu)', marginTop: 3, display: '-webkit-box', WebkitLineClamp: 1, WebkitBoxOrient: 'vertical', overflow: 'hidden' }}>{it.desc}</div>
                </div>
                <button onClick={() => setEditing(it)} style={{ color: 'var(--mu)', padding: 4, flexShrink: 0 }}><window.MFIcon name="edit" size={14} /></button>
                <button onClick={() => toggleActive(it.id)} style={{
                  width: 32, height: 18, borderRadius: 999, position: 'relative', cursor: 'pointer',
                  background: it.active !== false ? 'var(--sage-deep)' : 'var(--line-3)',
                  border: 'none', padding: 0, transition: 'background 200ms', flexShrink: 0, alignSelf: 'center',
                }}>
                  <span style={{
                    position: 'absolute', top: 2,
                    left: it.active !== false ? 'calc(100% - 16px)' : 2,
                    width: 14, height: 14, borderRadius: '50%', background: '#fff',
                    transition: 'left 200ms',
                  }} />
                </button>
              </div>
            ))}
          </div>
        </>
      ) : (
        <div style={{ display: 'grid', gridTemplateColumns: '240px 1fr', gap: 32 }}>
          <div>
            <div style={{ fontSize: 10, letterSpacing: '0.18em', textTransform: 'uppercase', fontWeight: 600, color: 'var(--mu)', marginBottom: 12 }}>Categorías</div>
            {search && <div style={{ fontSize: 10, color: 'var(--mu)', marginBottom: 8, padding: '4px 8px', background: 'var(--paper-2)', borderRadius: 6 }}>Buscando en todo</div>}
            <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
              {cats.map(c => (
                <button key={c.id} onClick={() => setOpenCat(c.id)} style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '12px 14px', borderRadius: 'var(--r-md)', background: openCat===c.id?'var(--paper-2)':'transparent', border: '1px solid '+(openCat===c.id?'var(--line)':'transparent'), textAlign: 'left' }}>
                  <span className="serif-italic" style={{ fontSize: 16 }}>{c.name}</span>
                  <span style={{ fontSize: 11, color: 'var(--mu)' }}>{localItems.filter(i => i.cat===c.id).length}</span>
                </button>
              ))}
            </div>
          </div>
          <div className="card" style={{ overflow: 'hidden' }}>
            {visible.length === 0 && (
              <div style={{ padding: '40px 24px', textAlign: 'center', color: 'var(--mu)', fontSize: 14 }}>Sin platos en esta categoría</div>
            )}
            {visible.map((it, idx) => (
              <div key={it.id} style={{ padding: '20px 24px', display: 'grid', gridTemplateColumns: '64px 1fr 80px 100px 60px', gap: 18, alignItems: 'center', borderTop: idx>0?'1px solid var(--line)':'none', opacity: it.active !== false ? 1 : 0.5, transition: 'opacity 200ms' }}>
                <div style={{ width: 56, height: 56, borderRadius: 8, background: it.img?`url(${it.img}) center/cover`:'var(--paper-2)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 24 }}>
                  {!it.img && (it.emoji || '🍽')}
                </div>
                <div>
                  <div className="serif-italic" style={{ fontSize: 16 }}>{it.name}</div>
                  <div style={{ fontSize: 12, color: 'var(--mu)', marginTop: 4, display: '-webkit-box', WebkitLineClamp: 1, WebkitBoxOrient: 'vertical', overflow: 'hidden' }}>{it.desc}</div>
                  {(it.tags||[]).length>0 && <div style={{ marginTop: 6, display: 'flex', gap: 6 }}>{(it.tags||[]).map(t => <window.MFTag key={t} kind={t} />)}</div>}
                </div>
                <span className="serif" style={{ fontSize: 16, color: 'var(--accent)' }}>${it.price}</span>
                <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                  <button onClick={() => toggleActive(it.id)} style={{
                    width: 32, height: 18, borderRadius: 999, position: 'relative', cursor: 'pointer',
                    background: it.active !== false ? 'var(--sage-deep)' : 'var(--line-3)',
                    border: 'none', padding: 0, transition: 'background 200ms', flexShrink: 0,
                  }}>
                    <span style={{
                      position: 'absolute', top: 2,
                      left: it.active !== false ? 'calc(100% - 16px)' : 2,
                      width: 14, height: 14, borderRadius: '50%', background: '#fff',
                      transition: 'left 200ms',
                    }} />
                  </button>
                  <span style={{ fontSize: 11, color: 'var(--mu)' }}>{it.active !== false ? 'Activo' : 'Oculto'}</span>
                </div>
                <button onClick={() => setEditing(it)} style={{ color: 'var(--mu)' }}><window.MFIcon name="edit" size={14} /></button>
              </div>
            ))}
          </div>
        </div>
      )}

      {editing !== null && (
        <DishEditModal
          brand={{ ...brand, items: localItems }}
          item={editing}
          onClose={() => setEditing(null)}
          onSave={handleSaveItem}
        />
      )}
      {aiModal && <AiComingSoonModal onClose={() => setAiModal(false)} />}
    </div>
  );
}

/* ── Brand kit ───────────────────────────────────────────────────────── */
function DashBrandKit({ brand, isMobile, goTo }) {
  const p = isMobile ? '20px 16px 90px' : '40px 56px 80px';

  // Cover background that guests see on the QR landing screen — uploaded, saved to doc.brand.cover
  const [cover, setCover]         = usD(brand.cover || '');
  const [coverState, setCoverState] = usD(''); // '' | 'saving' | 'saved' | 'error'
  const saveCover = async (url) => {
    setCover(url);
    const rid = brand.id;
    if (!rid || typeof firebase === 'undefined') return;
    setCoverState('saving');
    try {
      await firebase.firestore().collection('restaurants').doc(rid)
        .set({ brand: { cover: url || null } }, { merge: true });
      setCoverState('saved');
      setTimeout(() => setCoverState(s => s === 'saved' ? '' : s), 2200);
    } catch (_) {
      setCoverState('error');
    }
  };

  return (
    <div style={{ padding: p }}>
      <window.MFMarker label="Marca · Identidad" />
      <h1 className="display-md" style={{ marginTop: 14, fontWeight: 400, marginBottom: isMobile ? 20 : 40, fontSize: isMobile ? 'clamp(28px, 8vw, 48px)' : undefined }}>Tu kit visual</h1>
      <div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr' : '1fr 1fr', gap: isMobile ? 16 : 24 }}>
        <div className="card" style={{ padding: 36 }}>
          <window.MFMarker label="Identidad" />
          <div style={{ marginTop: 28 }}>
            {brand.logoUrl
              ? <img src={brand.logoUrl} style={{ height: 72, objectFit: 'contain', background: brand.palette?.bg||'#0a0a0a', borderRadius: 12, padding: 10 }} />
              : <div style={{ fontFamily: 'var(--serif)', fontStyle: 'italic', fontSize: 48, lineHeight: 1 }}>{brand.name[0]}</div>
            }
          </div>
          <div style={{ marginTop: 32, display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: 18 }}>
            <KitItem label="Tagline"   value={brand.tagline} />
            <KitItem label="Ubicación" value={brand.location||brand.subtitle||'—'} />
            <KitItem label="Fundación" value={brand.founded||'—'} />
            <KitItem label="Horario"   value={brand.hours} />
          </div>
          <div style={{ marginTop: 24, paddingTop: 24, borderTop: '1px solid var(--line)' }}>
            <KitItem label="Voz" value={brand.quote} serif />
          </div>
        </div>
        <div className="card" style={{ padding: 36 }}>
          <window.MFMarker label="Color · Tipografía" />
          <div style={{ marginTop: 28 }}>
            <div style={{ fontSize: 11, color: 'var(--mu)', letterSpacing: '0.12em', textTransform: 'uppercase', marginBottom: 10 }}>Acento</div>
            <div style={{ display: 'flex', borderRadius: 'var(--r-md)', overflow: 'hidden', height: 88 }}>
              {[['Primario', brand.accent,'#fff',2],['Deep',brand.accentDeep,'#fff',1],['Soft',brand.accentSoft,'var(--ink)',1]].map(([lbl,col,tc,flex]) => (
                <div key={lbl} style={{ flex, background: col, color: tc, padding: 12, display: 'flex', flexDirection: 'column', justifyContent: 'flex-end' }}>
                  <div style={{ fontSize: 9, letterSpacing: '0.14em', textTransform: 'uppercase' }}>{lbl}</div>
                  <div className="mono" style={{ fontSize: 11 }}>{col}</div>
                </div>
              ))}
            </div>
          </div>
          <div style={{ marginTop: 28 }}>
            <div style={{ fontSize: 11, color: 'var(--mu)', letterSpacing: '0.12em', textTransform: 'uppercase', marginBottom: 14 }}>Tipografía</div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
              <div>
                <div className="serif" style={{ fontSize: 32, fontStyle: 'italic', lineHeight: 1 }}>Aa</div>
                <div style={{ fontSize: 11, color: 'var(--mu)', marginTop: 6 }}>Fraunces · Serif editorial</div>
              </div>
              <div>
                <div style={{ fontSize: 28, fontWeight: 500, letterSpacing: '-0.02em', lineHeight: 1 }}>Aa</div>
                <div style={{ fontSize: 11, color: 'var(--mu)', marginTop: 6 }}>Inter Tight · Sans para UI y descripciones</div>
              </div>
            </div>
          </div>
        </div>
      </div>

      {/* Cover background — what guests see on the QR landing screen */}
      <div className="card" style={{ padding: isMobile ? 24 : 36, marginTop: isMobile ? 16 : 24 }}>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 20, gap: 12 }}>
          <window.MFMarker label="Portada del menú" />
          <SaveStatus state={coverState} onRetry={() => saveCover(cover)} />
        </div>
        <p style={{ fontSize: 13, color: 'var(--mu)', lineHeight: 1.6, marginBottom: 20, maxWidth: 460 }}>
          Esta imagen recibe a tus comensales cuando escanean el QR. Se muestra difuminada
          detrás del nombre de tu restaurante. Sube una foto de tu local, un platillo estrella
          o el ambiente de tu casa.
        </p>
        <div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr' : '1fr 220px', gap: 24, alignItems: 'start' }}>
          <ImageUploadField
            value={cover}
            onChange={saveCover}
            pathPrefix={`restaurants/${brand.id || 'demo'}/cover`}
            aspect="16 / 9"
            emptyHint="Arrastra o toca · una foto del ambiente o un platillo estrella"
          />
          {/* Live phone preview of the guest cover */}
          <div>
            <div style={{ fontSize: 10, letterSpacing: '0.16em', textTransform: 'uppercase', fontWeight: 600, color: 'var(--mu)', marginBottom: 7 }}>Vista previa</div>
            <CoverPreview cover={cover} brand={brand} />
          </div>
        </div>
      </div>

      <div className="card" style={{ padding: 28, marginTop: 24, display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
        <div>
          <div className="serif-italic" style={{ fontSize: 18 }}>¿Quieres ajustar el sistema?</div>
          <p style={{ fontSize: 13, color: 'var(--mu)', marginTop: 4 }}>Cambia el acento, fuentes o sube nuevo logo.</p>
        </div>
        <button className="btn" onClick={() => goTo && goTo('brand-edit')}>Editar marca</button>
      </div>
    </div>
  );
}

/* ── Mini phone preview of the guest cover (mirrors PhCover's blurred bg) ── */
function CoverPreview({ cover, brand }) {
  const accent = brand.accent || '#C8923A';
  const bg = cover
    ? `linear-gradient(180deg, rgba(15,15,14,0.15) 0%, rgba(15,15,14,0.55) 55%, rgba(15,15,14,0.92) 100%), url(${cover}) center/cover`
    : `radial-gradient(ellipse at 30% 20%, ${accent}33 0%, transparent 55%), linear-gradient(180deg, #1a1208 0%, #0b0805 70%)`;
  return (
    <div style={{
      width: '100%', aspectRatio: '9 / 16', borderRadius: 'var(--r-md)', overflow: 'hidden',
      position: 'relative', border: '1px solid var(--line)', maxWidth: 200,
    }}>
      {/* blurred backdrop layer */}
      {cover && (
        <div style={{ position: 'absolute', inset: -8, background: `url(${cover}) center/cover`, filter: 'blur(3px)', transform: 'scale(1.1)' }} />
      )}
      <div style={{ position: 'absolute', inset: 0, background: bg }} />
      <div style={{ position: 'absolute', left: 0, right: 0, bottom: 0, padding: 16, color: '#fff' }}>
        <div className="serif" style={{ fontSize: 22, fontStyle: 'italic', lineHeight: 0.98 }}>{brand.name}</div>
        {brand.tagline && <div style={{ fontSize: 7, letterSpacing: '0.18em', textTransform: 'uppercase', opacity: 0.75, marginTop: 6 }}>{brand.tagline}</div>}
        <div style={{ marginTop: 12, height: 28, borderRadius: 999, background: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 9, fontWeight: 600, color: 'var(--ink)' }}>
          Ver la carta
        </div>
      </div>
    </div>
  );
}

function KitItem({ label, value, serif }) {
  return (
    <div>
      <div style={{ fontSize: 10, letterSpacing: '0.18em', textTransform: 'uppercase', fontWeight: 600, color: 'var(--mu)', marginBottom: 6 }}>{label}</div>
      <div className={serif ? 'serif-italic' : ''} style={{ fontSize: serif ? 18 : 14, color: 'var(--ink)' }}>{value || '—'}</div>
    </div>
  );
}

/* ── Live / Sala ─────────────────────────────────────────────────────── */
function DashLiveOps({ brand, goTo, isMobile, restaurantId }) {
  const { tables: liveTables, loading: tablesLoading } = useLiveTablesD(restaurantId);
  const { stats, loading: statsLoading }               = useTodayStatsD(restaurantId);

  const statusLabel = { kitchen: 'En cocina', ready: 'Listo', ordering: 'Ordenando', paying: 'Cobro' };
  const fmt = (n) => n != null && n > 0 ? `$${Number(n).toLocaleString('es-MX')}` : '—';

  const statusGroups = {
    ordering: liveTables.filter(t => t.status === 'ordering').length,
    kitchen:  liveTables.filter(t => t.status === 'kitchen').length,
    ready:    liveTables.filter(t => t.status === 'ready').length,
    paying:   liveTables.filter(t => t.status === 'paying').length,
  };
  const alerts = liveTables.filter(t => t.helpRequest || t.paymentRequest);
  const [ackedLive, setAckedLive] = usD(() => new Set());
  const visibleAlerts = alerts.filter(t => !ackedLive.has(t.id));

  const p = isMobile ? '20px 16px 90px' : '40px 56px 80px';
  return (
    <div style={{ padding: p }}>
      {/* Header */}
      <div style={{ display: 'flex', alignItems: isMobile ? 'flex-start' : 'center', justifyContent: 'space-between', flexDirection: isMobile ? 'column' : 'row', gap: isMobile ? 16 : 0 }}>
        <div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 14 }}>
            <window.MFMarker label="En vivo" />
            {liveTables.length > 0 && <window.MFLiveDot color="var(--sage-deep)" />}
          </div>
          <h1 className="display-md" style={{ fontWeight: 400, fontSize: isMobile ? 'clamp(28px, 8vw, 48px)' : undefined }}>Sala</h1>
        </div>
        <button className="btn accent" onClick={() => goTo('admin')} title="Abre en una pestaña nueva">
          {isMobile ? 'Abrir consola' : 'Abrir consola de mesero'} <window.MFIcon name="arrowUR" size={14} />
        </button>
      </div>

      {/* Alert banner */}
      {visibleAlerts.length > 0 && (
        <div style={{ marginTop: 24, padding: '12px 18px', background: 'rgba(245,166,35,0.08)', border: '1px solid rgba(245,166,35,0.35)', borderRadius: 'var(--r-md)', display: 'flex', alignItems: 'center', gap: 12 }}>
          <window.MFIcon name="bell" size={15} style={{ color: 'rgba(245,166,35,0.9)', flexShrink: 0 }} />
          <span style={{ fontSize: 13, fontWeight: 500, flex: 1 }}>
            {visibleAlerts.map(t => `Mesa ${t.id} · ${t.helpRequest ? 'llamó al mesero' : 'solicita cuenta'}`).join('   ·   ')}
          </span>
          <button onClick={() => setAckedLive(prev => new Set([...prev, ...visibleAlerts.map(t => t.id)]))}
            style={{ fontSize: 11, color: 'var(--mu)', flexShrink: 0 }}>
            Visto ✓
          </button>
        </div>
      )}

      {/* Status summary */}
      <div style={{ display: 'grid', gridTemplateColumns: isMobile ? 'repeat(2, 1fr)' : 'repeat(4, 1fr)', gap: isMobile ? 10 : 16, marginTop: 28 }}>
        {[
          { label: 'Ordenando', key: 'ordering', color: 'var(--mu)'         },
          { label: 'En cocina', key: 'kitchen',  color: 'var(--accent)'     },
          { label: 'Listo',     key: 'ready',    color: 'var(--sage-deep)'  },
          { label: 'Cobro',     key: 'paying',   color: 'rgba(245,166,35,0.9)' },
        ].map(({ label, key, color }) => (
          <div key={key} className="card" style={{ padding: isMobile ? '14px 16px' : '18px 20px', textAlign: 'center' }}>
            <div style={{ fontSize: 10, letterSpacing: '0.14em', textTransform: 'uppercase', fontWeight: 600, color: 'var(--mu)', marginBottom: 8 }}>{label}</div>
            <div className="serif" style={{ fontSize: 32, fontStyle: 'italic', color, lineHeight: 1 }}>{statusGroups[key]}</div>
          </div>
        ))}
      </div>

      {/* Live table grid */}
      <div style={{ marginTop: isMobile ? 20 : 32 }}>
        <div style={{ fontSize: 11, letterSpacing: '0.18em', textTransform: 'uppercase', fontWeight: 600, color: 'var(--mu)', marginBottom: 14 }}>
          {tablesLoading ? 'Cargando…' : liveTables.length === 0 ? 'Sin mesas activas' : `${liveTables.length} mesa${liveTables.length !== 1 ? 's' : ''} activa${liveTables.length !== 1 ? 's' : ''}`}
        </div>
        {liveTables.length === 0 && !tablesLoading ? (
          <div className="card" style={{ padding: '48px 24px', textAlign: 'center', color: 'var(--mu)', fontSize: 13 }}>
            <div style={{ fontSize: 32, marginBottom: 12 }}>🍽</div>
            Las mesas aparecerán aquí cuando un comensal escanee el QR.
          </div>
        ) : (
          <div className="card" style={{ overflow: 'hidden' }}>
            {liveTables.map((t, idx) => {
              const hasAlert = t.helpRequest || t.paymentRequest;
              return (
                <div key={t.id} style={{ display: 'grid', gridTemplateColumns: isMobile ? '60px 1fr 110px' : '80px 1fr 130px 100px 80px 36px', gap: isMobile ? 10 : 16, alignItems: 'center', padding: '16px 24px', borderTop: idx > 0 ? '1px solid var(--line)' : 'none', borderLeft: hasAlert ? '3px solid rgba(245,166,35,0.6)' : '3px solid transparent', background: hasAlert ? 'rgba(245,166,35,0.04)' : 'transparent', transition: 'background 300ms' }}>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                    <span className="mono" style={{ fontSize: 13, fontWeight: 600 }}>{t.id}</span>
                    {hasAlert && <span style={{ width: 5, height: 5, borderRadius: '50%', background: 'rgba(245,166,35,0.9)', display: 'inline-block', flexShrink: 0 }} />}
                  </div>
                  <div>
                    <div style={{ fontSize: 13, fontWeight: 500 }}>{t.pax} persona{t.pax !== 1 ? 's' : ''}</div>
                    <div style={{ fontSize: 11, color: hasAlert ? 'rgba(245,166,35,0.85)' : 'var(--mu)', marginTop: 2 }}>
                      {t.helpRequest ? '🔔 Llamó al mesero' : t.paymentRequest ? '🧾 Solicita cuenta' : `Abrió ${t.ts}`}
                    </div>
                  </div>
                  <window.MFStatusPill status={t.status} label={statusLabel[t.status] || t.status} />
                  {!isMobile && (
                    <span className="serif" style={{ fontSize: 15, color: t.total ? 'var(--ink)' : 'var(--mu)' }}>
                      {t.total ? `$${t.total.toLocaleString('es-MX')}` : '—'}
                    </span>
                  )}
                  {!isMobile && (
                    <span style={{ fontSize: 11, color: 'var(--mu-2)' }}>
                      {t.helpRequest ? 'Llamó' : t.paymentRequest ? 'Cuenta' : ''}
                    </span>
                  )}
                  {!isMobile && <window.MFIcon name="chevR" size={13} style={{ color: 'var(--mu)', justifySelf: 'end' }} />}
                </div>
              );
            })}
          </div>
        )}
      </div>

      {/* Stats + Activity */}
      <div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr' : '1fr 1.5fr', gap: isMobile ? 16 : 32, marginTop: isMobile ? 16 : 32 }}>
        {/* Today stats */}
        <div className="card" style={{ padding: 28 }}>
          <window.MFMarker label="Resumen de hoy" />
          <div style={{ marginTop: 20, display: 'flex', flexDirection: 'column' }}>
            {[
              ['Tickets cerrados', statsLoading ? React.createElement(SkeletonVal) : String(stats.ticketsToday)],
              ['Ingreso total',    statsLoading ? React.createElement(SkeletonVal) : fmt(stats.revenueToday)],
              ['Ticket promedio',  statsLoading ? React.createElement(SkeletonVal) : fmt(stats.avgTicket)],
            ].map(([label, value], i) => (
              <div key={label} style={{ padding: '14px 0', display: 'flex', justifyContent: 'space-between', alignItems: 'center', borderTop: i > 0 ? '1px solid var(--line)' : 'none' }}>
                <span style={{ fontSize: 12, color: 'var(--mu)' }}>{label}</span>
                <span className="serif" style={{ fontSize: 22, fontStyle: 'italic' }}>{value}</span>
              </div>
            ))}
          </div>
        </div>
        {/* Activity */}
        <ActivityFeed isMobile={isMobile} restaurantId={restaurantId} goTo={goTo} />
      </div>
    </div>
  );
}

/* ── Analytics ───────────────────────────────────────────────────────── */
function DashAnalytics({ brand, isMobile, restaurantId }) {
  const { stats } = useTodayStatsD(restaurantId);
  const p = isMobile ? '20px 16px 90px' : '40px 56px 80px';

  const currentHour = new Date().getHours();
  const hourlyRevenue = Array(24).fill(0);
  (stats.ordersRaw || []).forEach(o => {
    const h = toDateD(o.closedAt).getHours();
    if (h <= currentHour) hourlyRevenue[h] += (o.total || 0);
  });
  const hasRevenueData = hourlyRevenue.some(v => v > 0);
  const maxRevenue = Math.max(...hourlyRevenue, 1);
  const chartHours = hourlyRevenue.map((v, h) => ({ h, v })).filter(({ h }) => h <= currentHour);

  return (
    <div style={{ padding: p }}>
      <window.MFMarker label="Métricas" />
      <h1 className="display-md" style={{ marginTop: 14, fontWeight: 400, marginBottom: isMobile ? 16 : 40, fontSize: isMobile ? 'clamp(28px, 8vw, 48px)' : undefined }}>Hoy</h1>
      <KPIRow isMobile={isMobile} restaurantId={restaurantId} />
      <div className="card" style={{ padding: 32, marginTop: 32 }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
          <div>
            <div style={{ fontSize: 11, color: 'var(--mu)', letterSpacing: '0.18em', textTransform: 'uppercase', fontWeight: 600 }}>Platos en tu carta</div>
            <div style={{ fontSize: 11, color: 'var(--mu)', marginTop: 4 }}>Los datos de popularidad estarán disponibles cuando los comensales empiecen a ordenar.</div>
          </div>
          <span style={{ fontSize: 10, color: 'var(--mu-2)', letterSpacing: '0.1em', textTransform: 'uppercase', flexShrink: 0 }}>Vista previa</span>
        </div>
        <div style={{ marginTop: 24, display: 'flex', flexDirection: 'column', gap: 14 }}>
          {(brand.items||[]).slice(0,6).map((it,i) => (
            <div key={it.id||i} style={{ display: 'grid', gridTemplateColumns: '24px 1fr 1fr 80px', gap: 16, alignItems: 'center' }}>
              <span className="mono" style={{ fontSize: 11, color: 'var(--mu-2)' }}>{String(i+1).padStart(2,'0')}</span>
              <span className="serif-italic" style={{ fontSize: 15 }}>{it.name}</span>
              <span style={{ fontSize: 11, color: 'var(--mu)' }}>{(brand.categories||[]).find(c => c.id === it.cat)?.name || '—'}</span>
              <span className="mono" style={{ fontSize: 12, color: 'var(--accent)', textAlign: 'right' }}>${it.price || 0}</span>
            </div>
          ))}
        </div>
      </div>
      <div className="card" style={{ padding: 32, marginTop: 24 }}>
        <div style={{ fontSize: 11, color: 'var(--mu)', letterSpacing: '0.18em', textTransform: 'uppercase', fontWeight: 600, marginBottom: 20 }}>Ventas por hora</div>
        {!hasRevenueData ? (
          <div style={{ textAlign: 'center', padding: '32px 0', color: 'var(--mu)', fontSize: 13 }}>Los datos de ventas estarán disponibles cuando los comensales empiecen a ordenar.</div>
        ) : (
          <div style={{ height: 200, display: 'flex', alignItems: 'flex-end', gap: 3, paddingBottom: 24, position: 'relative' }}>
            {chartHours.map(({ h, v }) => (
              <div key={h} style={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 4, height: '100%', justifyContent: 'flex-end' }}>
                <div style={{
                  width: '100%', minHeight: v > 0 ? 4 : 1,
                  height: `${(v / maxRevenue) * 88}%`,
                  background: 'var(--accent)', opacity: 0.6, borderRadius: '3px 3px 0 0',
                  transition: 'height 300ms',
                }} />
                <span style={{ fontSize: 8, color: 'var(--mu-2)' }}>{h}</span>
              </div>
            ))}
          </div>
        )}
      </div>
    </div>
  );
}

/* ── Team ────────────────────────────────────────────────────────────── */
function DashTeam({ brand, isMobile }) {
  const [members, setMembers] = usD(() => {
    try { return JSON.parse(localStorage.getItem('mf_team') || 'null') || []; } catch { return []; }
  });
  const [showForm, setShowForm] = usD(false);
  const [form, setForm] = usD({ name: '', email: '', role: 'Mesero' });
  const [expandedMember, setExpandedMember] = usD(null);

  const addMember = () => {
    if (!form.name.trim() || !form.email.trim()) return;
    const next = [...members, { id: 'mb-' + Date.now(), name: form.name, email: form.email, role: form.role }];
    localStorage.setItem('mf_team', JSON.stringify(next));
    setMembers(next);
    setForm({ name: '', email: '', role: 'Mesero' });
    setShowForm(false);
  };

  const updateRole = (id, role) => {
    const next = members.map(m => m.id === id ? { ...m, role } : m);
    localStorage.setItem('mf_team', JSON.stringify(next));
    setMembers(next);
  };

  const p = isMobile ? '20px 16px 90px' : '40px 56px 80px';
  return (
    <div style={{ padding: p }}>
      <window.MFMarker label="Equipo" />
      <h1 className="display-md" style={{ marginTop: 14, fontWeight: 400, marginBottom: isMobile ? 20 : 40, fontSize: isMobile ? 'clamp(28px, 8vw, 48px)' : undefined }}>Tu staff</h1>

      {members.length === 0 && !showForm ? (
        <div className="card" style={{ padding: '48px 24px', textAlign: 'center' }}>
          <div style={{ fontSize: 32, marginBottom: 12 }}>👥</div>
          <div style={{ fontSize: 14, fontWeight: 500, marginBottom: 6 }}>Todavía no has invitado a nadie</div>
          <div style={{ fontSize: 12, color: 'var(--mu)', marginBottom: 20 }}>Invita a tu equipo para que gestionen el menú y la sala.</div>
          <button className="btn" onClick={() => setShowForm(true)}><window.MFIcon name="plus" size={13} />Invitar miembro</button>
        </div>
      ) : (
        <>
          {members.length > 0 && (
            <div className="card" style={{ overflow: 'hidden', marginBottom: showForm ? 18 : 0 }}>
              {members.map((m, i) => (
                <React.Fragment key={m.id}>
                  <div style={{ padding: '18px 24px', display: 'flex', alignItems: 'center', gap: 16, borderTop: i > 0 ? '1px solid var(--line)' : 'none' }}>
                    <div style={{ width: 40, height: 40, borderRadius: '50%', background: 'var(--paper-2)', display: 'grid', placeItems: 'center', fontFamily: 'var(--serif)', fontStyle: 'italic' }}>{m.name[0]}</div>
                    <div style={{ flex: 1 }}>
                      <div style={{ fontSize: 14, fontWeight: 500 }}>{m.name}</div>
                      <div style={{ fontSize: 12, color: 'var(--mu)' }}>{m.role} · {m.email}</div>
                    </div>
                    <button className="btn ghost sm" onClick={() => setExpandedMember(expandedMember === m.id ? null : m.id)}>Permisos</button>
                  </div>
                  {expandedMember === m.id && (
                    <div style={{ padding: '12px 24px 16px', background: 'var(--paper-2)', borderTop: '1px solid var(--line)' }}>
                      <DashField label="Rol">
                        <select value={m.role} onChange={e => updateRole(m.id, e.target.value)} style={dashInputStyle}>
                          {['Dueño', 'Mesero', 'Cocina', 'Caja'].map(r => <option key={r} value={r}>{r}</option>)}
                        </select>
                      </DashField>
                    </div>
                  )}
                </React.Fragment>
              ))}
            </div>
          )}
          {!showForm && (
            <button className="btn" style={{ marginTop: members.length > 0 ? 18 : 0 }} onClick={() => setShowForm(true)}><window.MFIcon name="plus" size={13} />Invitar miembro</button>
          )}
        </>
      )}

      {showForm && (
        <div className="card" style={{ padding: 24, marginTop: members.length > 0 ? 18 : 0, border: '1px solid var(--accent)' }}>
          <div style={{ fontSize: 13, fontWeight: 500, marginBottom: 16 }}>Nuevo miembro</div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
            <DashField label="Nombre">
              <input value={form.name} onChange={e => setForm(f => ({ ...f, name: e.target.value }))} placeholder="Nombre completo" style={dashInputStyle} />
            </DashField>
            <DashField label="Email">
              <input value={form.email} onChange={e => setForm(f => ({ ...f, email: e.target.value }))} placeholder="email@ejemplo.com" type="email" style={dashInputStyle} />
            </DashField>
            <DashField label="Rol">
              <select value={form.role} onChange={e => setForm(f => ({ ...f, role: e.target.value }))} style={dashInputStyle}>
                {['Dueño', 'Mesero', 'Cocina', 'Caja'].map(r => <option key={r} value={r}>{r}</option>)}
              </select>
            </DashField>
            <div style={{ display: 'flex', gap: 8, marginTop: 4 }}>
              <button className="btn ghost" style={{ flex: 1 }} onClick={() => setShowForm(false)}>Cancelar</button>
              <button className="btn accent" style={{ flex: 2, justifyContent: 'center' }} onClick={addMember}>Enviar invitación</button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

/* ── POS Connect Modal ───────────────────────────────────────────────── */
function POSConnectModal({ onClose, restaurantId }) {
  const [tab, setTab]               = usD('webhook');
  const [webhookUrl, setWebhookUrl] = usD(() => localStorage.getItem('mf_wh_url') || '');
  const [whSecret, setWhSecret]     = usD(() => localStorage.getItem('mf_wh_secret') || '');
  const [provider, setProvider]     = usD(() => localStorage.getItem('mf_pos_provider') || 'square');
  const [apiKey, setApiKey]         = usD(() => localStorage.getItem('mf_pos_apikey') || '');
  const [testing, setTesting]       = usD(false);
  const [testResult, setTestResult] = usD(null);
  const [saved, setSaved]           = usD(false);

  const save = () => {
    if (tab === 'webhook') {
      localStorage.setItem('mf_wh_url', webhookUrl);
      localStorage.setItem('mf_wh_secret', whSecret);
      localStorage.setItem('mf_pos_method', 'webhook');
    } else {
      localStorage.setItem('mf_pos_provider', provider);
      localStorage.setItem('mf_pos_apikey', apiKey);
      localStorage.setItem('mf_pos_method', 'api');
    }
    localStorage.setItem('mf_pos_connected', '1');
    setSaved(true);
    setTimeout(onClose, 700);
  };

  const testWebhook = async () => {
    if (!webhookUrl) return;
    setTesting(true);
    setTestResult(null);
    const payload = { event: 'test', timestamp: new Date().toISOString(), restaurantId, tableId: 'M-01', message: 'Webhook de prueba desde Menu Factory' };
    try {
      const headers = { 'Content-Type': 'application/json' };
      if (whSecret) headers['X-Menu-Secret'] = whSecret;
      const res = await fetch(webhookUrl, { method: 'POST', headers, body: JSON.stringify(payload) });
      setTestResult(res.ok ? 'ok' : String(res.status));
    } catch (e) {
      setTestResult('error: ' + e.message);
    }
    setTesting(false);
  };

  const canSave = tab === 'webhook' ? !!webhookUrl : !!apiKey;

  return (
    <div onClick={e => { if (e.target === e.currentTarget) onClose(); }} style={{
      position: 'fixed', inset: 0, zIndex: 300,
      background: 'rgba(10,8,5,0.55)', backdropFilter: 'blur(4px)',
      display: 'flex', alignItems: window.innerWidth >= 768 ? 'center' : 'flex-end', justifyContent: 'center',
    }}>
      <div style={{ width: '100%', maxWidth: 560, background: 'var(--paper)', borderRadius: window.innerWidth >= 768 ? 'var(--r-lg)' : '20px 20px 0 0', maxHeight: window.innerWidth >= 768 ? '90vh' : '85vh', marginTop: window.innerWidth >= 768 ? 20 : 0, overflowY: 'auto', display: 'flex', flexDirection: 'column' }}>
        <div style={{ padding: '22px 24px 16px', display: 'flex', justifyContent: 'space-between', alignItems: 'center', position: 'sticky', top: 0, background: 'var(--paper)', zIndex: 1, borderBottom: '1px solid var(--line)' }}>
          <div>
            <window.MFMarker label="Integraciones" />
            <h2 style={{ marginTop: 6, fontSize: 20, fontFamily: 'var(--serif)', fontStyle: 'italic', fontWeight: 400 }}>Conectar POS</h2>
          </div>
          <button onClick={onClose} style={{ width: 36, height: 36, borderRadius: '50%', background: 'var(--paper-2)', display: 'grid', placeItems: 'center' }}>
            <window.MFIcon name="x" size={14} />
          </button>
        </div>

        <div style={{ display: 'flex', padding: '16px 24px 0', gap: 8 }}>
          {[['webhook', 'Webhook'], ['api', 'API directa']].map(([id, lbl]) => (
            <button key={id} onClick={() => setTab(id)} style={{
              padding: '7px 16px', borderRadius: 20, fontSize: 13, fontWeight: 500,
              background: tab === id ? 'var(--accent)' : 'var(--paper-2)',
              color: tab === id ? '#fff' : 'var(--ink)',
              border: tab === id ? 'none' : '1px solid var(--line)',
            }}>{lbl}</button>
          ))}
        </div>

        <div style={{ padding: '20px 24px', flex: 1, display: 'flex', flexDirection: 'column', gap: 16 }}>
          {tab === 'webhook' && (
            <>
              <DashField label="URL del endpoint">
                <input value={webhookUrl} onChange={e => setWebhookUrl(e.target.value)}
                  placeholder="https://tu-servidor.com/webhook" style={dashInputStyle} />
              </DashField>
              <DashField label="Secreto compartido (opcional)">
                <input value={whSecret} onChange={e => setWhSecret(e.target.value)}
                  placeholder="Cabecera X-Menu-Secret" style={dashInputStyle} type="password" />
              </DashField>
              <div style={{ background: 'var(--paper-2)', borderRadius: 12, padding: '14px 16px' }}>
                <div style={{ fontSize: 11, fontWeight: 600, letterSpacing: '0.1em', textTransform: 'uppercase', color: 'var(--mu)', marginBottom: 10 }}>Eventos disponibles</div>
                {[
                  ['order.sent',           'Mesa envía pedido a cocina'],
                  ['order.status_changed', 'Estado del pedido avanza'],
                  ['order.paid',           'Mesa cierra cuenta'],
                ].map(([evt, desc]) => (
                  <div key={evt} style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '7px 0', borderBottom: '1px solid var(--line)' }}>
                    <code style={{ fontSize: 12, color: 'var(--accent)' }}>{evt}</code>
                    <span style={{ color: 'var(--mu)', fontSize: 12 }}>{desc}</span>
                  </div>
                ))}
              </div>
              {testResult && (
                <div style={{ padding: '10px 14px', borderRadius: 10, fontSize: 13, background: testResult === 'ok' ? '#e6f7ee' : '#fff0f0', color: testResult === 'ok' ? '#0a7a3b' : '#c0392b' }}>
                  {testResult === 'ok' ? '✓ Webhook respondió correctamente' : 'Error: ' + testResult}
                </div>
              )}
            </>
          )}
          {tab === 'api' && (
            <>
              <DashField label="Sistema POS">
                <select value={provider} onChange={e => setProvider(e.target.value)} style={dashInputStyle}>
                  <option value="square">Square</option>
                  <option value="toast">Toast</option>
                  <option value="loyverse">Loyverse</option>
                  <option value="other">Otro / Custom</option>
                </select>
              </DashField>
              <DashField label="API Key">
                <input value={apiKey} onChange={e => setApiKey(e.target.value)}
                  placeholder="sk_live_…" style={dashInputStyle} type="password" />
              </DashField>
              <div style={{ padding: '12px 14px', borderRadius: 10, background: 'var(--paper-2)', fontSize: 12, color: 'var(--mu)', lineHeight: 1.6 }}>
                La conexión directa vía API sincroniza ítems, precios y pedidos con tu POS en tiempo real. Requiere plan Salón o superior.
              </div>
            </>
          )}
        </div>

        <div style={{ padding: '16px 24px', borderTop: '1px solid var(--line)', display: 'flex', gap: 10, position: 'sticky', bottom: 0, background: 'var(--paper)' }}>
          {tab === 'webhook' && (
            <button onClick={testWebhook} disabled={!webhookUrl || testing} style={{
              flex: 1, padding: 12, borderRadius: 12, fontSize: 14, fontWeight: 500,
              background: 'var(--paper-2)', color: 'var(--ink)', border: '1px solid var(--line)',
              opacity: !webhookUrl || testing ? 0.5 : 1,
            }}>
              {testing ? 'Probando…' : 'Probar'}
            </button>
          )}
          <button onClick={save} disabled={!canSave} style={{
            flex: 2, padding: 12, borderRadius: 12, fontSize: 14, fontWeight: 600,
            background: saved ? '#0a7a3b' : 'var(--accent)', color: '#fff',
            opacity: canSave ? 1 : 0.5,
          }}>
            {saved ? '✓ Guardado' : 'Guardar conexión'}
          </button>
        </div>
      </div>
    </div>
  );
}

/* ── Webhook Management Panel ────────────────────────────────────────── */
function WebhookPanel({ onClose, restaurantId }) {
  const [webhooks, setWebhooks] = usD(() => {
    try { return JSON.parse(localStorage.getItem('mf_webhooks') || '[]'); } catch { return []; }
  });
  const [adding, setAdding]     = usD(false);
  const [url, setUrl]           = usD('');
  const [secret, setSecret]     = usD('');
  const [testing, setTesting]   = usD(null);
  const [results, setResults]   = usD({});

  const addWebhook = () => {
    if (!url) return;
    const next = [...webhooks, { id: 'wh-' + Date.now(), url, secret, events: ['order.sent', 'order.status_changed', 'order.paid'] }];
    localStorage.setItem('mf_webhooks', JSON.stringify(next));
    setWebhooks(next);
    setAdding(false);
    setUrl('');
    setSecret('');
  };

  const removeWebhook = (id) => {
    const next = webhooks.filter(w => w.id !== id);
    localStorage.setItem('mf_webhooks', JSON.stringify(next));
    setWebhooks(next);
  };

  const testWebhook = async (wh) => {
    setTesting(wh.id);
    const payload = { event: 'test', timestamp: new Date().toISOString(), restaurantId, message: 'Test desde Menu Factory' };
    try {
      const headers = { 'Content-Type': 'application/json' };
      if (wh.secret) headers['X-Menu-Secret'] = wh.secret;
      const res = await fetch(wh.url, { method: 'POST', headers, body: JSON.stringify(payload) });
      setResults(r => ({ ...r, [wh.id]: res.ok ? 'ok' : String(res.status) }));
    } catch {
      setResults(r => ({ ...r, [wh.id]: 'error' }));
    }
    setTesting(null);
  };

  return (
    <div onClick={e => { if (e.target === e.currentTarget) onClose(); }} style={{
      position: 'fixed', inset: 0, zIndex: 300,
      background: 'rgba(10,8,5,0.55)', backdropFilter: 'blur(4px)',
      display: 'flex', alignItems: window.innerWidth >= 768 ? 'center' : 'flex-end', justifyContent: 'center',
    }}>
      <div style={{ width: '100%', maxWidth: 560, background: 'var(--paper)', borderRadius: window.innerWidth >= 768 ? 'var(--r-lg)' : '20px 20px 0 0', maxHeight: window.innerWidth >= 768 ? '90vh' : '85vh', marginTop: window.innerWidth >= 768 ? 20 : 0, overflowY: 'auto', display: 'flex', flexDirection: 'column' }}>
        <div style={{ padding: '22px 24px 16px', display: 'flex', justifyContent: 'space-between', alignItems: 'center', position: 'sticky', top: 0, background: 'var(--paper)', zIndex: 1, borderBottom: '1px solid var(--line)' }}>
          <div>
            <window.MFMarker label="Integraciones" />
            <h2 style={{ marginTop: 6, fontSize: 20, fontFamily: 'var(--serif)', fontStyle: 'italic', fontWeight: 400 }}>Webhooks de salida</h2>
          </div>
          <button onClick={onClose} style={{ width: 36, height: 36, borderRadius: '50%', background: 'var(--paper-2)', display: 'grid', placeItems: 'center' }}>
            <window.MFIcon name="x" size={14} />
          </button>
        </div>

        <div style={{ padding: '20px 24px', flex: 1, display: 'flex', flexDirection: 'column', gap: 12 }}>
          {webhooks.length === 0 && !adding && (
            <div style={{ textAlign: 'center', padding: '32px 0', color: 'var(--mu)', fontSize: 14 }}>Sin endpoints configurados</div>
          )}
          {webhooks.map(wh => (
            <div key={wh.id} style={{ border: '1px solid var(--line)', borderRadius: 12, padding: '14px 16px' }}>
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 8 }}>
                <div style={{ fontSize: 13, fontWeight: 500, wordBreak: 'break-all', flex: 1, marginRight: 8 }}>{wh.url}</div>
                <button onClick={() => removeWebhook(wh.id)} style={{ fontSize: 11, color: 'var(--warn)', flexShrink: 0 }}>Eliminar</button>
              </div>
              <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', marginBottom: 10 }}>
                {wh.events.map(e => <span key={e} style={{ fontSize: 10, padding: '2px 8px', background: 'var(--paper-2)', borderRadius: 20, color: 'var(--accent)' }}>{e}</span>)}
              </div>
              <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                <button onClick={() => testWebhook(wh)} disabled={testing === wh.id} style={{ fontSize: 12, color: 'var(--accent)', fontWeight: 500 }}>
                  {testing === wh.id ? 'Probando…' : 'Probar →'}
                </button>
                {results[wh.id] && (
                  <span style={{ fontSize: 12, color: results[wh.id] === 'ok' ? '#0a7a3b' : '#c0392b' }}>
                    {results[wh.id] === 'ok' ? '✓ OK' : '✗ ' + results[wh.id]}
                  </span>
                )}
              </div>
            </div>
          ))}

          {adding ? (
            <div style={{ border: '1px solid var(--accent)', borderRadius: 12, padding: 16 }}>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
                <DashField label="URL del endpoint">
                  <input value={url} onChange={e => setUrl(e.target.value)} placeholder="https://…" style={dashInputStyle} />
                </DashField>
                <DashField label="Secreto (opcional)">
                  <input value={secret} onChange={e => setSecret(e.target.value)} placeholder="X-Menu-Secret" style={dashInputStyle} type="password" />
                </DashField>
                <div style={{ display: 'flex', gap: 8 }}>
                  <button onClick={() => setAdding(false)} style={{ flex: 1, padding: 10, borderRadius: 10, fontSize: 13, background: 'var(--paper-2)', color: 'var(--ink)', border: '1px solid var(--line)' }}>Cancelar</button>
                  <button onClick={addWebhook} disabled={!url} style={{ flex: 2, padding: 10, borderRadius: 10, fontSize: 13, fontWeight: 600, background: 'var(--accent)', color: '#fff', opacity: url ? 1 : 0.5 }}>Guardar</button>
                </div>
              </div>
            </div>
          ) : (
            <button onClick={() => setAdding(true)} style={{ padding: 12, borderRadius: 12, fontSize: 13, fontWeight: 500, border: '2px dashed var(--line)', background: 'transparent', color: 'var(--mu)', width: '100%' }}>
              + Agregar endpoint
            </button>
          )}
        </div>

        <div style={{ padding: '14px 24px', borderTop: '1px solid var(--line)', background: 'var(--paper)', position: 'sticky', bottom: 0 }}>
          <div style={{ fontSize: 12, color: 'var(--mu)', lineHeight: 1.6 }}>
            POST enviado a cada endpoint en <code style={{ fontSize: 11 }}>order.sent</code>, <code style={{ fontSize: 11 }}>order.status_changed</code> y <code style={{ fontSize: 11 }}>order.paid</code>.
          </div>
        </div>
      </div>
    </div>
  );
}

/* ── Settings ────────────────────────────────────────────────────────── */
function DashSettings({ brand, isMobile }) {
  const [posModal,      setPosModal]      = usD(false);
  const [webhookPanel,  setWebhookPanel]  = usD(false);
  const [posConnected,  setPosConnected]  = usD(() => !!localStorage.getItem('mf_pos_connected'));
  const [webhookCount,  setWebhookCount]  = usD(() => {
    try { return JSON.parse(localStorage.getItem('mf_webhooks') || '[]').length; } catch { return 0; }
  });

  const posMethod   = localStorage.getItem('mf_pos_method');
  const posProvider = localStorage.getItem('mf_pos_provider');
  const posValue    = posConnected
    ? (posMethod === 'api' ? (posProvider ? posProvider.charAt(0).toUpperCase() + posProvider.slice(1) : 'POS') + ' · Conectado' : 'Webhook activo')
    : 'Sin conectar';
  const whValue     = webhookCount === 0 ? '0 endpoints activos' : webhookCount + ' endpoint' + (webhookCount !== 1 ? 's' : '') + ' activo' + (webhookCount !== 1 ? 's' : '');

  const p = isMobile ? '20px 16px 90px' : '40px 56px 80px';
  return (
    <div style={{ padding: p }}>
      <window.MFMarker label="Ajustes" />
      <h1 className="display-md" style={{ marginTop: 14, fontWeight: 400, marginBottom: isMobile ? 20 : 32, fontSize: isMobile ? 'clamp(28px, 8vw, 48px)' : undefined }}>Tu cuenta</h1>
      <div className="card" style={{ padding: 32, maxWidth: 720 }}>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 22 }}>
          <SettingRow label="Plan actual" value="Salón · $890 / mes"   action="Cambiar plan" />
          <SettingRow label="Dominio"     value={brand.id+'.menu.app'} action="Conectar dominio propio" />
          <SettingRow label="Idiomas"     value="Español + Inglés"      action="Agregar idioma" />
          <SettingRow label="Moneda"      value="MXN · Peso mexicano"   action="Cambiar" />
          <SettingRow label="POS"         value={posValue}              action={posConnected ? 'Reconfigurar' : 'Conectar Square / Toast'} danger={!posConnected} onClick={() => setPosModal(true)} />
          <SettingRow label="Webhooks"    value={whValue}               action="Gestionar webhooks" onClick={() => setWebhookPanel(true)} />
        </div>
      </div>
      {posModal     && <POSConnectModal onClose={() => { setPosModal(false);     setPosConnected(!!localStorage.getItem('mf_pos_connected')); }} restaurantId={brand.id} />}
      {webhookPanel && <WebhookPanel    onClose={() => { setWebhookPanel(false); try { setWebhookCount(JSON.parse(localStorage.getItem('mf_webhooks') || '[]').length); } catch {} }} restaurantId={brand.id} />}
    </div>
  );
}

function SettingRow({ label, value, action, danger, onClick }) {
  return (
    <div style={{ display:'flex', justifyContent:'space-between', alignItems:'center', paddingBottom:20, borderBottom:'1px solid var(--line)' }}>
      <div>
        <div style={{ fontSize:10, letterSpacing:'0.18em', textTransform:'uppercase', fontWeight:600, color:'var(--mu)' }}>{label}</div>
        <div style={{ fontSize:14, marginTop:6, color:'var(--ink)' }}>{value}</div>
      </div>
      <button
        onClick={onClick}
        className={danger ? 'btn ghost sm' : 'btn sm'}
        style={{ color: danger ? 'var(--warn)' : undefined, borderColor: danger ? 'var(--warn)' : undefined, flexShrink: 0 }}
      >{action}</button>
    </div>
  );
}

/* ── GuestPreviewView — VERBATIM (Firebase write) ────────────────────── */
function GuestPreviewView({ restaurantId }) {
  const [dir, setDir] = usD(() => localStorage.getItem('mf_display_dir') || 'editorial');
  const dirs = [
    ['editorial', 'A · Folklor', 'Dark · Serif · Editorial'],
    ['bento',     'B · Bento',   'Light · Cards · Apple'],
    ['story',     'C · Story',   'Full-bleed · Swipe'],
    ['ar',        'D · AR Glass','Dark · Glass · Augmented'],
  ];

  const saveDir = (id) => {
    setDir(id);
    localStorage.setItem('mf_display_dir', id);
    if (restaurantId && typeof firebase !== 'undefined') {
      try {
        firebase.firestore().collection('restaurants').doc(restaurantId)
          .update({ 'settings.displayDirection': id })
          .catch(() => {});
      } catch (_) {}
    }
  };

  const rid = restaurantId || 'demo';
  const guestUrl = `MENU%20structure/index.html?table=M-01&restaurant=${rid}`;
  const adminUrl = `MENU%20structure/index.html?restaurant=${rid}&staff=1`;

  return (
    <div>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 28 }}>
        <div>
          <div className="eyebrow dot">Pantalla del comensal</div>
          <h1 className="display display-md" style={{ marginTop: 12 }}>
            Elige tu <span className="italic">dirección visual</span>
          </h1>
          <p style={{ fontSize: 13, color: 'var(--mu)', marginTop: 8, maxWidth: 480 }}>
            Así verán el menú tus comensales al escanear el QR. Elige el estilo, guárdalo y ábrelo en vivo con tus colores y platos reales.
          </p>
        </div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 10, flexShrink: 0, alignItems: 'flex-end' }}>
          <a href={guestUrl} target="_blank" rel="noreferrer" className="btn coral"
            style={{ textDecoration: 'none', display: 'flex', alignItems: 'center', gap: 8 }}>
            <span>↗</span> Abrir menú (cliente)
          </a>
          <a href={adminUrl} target="_blank" rel="noreferrer" className="btn ghost"
            style={{ textDecoration: 'none', display: 'flex', alignItems: 'center', gap: 8 }}>
            <span>⚙</span> Abrir panel admin
          </a>
        </div>
      </div>

      <div style={{ display: 'flex', gap: 10, marginBottom: 32 }}>
        {dirs.map(([id, label, sub]) => (
          <button key={id} onClick={() => saveDir(id)} style={{
            padding: '10px 18px', borderRadius: 10, textAlign: 'left',
            background: dir === id ? 'var(--ink)' : 'var(--bg)',
            color: dir === id ? '#fff' : 'var(--mu)',
            border: `1px solid ${dir === id ? 'var(--ink)' : 'var(--line)'}`,
            transition: 'all 160ms',
          }}>
            <div style={{ fontSize: 13, fontWeight: 600, color: dir === id ? '#fff' : 'var(--ink)' }}>{label}</div>
            <div style={{ fontSize: 10, marginTop: 2, color: dir === id ? 'rgba(255,255,255,0.6)' : 'var(--mu)' }}>{sub}</div>
          </button>
        ))}
      </div>

      <div style={{ fontSize: 12, color: 'var(--ok)', marginBottom: 20, display: 'flex', alignItems: 'center', gap: 6 }}>
        <span>●</span> Dirección guardada: <strong style={{ color: 'var(--ink)' }}>{dirs.find(d => d[0] === dir)?.[1]}</strong>
        — se aplica al abrir el menú en vivo
      </div>

      <div style={{ display: 'flex', justifyContent: 'center', gap: 40 }}>
        {dir === 'editorial' && <window.MFGuestEditorial />}
        {dir === 'bento'     && <window.MFGuestBento />}
        {dir === 'story'     && <window.MFGuestStory />}
        {dir === 'ar'        && <window.MFGuestAR />}
      </div>

      <div style={{ marginTop: 32, padding: '20px 24px', background: 'var(--bg)', border: '1px solid var(--line)', borderRadius: 14, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
        <div>
          <div style={{ fontSize: 14, fontWeight: 600 }}>¿Listo para compartirlo?</div>
          <div style={{ fontSize: 12, color: 'var(--mu)', marginTop: 2 }}>Imprime el QR y pégalo en cada mesa. Cada mesa tiene su propia URL.</div>
        </div>
        <a href={guestUrl} target="_blank" rel="noreferrer" className="btn coral" style={{ textDecoration: 'none', flexShrink: 0 }}>
          Probar menú live ↗
        </a>
      </div>
    </div>
  );
}

/* ── MesasView — VERBATIM (real Google Charts QRs) ───────────────────── */
function MesasView({ restaurantId }) {
  const [tableCount, setTableCount] = usD(10);
  const [prefix, setPrefix]         = usD('M-');

  const rid    = restaurantId || 'demo';
  const count  = Math.min(50, Math.max(1, tableCount || 1));
  const tables = Array.from({ length: count }, (_, i) => `${prefix}${String(i + 1).padStart(2, '0')}`);

  const getTableUrl = (tableId) => {
    const base = window.location.href.split('?')[0].replace(/[^/]+$/, '');
    return `${base}MENU%20structure/index.html?table=${encodeURIComponent(tableId)}&restaurant=${encodeURIComponent(rid)}`;
  };

  const download = (id) => {
    if (window.QRCode) {
      window.QRCode.toDataURL(getTableUrl(id), {
        width: 280,
        margin: 1,
        color: { dark: '#0f0f0e', light: '#ffffff' }
      }, (error, dataUrl) => {
        if (error) {
          console.error('Error generating QR:', error);
          return;
        }
        const a = document.createElement('a');
        a.href = dataUrl;
        a.download = `QR-Mesa-${id}.png`;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
      });
    }
  };

  const downloadAll = async () => {
    for (const id of tables) {
      download(id);
      await new Promise(r => setTimeout(r, 250));
    }
  };

  function TableQR({ url, displaySize = 140 }) {
    const [src, setSrc] = React.useState('');
    React.useEffect(() => {
      if (window.QRCode) {
        // Generate a 280x280 image for Retina displays, but show at displaySize
        window.QRCode.toDataURL(url, {
          width: 280, margin: 1, color: { dark: '#0f0f0e', light: '#ffffff' }
        }, (error, dataUrl) => {
          if (!error) setSrc(dataUrl);
        });
      }
    }, [url]);
    
    if (!src) return <div style={{ width: displaySize, height: displaySize, background: 'var(--paper-2)' }} />;
    return <img src={src} alt="QR" style={{ display: 'block', width: displaySize, height: displaySize, objectFit: 'contain' }} />;
  }

  return (
    <div>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-end', marginBottom: 32 }}>
        <div>
          <window.MFMarker label="Mesas · QR" />
          <h1 className="display-md" style={{ marginTop: 14, fontWeight: 400 }}>
            Un QR por <em>mesa</em>
          </h1>
          <p style={{ fontSize: 13, color: 'var(--mu)', marginTop: 8, maxWidth: 520 }}>
            Cada QR lleva al comensal directo al menú de su mesa. Imprímelo, recórtalo y pégalo en la mesa.
          </p>
        </div>
        <button className="btn coral" onClick={downloadAll}>↓ Descargar todos</button>
      </div>

      <div className="card" style={{ padding: '16px 20px', marginBottom: 24, display: 'flex', gap: 24, alignItems: 'center' }}>
        <div>
          <div style={{ fontSize: 11, color: 'var(--mu)', marginBottom: 6, fontWeight: 600, letterSpacing: '0.08em', textTransform: 'uppercase' }}>Número de mesas</div>
          <input type="number" className="input" value={tableCount} min={1} max={50}
            onChange={e => setTableCount(parseInt(e.target.value) || 1)} style={{ width: 72 }} />
        </div>
        <div>
          <div style={{ fontSize: 11, color: 'var(--mu)', marginBottom: 6, fontWeight: 600, letterSpacing: '0.08em', textTransform: 'uppercase' }}>Prefijo</div>
          <input type="text" className="input" value={prefix} onChange={e => setPrefix(e.target.value)} style={{ width: 80 }} placeholder="M-" />
        </div>
        <div style={{ fontSize: 12, color: 'var(--mu)', marginTop: 18 }}>
          Ejemplo: <span className="mono" style={{ color: 'var(--ink)' }}>{tables[0]}</span>
          {tables[1] ? <>, <span className="mono" style={{ color: 'var(--ink)' }}>{tables[1]}</span>…</> : null}
        </div>
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(176px, 1fr))', gap: 14 }}>
        {tables.map(id => (
          <div key={id} className="card" style={{ padding: 18, display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 12 }}>
            <div className="serif italic" style={{ fontSize: 20, alignSelf: 'flex-start' }}>{id}</div>
            <div style={{ width: 140, height: 140, background: '#fff', borderRadius: 10, border: '1px solid var(--line)', overflow: 'hidden' }}>
              <TableQR url={getTableUrl(id)} displaySize={140} />
            </div>
            <div style={{ display: 'flex', gap: 7, width: '100%' }}>
              <a href={getTableUrl(id)} target="_blank" rel="noreferrer" className="btn ghost"
                style={{ flex: 1, textDecoration: 'none', fontSize: 11, padding: '7px 8px', textAlign: 'center' }}>Abrir ↗</a>
              <button className="btn coral" style={{ flex: 1, fontSize: 11, padding: '7px 8px' }} onClick={() => download(id)}>↓ QR</button>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

/* ── Mobile bottom nav ───────────────────────────────────────────────── */
const DASH_MOBILE_TABS = [
  { id: 'home',     label: 'Inicio',   icon: 'home'     },
  { id: 'menu',     label: 'Menú',     icon: 'fork'     },
  { id: 'live',     label: 'Sala',     icon: 'activity' },
  { id: 'comensal', label: 'Pantalla', icon: 'eye'      },
  { id: 'settings', label: 'Ajustes',  icon: 'settings' },
];

function DashMobileNav({ tab, setTab, liveCount }) {
  return (
    <div style={{
      position: 'fixed', bottom: 0, left: 0, right: 0, zIndex: 200,
      background: 'var(--paper)', borderTop: '1px solid var(--line)',
      display: 'flex', paddingBottom: 'env(safe-area-inset-bottom, 4px)',
    }}>
      {DASH_MOBILE_TABS.map(t => (
        <button key={t.id} onClick={() => setTab(t.id)} style={{
          flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center',
          padding: '10px 0 8px', gap: 3, background: 'none',
          color: tab === t.id ? 'var(--accent)' : 'var(--mu-2)',
          transition: 'color 140ms',
        }}>
          <div style={{ position: 'relative' }}>
            <window.MFIcon name={t.icon} size={18} />
            {t.id === 'live' && liveCount > 0 && (
              <span style={{
                position: 'absolute', top: -4, right: -6,
                background: 'var(--accent)', color: '#fff',
                fontSize: 8, fontWeight: 700, borderRadius: 999,
                padding: '1px 4px', lineHeight: 1.4,
              }}>{liveCount}</span>
            )}
          </div>
          <span style={{ fontSize: 9, letterSpacing: '0.06em', textTransform: 'uppercase', fontWeight: tab === t.id ? 600 : 400 }}>{t.label}</span>
        </button>
      ))}
    </div>
  );
}

/* ── MFDashboard adapter ─────────────────────────────────────────────── */
function MFDashboard({ profile: profileProp, onSignOut, onEditBrand }) {
  const [tab, setTab] = usD('home');
  const isMobile = useMobileD();

  const profileData = profileProp || {
    user: { name: 'Demo', email: 'demo@restaurante.mx' },
    brand: window.MF_BRAND,
    menu: window.MF_MENU,
    logoUrl: null,
  };
  const { user } = profileData;
  const restaurantId = profileData.restaurantId ||
    window.factorySlug?.(
      typeof profileData.brand?.name === 'object'
        ? (profileData.brand.name.es || profileData.brand.name.en)
        : profileData.brand?.name
    ) || 'demo';

  const brand = normalizeBrand(profileData, restaurantId);
  const { tables: _sidebarTables } = useLiveTablesD(restaurantId);
  const liveCount = _sidebarTables.length;

  const goTo = (screen) => {
    if (screen === 'guest') {
      const url = `MENU%20structure/index.html?table=M-01&restaurant=${encodeURIComponent(restaurantId)}`;
      window.open(url, '_blank');
    }
    else if (screen === 'qr') setTab('qr');
    else if (screen === 'admin') {
      const url = `MENU%20structure/index.html?restaurant=${encodeURIComponent(restaurantId)}&staff=1`;
      window.open(url, '_blank');
    }
    else if (screen === 'brand-edit') { if (onEditBrand) onEditBrand(); }
    else if (screen === 'menu') setTab('menu');
  };

  const p = isMobile ? '24px 16px 90px' : '40px 56px 80px';

  return (
    <>
    <style>{`@keyframes mf-pulse { 0%,100%{opacity:.4} 50%{opacity:.9} } @keyframes mf-spin { to { transform: rotate(360deg) } }`}</style>
    <div style={{ background: 'var(--paper)', height: '100dvh', display: 'grid', gridTemplateColumns: isMobile ? '1fr' : '260px 1fr', overflow: 'hidden' }}>
      {!isMobile && <DashboardSidebar tab={tab} setTab={setTab} brand={brand} user={user} onSignOut={onSignOut} liveCount={liveCount} goTo={goTo} />}
      <main style={{ borderLeft: isMobile ? 'none' : '1px solid var(--line)', height: '100dvh', overflowY: 'auto' }}>
        {isMobile && (
          <DashMobileTopBar brand={brand} user={user} onSignOut={onSignOut} tab={tab} />
        )}
        {tab === 'home'      && <DashHome brand={brand} goTo={goTo} isMobile={isMobile} restaurantId={restaurantId} />}
        {tab === 'menu'      && <DashMenuMgmt brand={brand} isMobile={isMobile} />}
        {tab === 'brand'     && <DashBrandKit brand={brand} isMobile={isMobile} goTo={goTo} />}
        {tab === 'qr'        && <div style={{ padding: p }}><MesasView restaurantId={brand.id} /></div>}
        {tab === 'live'      && <DashLiveOps brand={brand} goTo={goTo} isMobile={isMobile} restaurantId={restaurantId} />}
        {tab === 'comensal'  && <div style={{ padding: p }}><GuestPreviewView restaurantId={restaurantId} /></div>}
        {tab === 'analytics' && <DashAnalytics brand={brand} isMobile={isMobile} restaurantId={restaurantId} />}
        {tab === 'team'      && <DashTeam brand={brand} isMobile={isMobile} />}
        {tab === 'settings'  && <DashSettings brand={brand} isMobile={isMobile} />}
      </main>
      {isMobile && <DashMobileNav tab={tab} setTab={setTab} liveCount={liveCount} />}
    </div>
    </>
  );
}

function DashMobileTopBar({ brand, user, onSignOut, tab }) {
  const label = DASH_MOBILE_TABS.find(t => t.id === tab)?.label || 'Dashboard';
  return (
    <div style={{ padding: '16px 16px 12px', borderBottom: '1px solid var(--line)', display: 'flex', alignItems: 'center', justifyContent: 'space-between', background: 'var(--paper)', position: 'sticky', top: 0, zIndex: 50 }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
        <div style={{ width: 28, height: 28, borderRadius: 6, background: brand.palette?.bg || '#0a0a0a', color: brand.palette?.gold || brand.accent, display: 'grid', placeItems: 'center', fontFamily: 'var(--serif)', fontStyle: 'italic', fontSize: 15, flexShrink: 0 }}>
          {brand.name[0]}
        </div>
        <div>
          <div style={{ fontSize: 13, fontWeight: 600, lineHeight: 1 }}>{brand.name}</div>
          <div style={{ fontSize: 10, color: 'var(--mu)', marginTop: 2 }}>{label}</div>
        </div>
      </div>
      {onSignOut && (
        <button onClick={onSignOut} style={{ fontSize: 12, color: 'var(--mu)', border: '1px solid var(--line-2)', borderRadius: 8, padding: '5px 10px' }}>Salir</button>
      )}
    </div>
  );
}

window.MFDashboard = MFDashboard;
