// Watt Spot - Client side screens
const { useState, useEffect, useMemo, useRef } = React;

// ---------- Formatters ----------
const fmt = (n) => (Number(n) || 0).toFixed(3).replace('.', ',');
const TND = ({ v }) => <span>{fmt(v)} <span style={{ opacity: 0.6, fontSize: '0.78em', fontWeight: 500 }}>TND</span></span>;

// ---------- Stock status (3-state availability, no quantities shown) ----------
const STOCK_STATUS_LABELS = {
  disponible:  { label: 'Disponible',       cls: 'ok' },
  en_arrivage: { label: 'En arrivage',      cls: 'warn' },
  rupture:     { label: 'Rupture de stock', cls: 'danger' },
};
const StockBadge = ({ status }) => {
  const s = STOCK_STATUS_LABELS[status] || STOCK_STATUS_LABELS.disponible;
  return <span className={`ws-stock-badge ws-stock-badge-${s.cls}`}>{s.label}</span>;
};

// ---------- Category-tree helpers (shared with home + admin) ----------
// Recursively flatten a node's leaf slugs so we can count products per L1.
const collectLeafSlugs = (node, into = new Set()) => {
  const children = node.children || [];
  if (children.length === 0) into.add(node.slug);
  else children.forEach(c => collectLeafSlugs(c, into));
  return into;
};

// Pick a header icon for each L1 category (mirrors the Flutter mobile app).
const topIconFor = (slug) => {
  switch (slug) {
    case 'appareillage-electrique-industriel': return 'pkg';
    case 'appareillage-electrique-batiment':   return 'home';
    case 'eclairage':                          return 'bolt';
    case 'domotique':                          return 'grid';
    case 'securite-et-communication':          return 'shield';
    default:                                   return 'tag';
  }
};

// Convert the flat Supabase rows (each with parent_id) into a nested tree
// shaped like the bundled static tree: [{ slug, name, children: [...] }, ...].
const buildTree = (flat) => {
  const byId = {};
  for (const c of flat) {
    if (c.active === false) continue;
    byId[c.id] = { slug: c.id, name: c.nom, _order: c.display_order ?? 0, _parent: c.parent_id || null, children: [] };
  }
  const roots = [];
  for (const id in byId) {
    const node = byId[id];
    const parent = node._parent ? byId[node._parent] : null;
    if (parent) parent.children.push(node);
    else roots.push(node);
  }
  const sortRec = (list) => {
    list.sort((a, b) => a._order - b._order);
    list.forEach(n => sortRec(n.children));
  };
  sortRec(roots);
  // Strip private fields + drop empty `children` arrays for a clean shape.
  const clean = (n) => {
    const c = n.children.length ? { slug: n.slug, name: n.name, children: n.children.map(clean) }
                                : { slug: n.slug, name: n.name };
    return c;
  };
  return roots.map(clean);
};

// Apply admin overrides on top of the bundled scrape tree. Override shape:
//   { [slug]: { nom?: string, desc?: string, display_order?: number,
//                active?: boolean, _deleted?: true,
//                _added?: true, parent_id?: string|null } }
// Adds/renames/hides nodes in place while preserving the tree shape that
// the rest of the front-end already understands.
const applyCategoryOverrides = (tree, overrides) => {
  const o = overrides || {};
  const transform = (node) => {
    const ov = o[node.slug];
    if (ov?._deleted) return null;
    const next = {
      slug: node.slug,
      name: (ov?.nom != null && ov.nom !== '') ? ov.nom : node.name,
      _active: ov?.active !== false,
      _order: ov?.display_order,
    };
    if (node.children?.length) {
      const kids = node.children.map(transform).filter(Boolean);
      if (kids.length) next.children = kids;
    }
    return next;
  };
  let result = tree.map(transform).filter(Boolean);

  // Honour added entries: nodes the admin created from scratch (have _added
  // and a parent_id pointing at an existing node, or null for top-level).
  const findContainer = (nodes, parentId) => {
    for (const n of nodes) {
      if (n.slug === parentId) { n.children = n.children || []; return n.children; }
      if (n.children?.length) {
        const hit = findContainer(n.children, parentId);
        if (hit) return hit;
      }
    }
    return null;
  };
  // A slug already present in the bundled tree was already placed by
  // `transform` above — if an `_added` override reuses that same slug
  // (auto-slugify collision, e.g. two branches both getting a "Divers"
  // leaf), inserting it again would clone that node into a second spot
  // in the tree instead of creating the distinct category the admin
  // intended. Skip it rather than silently duplicating.
  const slugExists = (nodes, slug) => {
    for (const n of nodes) {
      if (n.slug === slug) return true;
      if (n.children?.length && slugExists(n.children, slug)) return true;
    }
    return false;
  };
  for (const slug in o) {
    const ov = o[slug];
    if (!ov?._added || ov._deleted) continue;
    if (slugExists(result, slug)) continue;
    const node = { slug, name: ov.nom || slug, _active: ov.active !== false, _order: ov.display_order };
    if (!ov.parent_id) result.push(node);
    else {
      const bag = findContainer(result, ov.parent_id);
      if (bag) bag.push(node);
    }
  }

  // Drop inactives, sort children by override display_order when provided.
  const finalize = (nodes) => nodes
    .filter(n => n._active !== false)
    .sort((a, b) => {
      if (a._order != null || b._order != null) return (a._order ?? 1e9) - (b._order ?? 1e9);
      return 0;
    })
    .map(n => {
      const out = { slug: n.slug, name: n.name };
      if (n.children?.length) out.children = finalize(n.children);
      return out;
    });
  return finalize(result);
};

// Flatten the tree to a list of [{slug, name, level, parent_slug, path}, ...]
// — used by the admin table renderer.
const flattenCategoryTree = (tree) => {
  const out = [];
  const walk = (nodes, level, parentSlug) => {
    for (const n of nodes) {
      out.push({ slug: n.slug, name: n.name, level, parent_slug: parentSlug, has_children: !!n.children?.length });
      if (n.children?.length) walk(n.children, level + 1, n.slug);
    }
  };
  walk(tree, 1, null);
  return out;
};

// Walk the tree once and return { node, path } for a given slug.
// `path` is the [L1, L2, L3] breadcrumb so the category page can render it.
const findInTree = (tree, slug) => {
  for (const l1 of tree) {
    if (l1.slug === slug) return { node: l1, path: [l1] };
    for (const l2 of (l1.children || [])) {
      if (l2.slug === slug) return { node: l2, path: [l1, l2] };
      for (const l3 of (l2.children || [])) {
        if (l3.slug === slug) return { node: l3, path: [l1, l2, l3] };
      }
    }
  }
  return null;
};

// Hook: returns the live category tree.
// Source = bundled scrape tree (5 L1 / 29 L2 / 131 L3) + admin overrides
// stored in the `cat_overrides` setting. Admin edits the tree from the
// dashboard → setting updates → this hook re-applies → nav, Rayons, and
// CategoryPage all rerender with the new names/order/state.
const useCategoriesTree = () => {
  const base = window.WS_CATEGORIES_TREE || [];
  const [tree, setTree] = useState(base);
  useEffect(() => {
    let alive = true;
    const refresh = () => {
      if (!window.WS_DB) return;
      window.WS_DB.getSetting('cat_overrides').then(overrides => {
        if (!alive) return;
        setTree(applyCategoryOverrides(base, overrides || {}));
      }).catch(() => {});
    };
    refresh();
    window.addEventListener('ws-cats-changed', refresh);
    return () => { alive = false; window.removeEventListener('ws-cats-changed', refresh); };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);
  return tree;
};

// ---------- Thumb: use real image if present, otherwise placeholder ----------
const Thumb = ({ p, size = 240 }) => {
  if (!p) return null;
  if (p.image_url) {
    return <img src={p.image_url} alt={p.nom || ''} loading="lazy"
                style={{ display: 'block', width: '100%', height: '100%', objectFit: 'cover' }}/>;
  }
  return <ProductImg cat={p.cat} id={p.id} size={size}/>;
};

// Favorites are mobile-only now — keep a stub hook so any leftover caller
// renders harmlessly without touching the DB or auth.
const useFavSet = () => ({
  ids: new Set(),
  isFav: () => false,
  toggle: () => {},
  refresh: () => {},
});

// ---------- Logo ----------
// Custom icon + WATT SPOT / ELECTRIC text. Clicking navigates to home.
const LOGO_ICON = 'assets/Design sans titre.png';
const Logo = ({ size = 40, onNav, showText = true }) => (
  <a
    className="ws-logo"
    href="#/"
    onClick={(e) => { e.preventDefault(); (onNav || ((r)=>{ try{window.dispatchEvent(new CustomEvent('ws-nav',{detail:r}));}catch(err){} }))('home'); }}
    style={{ display: 'inline-flex', alignItems: 'center', gap: 10, textDecoration: 'none', color: 'inherit', cursor: 'pointer' }}
    title="Accueil Watt Spot"
  >
    <img
      src={LOGO_ICON}
      alt=""
      style={{ height: size, width: 'auto', display: 'block', objectFit: 'contain', flexShrink: 0 }}
      onError={(e) => {
        // If custom icon fails, fall back to the inline SVG bolt
        const fallback = document.createElement('span');
        fallback.innerHTML = '<svg width="' + size + '" height="' + size + '" viewBox="0 0 100 100"><path d="M52 8 L78 8 L60 38 L82 38 L30 92 L44 56 L22 56 Z" fill="var(--accent)"/></svg>';
        e.currentTarget.replaceWith(fallback.firstChild);
      }}
    />
    {showText && (
      <div style={{ lineHeight: 1 }}>
        <div style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 18, letterSpacing: '0.02em', color: 'var(--accent)' }}>WATT SPOT</div>
        <div style={{ fontSize: 9, letterSpacing: '0.35em', color: 'var(--navy)', fontWeight: 600, marginTop: 2 }}>ELECTRIC</div>
      </div>
    )}
  </a>
);

// FavHeaderButton retired (no favorites on the public web).
const FavHeaderButton = () => null;

// ---------- Search autocomplete ----------
// Lightweight debounced suggestion dropdown shown under the header search.
// Queries WS_DB.listProducts with the typed text (matches nom, ref, marque).
const SearchAutocomplete = ({ query, onNav, onClose }) => {
  const [items, setItems] = useState([]);
  const [loading, setLoading] = useState(false);
  const [highlight, setHighlight] = useState(0);
  const q = (query || '').trim();

  useEffect(() => {
    if (q.length < 2) { setItems([]); return; }
    setLoading(true);
    const t = setTimeout(async () => {
      try {
        const results = await window.WS_DB.listProducts({ search: q, activeOnly: true, platform: 'web' });
        setItems((results || []).slice(0, 8));
        setHighlight(0);
      } catch (e) {
        setItems([]);
      } finally { setLoading(false); }
    }, 150);
    return () => clearTimeout(t);
  }, [q]);

  if (q.length < 2) return null;

  const go = (p) => { onNav('product', { id: p.id }); onClose?.(); };
  const seeAll = () => { onNav('search', { q }); onClose?.(); };

  return (
    <div className="ws-search-dropdown" onMouseDown={e => e.preventDefault()}>
      {loading && items.length === 0 && (
        <div className="ws-search-empty">Recherche en cours…</div>
      )}
      {!loading && items.length === 0 && (
        <div className="ws-search-empty">
          <Icon name="search" size={18} style={{ opacity: 0.5 }}/>
          <div>Aucun résultat pour « {q} »</div>
        </div>
      )}
      {items.length > 0 && (
        <>
          <div className="ws-search-results">
            {items.map((p, i) => (
              <div
                key={p.id}
                className={`ws-search-item ${i === highlight ? 'active' : ''}`}
                onMouseEnter={() => setHighlight(i)}
                onClick={() => go(p)}
              >
                <div className="ws-search-thumb"><Thumb p={p}/></div>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div className="ws-search-nom">{p.nom}</div>
                  <div className="ws-search-meta">{p.marque} · Réf {p.ref}</div>
                </div>
              </div>
            ))}
          </div>
          <div className="ws-search-footer" onClick={seeAll}>
            Voir tous les résultats pour « {q} » <Icon name="chevR" size={12}/>
          </div>
        </>
      )}
    </div>
  );
};

// ---------- Header (client) ----------
// Public read-only catalog: no cart, no account, no favorites — only search,
// browse, and a link to the brands page. Pro clients place orders in the
// Watt Spot mobile app.
const ClientHeader = ({ onNav, route, onSearch, query }) => {
  const [openSugg, setOpenSugg] = useState(false);
  const [drawerOpen, setDrawerOpen] = useState(false);
  const submitSearch = (e) => {
    if (e) e.preventDefault();
    const q = (query || '').trim();
    if (q.length >= 2) { onNav('search', { q }); setOpenSugg(false); }
  };
  const navAndClose = (r, p) => { setDrawerOpen(false); onNav(r, p); };
  return (
    <header className="ws-header">
      <div className="ws-header-main">
        <button
          className="ws-burger"
          onClick={() => setDrawerOpen(true)}
          aria-label="Ouvrir le menu"
        >
          <Icon name="menu" size={22}/>
        </button>
        <Logo onNav={onNav}/>
        <div className="ws-header-searchwrap">
          <form className="ws-search" onSubmit={submitSearch}>
            <Icon name="search" size={18} style={{ color: 'var(--muted)' }}/>
            <input
              placeholder="Rechercher par nom, référence, marque…"
              value={query}
              onChange={(e) => { onSearch(e.target.value); setOpenSugg(true); }}
              onFocus={() => setOpenSugg(true)}
              onBlur={() => setTimeout(() => setOpenSugg(false), 150)}
              autoComplete="off"
            />
          </form>
          {openSugg && query && (
            <SearchAutocomplete query={query} onNav={onNav} onClose={()=>setOpenSugg(false)}/>
          )}
        </div>
        <div className="ws-header-info">
          <a href="tel:+21693664935" title="Appeler Watt Spot">
            <Icon name="phone" size={12}/> 93 664 935
          </a>
          <span className="ws-header-info-sep">·</span>
          <a href="https://maps.app.goo.gl/3NDqJyKbJcK1aqUt7" target="_blank" rel="noopener noreferrer" title="Voir sur Google Maps">
            <Icon name="map" size={12}/> 44 Av. Habib Bougatfa, La Manouba
          </a>
        </div>
        <div className="ws-header-actions">
          <button className="ws-icon-btn" onClick={() => onNav('brands')} title="Nos marques">
            <Icon name="tag" size={20}/>
            <span className="ws-ico-label">Nos marques</span>
          </button>
        </div>
      </div>
      <NavBar onNav={onNav} route={route}/>
      <NavDrawer open={drawerOpen} onClose={() => setDrawerOpen(false)} onNav={navAndClose}/>
    </header>
  );
};

// ---------- Mobile slide-in nav drawer ----------
// Burger menu replacement for the horizontal `.ws-nav` row on small screens.
// Accordion: tap an L1 with children to expand its L2s; tap an L2 or a leaf
// to navigate. Locks body scroll while open.
const NavDrawer = ({ open, onClose, onNav }) => {
  const tree = useCategoriesTree();
  const [expanded, setExpanded] = useState(null);

  useEffect(() => {
    if (open) {
      document.body.style.overflow = 'hidden';
      const onKey = (e) => { if (e.key === 'Escape') onClose(); };
      window.addEventListener('keydown', onKey);
      return () => {
        document.body.style.overflow = '';
        window.removeEventListener('keydown', onKey);
      };
    }
  }, [open]);

  const toggle = (slug) => setExpanded(s => s === slug ? null : slug);
  const go = (slug) => { onNav('cat', { cat: slug }); setExpanded(null); };

  return (
    <>
      <div className={`ws-drawer-overlay ${open ? 'open' : ''}`} onClick={onClose}/>
      <aside className={`ws-drawer ${open ? 'open' : ''}`} aria-hidden={!open}>
        <div className="ws-drawer-head">
          <Logo onNav={() => { onNav('home'); }}/>
          <button className="ws-drawer-close" onClick={onClose} aria-label="Fermer">
            <Icon name="close" size={20}/>
          </button>
        </div>
        <nav className="ws-drawer-nav">
          <button className="ws-drawer-item ws-drawer-l1" onClick={() => onNav('home')}>
            <Icon name="grid" size={16}/> <span>Accueil</span>
          </button>
          {tree.map(top => {
            const hasChildren = (top.children || []).length > 0;
            const isOpen = expanded === top.slug;
            return (
              <div key={top.slug} className={`ws-drawer-group ${isOpen ? 'open' : ''}`}>
                <button
                  className="ws-drawer-item ws-drawer-l1"
                  onClick={() => hasChildren ? toggle(top.slug) : go(top.slug)}
                >
                  <Icon name={topIconFor(top.slug)} size={16}/>
                  <span>{top.name}</span>
                  {hasChildren && (
                    <Icon name={isOpen ? 'chevU' : 'chevD'} size={14} className="ws-drawer-chev"/>
                  )}
                </button>
                {hasChildren && (
                  <div className="ws-drawer-sub">
                    <button
                      className="ws-drawer-item ws-drawer-l2 ws-drawer-all"
                      onClick={() => go(top.slug)}
                    >
                      Tout {top.name}
                      <Icon name="chevR" size={12}/>
                    </button>
                    {(top.children || []).map(l2 => (
                      <button
                        key={l2.slug}
                        className="ws-drawer-item ws-drawer-l2"
                        onClick={() => go(l2.slug)}
                      >
                        {l2.name}
                      </button>
                    ))}
                  </div>
                )}
              </div>
            );
          })}
          <button className="ws-drawer-item ws-drawer-l1" onClick={() => onNav('brands')}>
            <Icon name="tag" size={16}/> <span>Nos marques</span>
          </button>
        </nav>

        <div className="ws-drawer-foot">
          <a className="ws-drawer-contact" href="tel:+21693664935">
            <Icon name="phone" size={14}/> 93 664 935
          </a>
          <a className="ws-drawer-contact" href="https://maps.app.goo.gl/3NDqJyKbJcK1aqUt7" target="_blank" rel="noopener noreferrer">
            <Icon name="map" size={14}/> Showroom Manouba
          </a>
        </div>
      </aside>
    </>
  );
};

// Top nav (extracted so it can subscribe to the live category tree hook).
const NavBar = ({ onNav, route }) => {
  const tree = useCategoriesTree();
  return (
    <nav className="ws-nav">
      <a href="#/" onClick={(e)=>{e.preventDefault(); onNav('home');}} className={route==='home'?'active':''}>
        <Icon name="grid" size={14}/> Accueil
      </a>
      {tree.map(top => (
        <TopCategoryDropdown key={top.slug} top={top} onNav={onNav} route={route}/>
      ))}
    </nav>
  );
};

// ---------- Per-L1 dropdown (one nav item per top category) ----------
// Each L1 sits inline in the nav bar. Hover (or click) shows a 2-column
// flyout: L2 list on the left, L3 children of the hovered L2 on the right.
// Tapping any node navigates to the category page for that slug.
const TopCategoryDropdown = ({ top, onNav, route }) => {
  const [open, setOpen] = useState(false);
  const [openL2, setOpenL2] = useState(null);
  const wrapRef = useRef(null);

  useEffect(() => {
    const close = (e) => { if (wrapRef.current && !wrapRef.current.contains(e.target)) { setOpen(false); setOpenL2(null); } };
    document.addEventListener('mousedown', close);
    return () => document.removeEventListener('mousedown', close);
  }, []);

  const go = (slug) => { setOpen(false); setOpenL2(null); onNav('cat', { cat: slug }); };
  const l2 = (top.children || []).find(c => c.slug === openL2);
  const hasChildren = (top.children || []).length > 0;

  return (
    <div className="ws-megamenu-wrap"
         ref={wrapRef}
         onMouseEnter={() => hasChildren && setOpen(true)}
         onMouseLeave={() => { setOpen(false); setOpenL2(null); }}>
      <a href="#"
         className={`ws-megamenu-trigger ${open ? 'active' : ''}`}
         onClick={(e) => {
           e.preventDefault();
           // On mobile the megamenu is CSS-hidden — tap goes straight to the L1.
           const isMobile = typeof window !== 'undefined' && window.innerWidth <= 768;
           if (!hasChildren || isMobile) go(top.slug);
           else setOpen(o => !o);
         }}>
        {top.name} {hasChildren && <Icon name="chevD" size={12}/>}
      </a>
      {open && hasChildren && (
        <div className="ws-megamenu">
          {/* L2 column */}
          <div className="ws-mm-col ws-mm-col-2">
            {top.children.map(c => (
              <button key={c.slug}
                className={`ws-mm-item ${openL2 === c.slug ? 'active' : ''}`}
                onMouseEnter={() => setOpenL2(c.slug)}
                onClick={() => go(c.slug)}>
                <span>{c.name}</span>
                {c.children?.length > 0 && <Icon name="chevR" size={12}/>}
              </button>
            ))}
          </div>
          {/* L3 column */}
          {l2?.children?.length > 0 && (
            <div className="ws-mm-col ws-mm-col-3">
              {l2.children.map(c => (
                <button key={c.slug} className="ws-mm-item ws-mm-leaf" onClick={() => go(c.slug)}>
                  <span>{c.name}</span>
                </button>
              ))}
            </div>
          )}
        </div>
      )}
    </div>
  );
};

// ---------- Home ----------
const HomePage = ({ onNav }) => {
  // Start empty — no demo seed. After a Supabase wipe the home page must
  // show 0 products, not the bundled 76-product fallback.
  const [products, setProducts] = useState([]);
  const [cats, setCats] = useState([]);
  const [heroId, setHeroId] = useState(null);
  useEffect(() => {
    let alive = true;
    Promise.all([
      window.WS_DB.listProducts({ platform: 'web' }),
      window.WS_DB.listCategories(),
      window.WS_DB.getSetting('hero_product_id').catch(() => null),
    ]).then(([p, c, hero]) => {
      if (!alive) return;
      setProducts(p || []);
      setCats(c || []);
      if (hero) setHeroId(hero);
    }).catch(() => {});
    return () => { alive = false; };
  }, []);
  const promos   = products.filter(p => p.tag === 'Promo');
  const best     = products.filter(p => p.tag === 'Best-seller');
  const nouveau  = products.filter(p => p.tag === 'Nouveau');
  // Prefer the admin-selected product; fall back to first promo/best-seller
  const featuredPromo = (heroId && products.find(p => p.id === heroId))
                      || promos[0] || best[0] || products[0];
  // hero stats — computed live from catalog
  const totalProducts = products.length;
  const inStockCount  = products.filter(p => p.stockStatus !== 'rupture').length;
  const avgRating     = products.length
    ? (products.filter(p => p.note).reduce((a, p) => a + p.note, 0) / Math.max(1, products.filter(p => p.note).length)).toFixed(1)
    : '—';
  return (
    <div className="ws-home">
      {/* Hero */}
      <section className="ws-hero">
        <div className="ws-hero-bg">
          <svg viewBox="0 0 800 500" preserveAspectRatio="xMidYMid slice" style={{ width: '100%', height: '100%' }}>
            <defs>
              <pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
                <path d="M 40 0 L 0 0 0 40" fill="none" stroke="rgba(255,255,255,0.05)" strokeWidth="1"/>
              </pattern>
            </defs>
            <rect width="800" height="500" fill="url(#grid)"/>
            {/* large bolt decoration */}
            <g transform="translate(600, 100)" opacity="0.12">
              <path d="M60 0 L120 0 L80 80 L140 80 L40 240 L70 140 L0 140 Z" fill="var(--accent)"/>
            </g>
          </svg>
        </div>
        <div className="ws-hero-content">
          <div className="ws-hero-eyebrow">
            <Icon name="bolt" size={14}/> Électricité · Éclairage · Domotique
          </div>
          <h1>Tout pour électrifier<br/>votre espace.</h1>
          <p>{totalProducts} références en stock. Livraison 24h sur Tunis. Conseils techniques par des pros.</p>
          <div className="ws-hero-cta">
            <button className="ws-btn ws-btn-primary" onClick={() => onNav('cat', { cat: cats[0]?.id || 'leds' })}>
              Explorer le catalogue <Icon name="chevR" size={16}/>
            </button>
            <button className="ws-btn ws-btn-ghost" onClick={() => onNav('brands')}>
              Voir les marques
            </button>
          </div>
          <div className="ws-hero-stats">
            <div><strong>{totalProducts}+</strong><span>Produits</span></div>
            <div><strong>24h</strong><span>Livraison</span></div>
            <div><strong>{avgRating}/5</strong><span>Note clients</span></div>
            <div><strong>{inStockCount}</strong><span>En stock</span></div>
          </div>
        </div>
        <div className="ws-hero-visual">
          {featuredPromo && (
            <div className="ws-hero-card" onClick={()=>onNav('product', { id: featuredPromo.id })} style={{ cursor: 'pointer' }}>
              <div className="ws-hero-card-tag">{featuredPromo.tag === 'Promo' ? 'Coup de projecteur' : featuredPromo.tag || 'À découvrir'}</div>
              <div style={{ width: 180, height: 180, margin: '0 auto' }}><Thumb p={featuredPromo}/></div>
              <div className="ws-hero-card-body">
                <div style={{ fontSize: 12, color: 'var(--muted)' }}>{featuredPromo.marque} · {featuredPromo.ref}</div>
                <div style={{ fontWeight: 600, margin: '4px 0 8px' }}>{featuredPromo.nom}</div>
              </div>
            </div>
          )}
        </div>
      </section>

      {/* Categories grid — driven by the live tree (matches top nav) */}
      <RayonsSection products={products} onNav={onNav}/>

      {/* Tagged-product rows — only render if the admin has tagged any */}
      {promos.length > 0 && (
        <section className="ws-section">
          <div className="ws-section-head">
            <div>
              <h2>Promos en cours</h2>
            </div>
          </div>
          <div className="ws-prod-grid">
            {promos.slice(0, 8).map(p => <ProductCard key={p.id} p={p} onOpen={() => onNav("product", { id: p.id })}/>)}
          </div>
        </section>
      )}

      {best.length > 0 && (
        <section className="ws-section">
          <div className="ws-section-head">
            <h2>Best-sellers</h2>
          </div>
          <div className="ws-prod-grid">
            {best.slice(0, 8).map(p => <ProductCard key={p.id} p={p} onOpen={() => onNav("product", { id: p.id })}/>)}
          </div>
        </section>
      )}

      {nouveau.length > 0 && (
        <section className="ws-section">
          <div className="ws-section-head">
            <h2>Nouveautés</h2>
          </div>
          <div className="ws-prod-grid">
            {nouveau.slice(0, 8).map(p => <ProductCard key={p.id} p={p} onOpen={() => onNav("product", { id: p.id })}/>)}
          </div>
        </section>
      )}

      {/* Showcase by category — admin picks which L2 categories to feature
          (setting "home_showcases"), each shows its product preview + a link
          to the full category page. */}
      <CategoryShowcases products={products} onNav={onNav} max={4} perRow={4}/>

      {/* Trust strip */}
      <section className="ws-trust">
        <div><Icon name="bolt" size={24}/><div><strong>Catalogue complet</strong><span>Toutes nos références</span></div></div>
        <div><Icon name="shield" size={24}/><div><strong>Garantie 2 ans</strong><span>Sur toutes les marques</span></div></div>
        <div><Icon name="map" size={24}/><div><strong>Showroom Manouba</strong><span>44 Av. Habib Bougatfa</span></div></div>
        <div><Icon name="phone" size={24}/><div><strong>93 664 935</strong><span>Lun–Sam · Dim matin</span></div></div>
      </section>
    </div>
  );
};

// ---------- Product Card ----------
// Public catalog card: thumbnail, brand, name, rating. No price, no cart,
// no favorites — those live in the Pro mobile app.
const ProductCard = ({ p, onOpen }) => {
  const cat = (window.CATEGORIES || []).find(c => c.id === p.cat);
  return (
    <article className="ws-prod-card" onClick={onOpen}>
      <div className="ws-prod-thumb">
        <Thumb p={p}/>
        {p.tag && <span className={`ws-chip ws-chip-${p.tag.toLowerCase().replace(/[^a-z]/g,'')}`}>{p.tag}</span>}
      </div>
      <div className="ws-prod-body">
        <div className="ws-prod-meta">{p.marque} · {cat?.nom}</div>
        <h3 className="ws-prod-nom">{p.nom}</h3>
        <div className="ws-prod-note">
          {p.note ? (
            <>
              <Icon name="star" size={12} style={{ color: 'var(--accent)', fill: 'var(--accent)' }}/>
              <span>{p.note}</span><span className="ws-muted">({p.avis})</span>
            </>
          ) : (
            <span className="ws-muted" style={{ fontSize: 12 }}>Réf {p.ref}</span>
          )}
        </div>
        <StockBadge status={p.stockStatus}/>
      </div>
    </article>
  );
};

// ---------- Category page ----------
const CategoryPage = ({ cat, onNav, initialFilter }) => {
  const tree = useCategoriesTree();
  const [all, setAll] = useState([]);
  const [sort, setSort] = useState('pop');
  const [view, setView] = useState('grid');
  const [brands, setBrands] = useState(new Set());
  const [onlyStock, setOnlyStock] = useState(false);

  // Resolve the category + its full path from the tree (single source of truth).
  const found = findInTree(tree, cat);
  const node = found?.node || { slug: cat, name: cat };
  const path = found?.path || [{ slug: cat, name: cat }];
  const isLeaf = !(node.children?.length);

  // For non-leaf nodes (L1/L2 with sub-categories) we aggregate products from
  // every leaf under it. Otherwise we just query the leaf's slug directly.
  const slugsToQuery = isLeaf
    ? [cat]
    : Array.from(collectLeafSlugs(node));

  useEffect(() => {
    let alive = true;
    if (!slugsToQuery.length) { setAll([]); return; }
    // Fire one request per slug; for top-level categories with many leaves this
    // is still a small handful of round-trips and avoids a server-side `IN`.
    Promise.all(slugsToQuery.map(s => window.WS_DB.listProducts({ category: s, platform: 'web' }).catch(() => [])))
      .then(lists => {
        if (!alive) return;
        const seen = new Set(); const merged = [];
        for (const list of lists) for (const p of (list || [])) {
          if (seen.has(p.id)) continue;
          seen.add(p.id); merged.push(p);
        }
        setAll(merged);
      });
    return () => { alive = false; };
    // slugsToQuery is derived from cat — re-run when cat changes
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [cat]);

  const availableBrands = [...new Set(all.map(p => p.marque).filter(Boolean))];

  let items = all.filter(p => {
    if (brands.size && !brands.has(p.marque)) return false;
    if (onlyStock && p.stockStatus === 'rupture') return false;
    return true;
  });
  if (sort === 'note') items = [...items].sort((a,b)=>(b.note||0)-(a.note||0));

  const toggleBrand = (b) => {
    const s = new Set(brands);
    s.has(b) ? s.delete(b) : s.add(b);
    setBrands(s);
  };

  // Sub-categories of the current node (chips above the grid for drilling down).
  const subs = node.children || [];
  // Siblings: alternate sub-categories at the same level (helpful at L2/L3).
  const siblings = path.length >= 2
    ? (path[path.length - 2].children || []).filter(c => c.slug !== node.slug)
    : [];

  return (
    <div className="ws-cat-page">
      <div className="ws-breadcrumb">
        <a onClick={()=>onNav('home')}>Accueil</a>
        {path.map((n, i) => (
          <React.Fragment key={n.slug}>
            <Icon name="chevR" size={12}/>
            {i === path.length - 1
              ? <span>{n.name}</span>
              : <a onClick={()=>onNav('cat', { cat: n.slug })}>{n.name}</a>}
          </React.Fragment>
        ))}
      </div>

      <div className="ws-cat-head">
        <div>
          <h1>{node.name}</h1>
          <p className="ws-muted">
            {!isLeaf && `${subs.length} sous-catégorie${subs.length > 1 ? 's' : ''} · `}
            {all.length} produit{all.length === 1 ? '' : 's'}
          </p>
        </div>
        {siblings.length > 0 && (
          <div className="ws-cat-badges">
            {siblings.slice(0, 6).map(c => (
              <button key={c.slug} className="ws-chip-nav" onClick={() => onNav('cat', { cat: c.slug })}>
                {c.name}
              </button>
            ))}
          </div>
        )}
      </div>

      {/* If we're on a parent (L1/L2 with children), drill-down chips first. */}
      {subs.length > 0 && (
        <div className="ws-subcat-row">
          {subs.map(s => (
            <button key={s.slug} className="ws-subcat-chip" onClick={() => onNav('cat', { cat: s.slug })}>
              {s.name}
              <Icon name="chevR" size={12}/>
            </button>
          ))}
        </div>
      )}

      <div className="ws-cat-body">
        {/* Filters */}
        <aside className="ws-filters">
          <div className="ws-filter-head">
            <h3><Icon name="filter" size={16}/> Filtres</h3>
            <button className="ws-link-sm" onClick={()=>{setBrands(new Set()); setOnlyStock(false);}}>Réinitialiser</button>
          </div>

          <div className="ws-filter-block">
            <div className="ws-filter-label">Marques</div>
            {availableBrands.length === 0
              ? <div className="ws-muted" style={{ fontSize: 12 }}>—</div>
              : availableBrands.map(b => (
                <label key={b} className="ws-check">
                  <input type="checkbox" checked={brands.has(b)} onChange={()=>toggleBrand(b)}/>
                  <span>{b}</span>
                  <span className="ws-muted ws-count">{all.filter(p=>p.marque===b).length}</span>
                </label>
              ))
            }
          </div>

          <div className="ws-filter-block">
            <div className="ws-filter-label">Disponibilité</div>
            <label className="ws-check">
              <input type="checkbox" checked={onlyStock} onChange={()=>setOnlyStock(!onlyStock)}/>
              <span>En stock uniquement</span>
            </label>
          </div>

          <div className="ws-filter-block">
            <div className="ws-filter-label">Note minimum</div>
            <div className="ws-star-filter">
              {[5,4,3].map(n => (
                <button key={n} className="ws-star-row">
                  {[1,2,3,4,5].map(i => (
                    <Icon key={i} name="star" size={14} style={{ color: i<=n?'var(--accent)':'var(--border)', fill: i<=n?'var(--accent)':'none' }}/>
                  ))}
                  <span className="ws-muted">& plus</span>
                </button>
              ))}
            </div>
          </div>
        </aside>

        {/* Grid */}
        <div className="ws-cat-main">
          <div className="ws-cat-toolbar">
            <div>
              <strong>{items.length}</strong> produits trouvés
              {brands.size > 0 && <span className="ws-muted"> · {[...brands].join(', ')}</span>}
            </div>
            <div className="ws-toolbar-actions">
              <select value={sort} onChange={(e)=>setSort(e.target.value)} className="ws-select">
                <option value="pop">Popularité</option>
                <option value="note">Mieux notés</option>
              </select>
              <div className="ws-view-toggle">
                <button onClick={()=>setView('grid')} className={view==='grid'?'active':''}><Icon name="grid" size={14}/></button>
                <button onClick={()=>setView('list')} className={view==='list'?'active':''}><Icon name="list" size={14}/></button>
              </div>
            </div>
          </div>

          {items.length === 0 ? (
            <div className="ws-empty">
              <Icon name="search" size={48} style={{ color: 'var(--muted)', opacity: 0.5 }}/>
              <h3>Aucun produit ne correspond</h3>
              <p>Ajustez vos filtres pour élargir la recherche.</p>
            </div>
          ) : view === 'grid' ? (
            <div className="ws-prod-grid">
              {items.map(p => <ProductCard key={p.id} p={p} onOpen={() => onNav('product', { id: p.id })}/>)}
            </div>
          ) : (
            <div className="ws-prod-list">
              {items.map(p => <ProductRow key={p.id} p={p} onOpen={() => onNav('product', { id: p.id })}/>)}
            </div>
          )}
        </div>
      </div>
    </div>
  );
};

const ProductRow = ({ p, onOpen }) => {
  const cat = (window.CATEGORIES || []).find(c => c.id === p.cat);
  return (
    <div className="ws-prod-row" onClick={onOpen}>
      <div className="ws-prod-row-thumb"><Thumb p={p}/></div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div className="ws-prod-meta">{p.marque} · {cat?.nom} · Réf {p.ref}</div>
        <h3 className="ws-prod-nom">{p.nom}</h3>
        {p.note ? (
          <div className="ws-prod-note">
            <Icon name="star" size={12} style={{ color: 'var(--accent)', fill: 'var(--accent)' }}/>
            <span>{p.note}</span><span className="ws-muted">({p.avis} avis)</span>
          </div>
        ) : null}
      </div>
      <div style={{ textAlign: 'right' }}>
        <Icon name="chevR" size={18} style={{ color: 'var(--muted)' }}/>
      </div>
    </div>
  );
};

// ---------- Search results page ----------
const SearchPage = ({ q, onNav }) => {
  const [results, setResults] = useState([]);
  const [loading, setLoading] = useState(true);
  const [sort, setSort] = useState('pop');

  useEffect(() => {
    let alive = true;
    setLoading(true);
    window.WS_DB.listProducts({ search: q, platform: 'web' })
      .then(p => { if (alive) setResults(p || []); })
      .catch(() => {})
      .finally(() => { if (alive) setLoading(false); });
    return () => { alive = false; };
  }, [q]);

  let items = results;
  if (sort === 'note') items = [...items].sort((a,b)=>(b.note||0)-(a.note||0));
  if (sort === 'nom')  items = [...items].sort((a,b)=>(a.nom||'').localeCompare(b.nom||''));

  return (
    <div className="ws-cat-page">
      <div className="ws-breadcrumb">
        <a onClick={()=>onNav('home')}>Accueil</a>
        <Icon name="chevR" size={12}/>
        <span>Recherche</span>
      </div>
      <div className="ws-cat-head">
        <div>
          <h1>Résultats pour « {q} »</h1>
          <p className="ws-muted">{loading ? 'Recherche en cours…' : `${items.length} produit${items.length === 1 ? '' : 's'} trouvé${items.length === 1 ? '' : 's'}`}</p>
        </div>
        {items.length > 0 && (
          <select value={sort} onChange={e=>setSort(e.target.value)} className="ws-select">
            <option value="pop">Pertinence</option>
            <option value="nom">Ordre alphabétique</option>
            <option value="note">Mieux notés</option>
          </select>
        )}
      </div>
      {!loading && items.length === 0 && (
        <div className="ws-empty">
          <Icon name="search" size={48} style={{ color: 'var(--muted)', opacity: 0.5 }}/>
          <h3>Aucun produit trouvé</h3>
          <p>Essayez une orthographe différente ou parcourez <a onClick={()=>onNav('home')} className="ws-link">tous les rayons</a>.</p>
        </div>
      )}
      {items.length > 0 && (
        <div className="ws-prod-grid" style={{ marginTop: 24 }}>
          {items.map(p => <ProductCard key={p.id} p={p} onOpen={() => onNav('product', { id: p.id })}/>)}
        </div>
      )}
    </div>
  );
};

// FavoritesPage was removed: favorites belong to the mobile Pro app only.
// Kept as a stub so any legacy route still renders harmlessly.
const FavoritesPage = ({ onNav }) => {
  useEffect(() => { onNav && onNav('home'); }, []);
  return null;
};

// ---------- Category product showcases (home section) ----------
// Renders product previews grouped by L2 category. Categories shown are
// admin-managed via the `home_showcases` setting (list of L2 slugs, in order).
// If the admin hasn't picked any, falls back to auto-picking the top-N
// L2 categories by product count so the home is never empty.
const CategoryShowcases = ({ products, onNav, max = 4, perRow = 4 }) => {
  const tree = useCategoriesTree();
  const [featured, setFeatured] = useState(null);  // null = not loaded

  useEffect(() => {
    let alive = true;
    const load = () => window.WS_DB.getSetting('home_showcases')
      .then(v => { if (alive) setFeatured(Array.isArray(v) ? v : []); })
      .catch(() => { if (alive) setFeatured([]); });
    load();
    const h = () => load();
    window.addEventListener('ws-showcases-changed', h);
    return () => { alive = false; window.removeEventListener('ws-showcases-changed', h); };
  }, []);

  if (!products || !products.length || featured === null) return null;

  // Index every L2 with its leaf products.
  const byId = {};
  for (const l1 of tree) {
    for (const l2 of (l1.children || [])) {
      const leaves = collectLeafSlugs(l2);
      const items = products.filter(p => leaves.has(p.cat));
      byId[l2.slug] = { slug: l2.slug, name: l2.name, parentName: l1.name, products: items };
    }
  }

  let showcases;
  if (featured.length) {
    // Admin's curated list. Drop slugs that don't exist or have no products.
    showcases = featured.map(id => byId[id]).filter(sc => sc && sc.products.length > 0);
  } else {
    // Fallback: top-N L2 by product count.
    showcases = Object.values(byId)
      .filter(sc => sc.products.length >= 2)
      .sort((a, b) => b.products.length - a.products.length)
      .slice(0, max);
  }
  if (!showcases.length) return null;

  return (
    <>
      {showcases.map(sc => (
        <section key={sc.slug} className="ws-section">
          <div className="ws-section-head">
            <div>
              <h2>{sc.name}</h2>
              <div className="ws-muted" style={{ fontSize: 13, marginTop: 2 }}>{sc.parentName}</div>
            </div>
            <a className="ws-link" style={{ cursor: 'pointer' }} onClick={() => onNav('cat', { cat: sc.slug })}>
              Voir tout ({sc.products.length}) <Icon name="chevR" size={14}/>
            </a>
          </div>
          <div className="ws-prod-grid">
            {sc.products.slice(0, perRow).map(p => (
              <ProductCard key={p.id} p={p} onOpen={() => onNav('product', { id: p.id })}/>
            ))}
          </div>
        </section>
      ))}
    </>
  );
};

// ---------- Rayons grid (home section) ----------
// Shows the L2 sub-categories curated by the admin via the
// `home_rayons` setting. Default = first 8 L2s across all L1s in tree order.
// Admin manages the list from "Catégories → Rayons en vedette".
const RayonsSection = ({ products, onNav }) => {
  const tree = useCategoriesTree();
  const [featured, setFeatured] = useState(null);   // null = not loaded yet

  useEffect(() => {
    let alive = true;
    const load = () => window.WS_DB.getSetting('home_rayons')
      .then(v => { if (alive) setFeatured(Array.isArray(v) ? v : []); })
      .catch(() => { if (alive) setFeatured([]); });
    load();
    const h = () => load();
    window.addEventListener('ws-rayons-changed', h);
    return () => { alive = false; window.removeEventListener('ws-rayons-changed', h); };
  }, []);

  // Flatten all L2s across L1s with their L1 parent name (for context).
  const allL2 = [];
  for (const l1 of tree) {
    for (const l2 of (l1.children || [])) {
      allL2.push({ ...l2, parentName: l1.name, parentSlug: l1.slug });
    }
  }
  const byId = Object.fromEntries(allL2.map(c => [c.slug, c]));

  // Apply the admin's pick; fall back to first 8 if nothing curated yet.
  let rayons;
  if (featured && featured.length) {
    rayons = featured.map(id => byId[id]).filter(Boolean);
  } else {
    rayons = allL2.slice(0, 8);
  }

  if (!rayons.length) return null;

  return (
    <section className="ws-section">
      <div className="ws-section-head">
        <h2>Rayons</h2>
        <span className="ws-muted">{rayons.length} rayon{rayons.length > 1 ? 's' : ''} en vedette</span>
      </div>
      <div className="ws-cat-grid">
        {rayons.map(c => {
          const subCount = (c.children || []).length;
          const leafSlugs = collectLeafSlugs(c);
          const productCount = products.filter(p => leafSlugs.has(p.cat)).length;
          return (
            <a key={c.slug} className="ws-cat-card"
               onClick={(e) => { e.preventDefault(); onNav('cat', { cat: c.slug }); }}
               href={`#/cat/${c.slug}`}>
              <div className="ws-cat-icon"><Icon name={topIconFor(c.parentSlug)} size={28}/></div>
              <div>
                <div className="ws-cat-nom">{c.name}</div>
                <div className="ws-cat-count">
                  {c.parentName}
                  {subCount > 0 && ` · ${subCount} sous-catégorie${subCount > 1 ? 's' : ''}`}
                  {productCount > 0 && ` · ${productCount} produits`}
                </div>
              </div>
              <Icon name="chevR" size={16} className="ws-cat-arrow"/>
            </a>
          );
        })}
      </div>
    </section>
  );
};

// ---------- Brands page (Nos marques) ----------
// Brands list = derived from products' `marque` field, enriched with logos
// and descriptions stored in the `brand_meta` setting (managed by admin).
// Click a brand → opens its dedicated product page.
const BrandsPage = ({ onNav }) => {
  const [products, setProducts] = useState([]);
  const [meta, setMeta] = useState({});

  useEffect(() => {
    let alive = true;
    const refresh = () => Promise.all([
      window.WS_DB.listProducts({ activeOnly: true, platform: 'web' }).catch(() => []),
      window.WS_DB.getSetting('brand_meta').catch(() => ({})),
    ]).then(([p, m]) => {
      if (!alive) return;
      setProducts(p || []);
      setMeta(m && typeof m === 'object' ? m : {});
    });
    refresh();
    window.addEventListener('ws-brands-changed', refresh);
    return () => { alive = false; window.removeEventListener('ws-brands-changed', refresh); };
  }, []);

  // Aggregate brands; merge in any meta-only entries (admin can pre-create
  // a brand even before products land).
  const byBrand = {};
  for (const p of products) {
    const b = (p.marque || '').trim();
    if (!b) continue;
    if (!byBrand[b]) byBrand[b] = { name: b, count: 0 };
    byBrand[b].count++;
  }
  for (const name of Object.keys(meta || {})) {
    if (!byBrand[name]) byBrand[name] = { name, count: 0 };
  }
  const brands = Object.values(byBrand).sort((a, b) => b.count - a.count);

  return (
    <div className="ws-home">
      <div className="ws-breadcrumb">
        <a onClick={() => onNav('home')}>Accueil</a>
        <Icon name="chevR" size={12}/>
        <span>Nos marques</span>
      </div>
      <section className="ws-section">
        <div className="ws-section-head">
          <h1 style={{ margin: 0 }}>Nos marques</h1>
          <span className="ws-muted">{brands.length} marque{brands.length > 1 ? 's' : ''} référencée{brands.length > 1 ? 's' : ''}</span>
        </div>
        {brands.length === 0 ? (
          <div className="ws-cart-empty">
            <Icon name="tag" size={64} style={{ color: 'var(--muted)', opacity: 0.3 }}/>
            <h2>Aucune marque pour le moment</h2>
            <p>Les marques apparaîtront ici dès que des produits seront ajoutés au catalogue.</p>
            <button className="ws-btn ws-btn-primary" onClick={() => onNav('home')}>Voir le catalogue</button>
          </div>
        ) : (
          <div className="ws-brand-grid">
            {brands.map(b => {
              const m = meta[b.name] || {};
              return (
                <a key={b.name} className="ws-brand-card"
                   onClick={(e) => { e.preventDefault(); onNav('brand', { brand: b.name }); }}
                   href={`#/brand/${encodeURIComponent(b.name)}`}>
                  <div className="ws-brand-logo">
                    {m.logo
                      ? <img src={m.logo} alt={b.name}/>
                      : <Icon name="tag" size={32}/>}
                  </div>
                  <div className="ws-brand-name">{b.name}</div>
                  <div className="ws-brand-count">{b.count} produit{b.count > 1 ? 's' : ''}</div>
                </a>
              );
            })}
          </div>
        )}
      </section>
    </div>
  );
};

// ---------- Single brand page: products grouped by category ----------
const BrandPage = ({ brand, onNav }) => {
  const [products, setProducts] = useState([]);
  const [meta, setMeta] = useState(null);
  const tree = useCategoriesTree();

  useEffect(() => {
    let alive = true;
    Promise.all([
      window.WS_DB.listProducts({ activeOnly: true, platform: 'web' }).catch(() => []),
      window.WS_DB.getSetting('brand_meta').catch(() => ({})),
    ]).then(([p, m]) => {
      if (!alive) return;
      setProducts((p || []).filter(x => (x.marque || '').trim().toLowerCase() === brand.toLowerCase()));
      setMeta((m && m[brand]) || {});
    });
    return () => { alive = false; };
  }, [brand]);

  // Build category labels (full path) for grouping
  const labelFor = (slug) => {
    const found = findInTree(tree, slug);
    return found ? found.path.map(n => n.name).join(' › ') : slug;
  };
  const groups = {};
  for (const p of products) {
    const key = p.cat || '__nocat__';
    (groups[key] = groups[key] || []).push(p);
  }

  return (
    <div className="ws-cat-page">
      <div className="ws-breadcrumb">
        <a onClick={() => onNav('home')}>Accueil</a>
        <Icon name="chevR" size={12}/>
        <a onClick={() => onNav('brands')}>Nos marques</a>
        <Icon name="chevR" size={12}/>
        <span>{brand}</span>
      </div>

      <div className="ws-brand-head">
        <div className="ws-brand-head-logo">
          {meta?.logo
            ? <img src={meta.logo} alt={brand}/>
            : <Icon name="tag" size={48}/>}
        </div>
        <div>
          <h1 style={{ margin: 0 }}>{brand}</h1>
          <p className="ws-muted" style={{ marginTop: 4 }}>{products.length} produit{products.length > 1 ? 's' : ''} référencé{products.length > 1 ? 's' : ''}</p>
          {meta?.description && <p style={{ marginTop: 8, maxWidth: 720, lineHeight: 1.6 }}>{meta.description}</p>}
        </div>
      </div>

      {products.length === 0 ? (
        <div className="ws-empty" style={{ marginTop: 24 }}>
          <Icon name="search" size={48} style={{ color: 'var(--muted)', opacity: 0.5 }}/>
          <h3>Aucun produit pour cette marque</h3>
        </div>
      ) : (
        Object.keys(groups).map(slug => (
          <section key={slug} className="ws-section" style={{ marginTop: 24 }}>
            <div className="ws-section-head">
              <h2 style={{ fontSize: 18 }}>{slug === '__nocat__' ? 'Sans catégorie' : labelFor(slug)}</h2>
              <span className="ws-muted">{groups[slug].length} produit{groups[slug].length > 1 ? 's' : ''}</span>
            </div>
            <div className="ws-prod-grid">
              {groups[slug].map(p => (
                <ProductCard key={p.id} p={p}
                  onOpen={() => onNav('product', { id: p.id })}/>
              ))}
            </div>
          </section>
        ))
      )}
    </div>
  );
};

Object.assign(window, {
  HomePage, CategoryPage, ProductCard, ProductRow, ClientHeader, Logo,
  SearchPage, FavoritesPage, BrandsPage, BrandPage, Thumb, useFavSet,
  fmt, TND, collectLeafSlugs, topIconFor,
  applyCategoryOverrides, flattenCategoryTree, findInTree,
});
