// Brand Catalog & Supply — HQ governance of the menu, products, vendors, and PO approvals across all locations

// ── Mock data (page-local; lives here so page is self-contained) ────────
const CATALOG_KPIS = {
  brandServices: 26,
  brandServicesLocked: 18,
  priceDriftShops: 2,
  vendors: 8,
  pendingPOs: 5,
  pendingPOValue: 11780,
  stockoutShops: 4,
};

// Master service menu — each service tells HQ:
//  • how many of 8 franchised shops have adopted it (corporate is always adopted)
//  • how many are within the brand-price band (±5%)
//  • current network revenue contribution
const MASTER_SERVICES = [
  { name:'Haircut & Beard Trim',       category:'Men',   brandPrice: 45, adopted: 10, priceCompliant: 10, netRev: 45784, locked: true,  status:'core' },
  { name:'Skin Fade',                  category:'Men',   brandPrice: 35, adopted: 10, priceCompliant: 10, netRev: 35648, locked: true,  status:'core' },
  { name:'Adult Haircut',              category:'Men',   brandPrice: 30, adopted: 10, priceCompliant: 10, netRev: 35305, locked: true,  status:'core' },
  { name:'Wash, Cut & Style',          category:'Women', brandPrice: 60, adopted: 10, priceCompliant: 10, netRev: 30410, locked: true,  status:'core' },
  { name:'Boys Haircut',               category:'Kids',  brandPrice: 25, adopted: 10, priceCompliant: 10, netRev: 29217, locked: true,  status:'core' },
  { name:'Women\u2019s Haircut',       category:'Women', brandPrice: 45, adopted: 10, priceCompliant: 10, netRev: 26715, locked: true,  status:'core' },
  { name:'Blowout',                    category:'Women', brandPrice: 40, adopted:  9, priceCompliant:  8, netRev: 24023, locked: false, status:'optional', flag:'price-drift' },
  { name:'Beard Trim',                 category:'Men',   brandPrice: 15, adopted: 10, priceCompliant: 10, netRev: 23084, locked: true,  status:'core' },
  { name:'Highlights',                 category:'Color', brandPrice:120, adopted:  6, priceCompliant:  5, netRev:  7100, locked: false, status:'optional', flag:'price-drift' },
  { name:'Full Color',                 category:'Color', brandPrice: 90, adopted:  7, priceCompliant:  7, netRev:  6810, locked: false, status:'optional' },
  { name:'Haircut, Beard & Hot Towel', category:'Men',   brandPrice: 60, adopted:  8, priceCompliant:  8, netRev:  6350, locked: false, status:'optional' },
];

// Vendors — network-wide supplier list
const NETWORK_VENDORS = [
  { name:'Atlas Salon Supply',           tier:'Core',        terms:'Net 30', shops: 10, mtdSpend: 3542, onTime: 48.1, status:'approved', primary:true, flag:'sla-watch' },
  { name:'Northbridge Beauty Wholesale', tier:'Core',        terms:'Net 15', shops: 10, mtdSpend: 5028, onTime: 22.0, status:'approved', flag:'sla-breach' },
  { name:'ProEdge Distribution',         tier:'Core',        terms:'Net 45', shops: 10, mtdSpend: 4733, onTime: 30.6, status:'approved', flag:'sla-watch' },
  { name:'Maple Grooming Imports',       tier:'Core',        terms:'Net 30', shops:  8, mtdSpend: 3500, onTime: 48.1, status:'approved' },
  { name:'Cedar & Co Retail Brands',     tier:'Core',        terms:'Net 60', shops: 10, mtdSpend: 3503, onTime: 60.0, status:'approved' },
  { name:'Sharp Edge Tools',             tier:'Equipment',   terms:'Net 45', shops: 10, mtdSpend:  620, onTime: 88.0, status:'approved' },
  { name:'Northern Linen Supply',        tier:'Consumables', terms:'Net 15', shops: 10, mtdSpend: 1890, onTime: 94.2, status:'approved' },
  { name:'GTA Sanitation Partners',      tier:'Consumables', terms:'Net 30', shops: 10, mtdSpend:  940, onTime: 91.6, status:'approved' },
  { name:'Discount Barber Depot',        tier:'Pending',     terms:'TBD',    shops:  0, mtdSpend:    0, onTime:  0,   status:'pending-approval' },
];

// PO approval queue — POs exceeding the HQ approval threshold
const PO_THRESHOLD = 1500;
const PENDING_POS = [
  { id:'PO-00151', location:'HB003', locationName:'Oakville',         vendor:'Atlas Salon Supply',           items: 14, total: 2340, requestor:'Y. Vandenberg', submitted:'2026-09-12', age:'1d',  priority:'standard' },
  { id:'PO-00152', location:'HB005', locationName:'Hamilton',         vendor:'ProEdge Distribution',         items:  9, total: 1820, requestor:'W. Underhill',  submitted:'2026-09-11', age:'2d',  priority:'rush',     flag:'vendor-sla' },
  { id:'PO-00153', location:'HB002', locationName:'Mississauga',      vendor:'Northbridge Beauty Wholesale', items: 12, total: 2940, requestor:'S. Davidson',   submitted:'2026-09-11', age:'2d',  priority:'standard', flag:'vendor-sla' },
  { id:'PO-00154', location:'HB010', locationName:'Scarborough',      vendor:'Discount Barber Depot',        items:  4, total: 1560, requestor:'K. Manderson',  submitted:'2026-09-10', age:'3d',  priority:'standard', flag:'unapproved-vendor' },
  { id:'PO-00155', location:'HB007', locationName:'Markham',          vendor:'Cedar & Co Retail Brands',     items: 11, total: 3120, requestor:'S. Fitzgerald', submitted:'2026-09-09', age:'4d',  priority:'standard' },
  { id:'PO-00150', location:'HB001', locationName:'Toronto Downtown', vendor:'Maple Grooming Imports',       items:  4, total: 1051, requestor:'I. Manderson',  submitted:'2026-08-28', age:'16d', priority:'standard', auto:true },
];

// Master product catalog — every SKU HQ manages
const MASTER_PRODUCTS = [
  { sku:'MZ887', name:'Product Shampoo',              category:'Hair Care',  brandPrice: 20, brandCost: 7.50, margin: 62, vendor:'Atlas Salon Supply',           adopted: 10, priceCompliant: 10, netRev: 4628, units: 231, status:'core',     locked: true,  stock:'healthy' },
  { sku:'MZ889', name:'2-in-1 Shampoo & Conditioner', category:'Hair Care',  brandPrice: 20, brandCost: 7.50, margin: 62, vendor:'Atlas Salon Supply',           adopted: 10, priceCompliant: 10, netRev: 4570, units: 229, status:'core',     locked: true,  stock:'low' },
  { sku:'MZ888', name:'Product Conditioner',          category:'Hair Care',  brandPrice: 20, brandCost: 7.50, margin: 62, vendor:'Atlas Salon Supply',           adopted: 10, priceCompliant: 10, netRev: 4462, units: 223, status:'core',     locked: true,  stock:'watch' },
  { sku:'MZ903', name:'Mustache Wax',                 category:'Beard Care', brandPrice: 22, brandCost: 7.75, margin: 65, vendor:'Northbridge Beauty Wholesale', adopted: 10, priceCompliant: 10, netRev: 3681, units: 167, status:'core',     locked: true,  stock:'healthy' },
  { sku:'MZ897', name:'Sea Salt Spray',               category:'Styling',    brandPrice: 18, brandCost: 6.50, margin: 64, vendor:'ProEdge Distribution',         adopted: 10, priceCompliant: 10, netRev: 3681, units: 205, status:'core',     locked: true,  stock:'low' },
  { sku:'MZ898', name:'Beard Oil',                    category:'Beard Care', brandPrice: 22, brandCost: 7.75, margin: 65, vendor:'Maple Grooming Imports',       adopted: 10, priceCompliant: 10, netRev: 3680, units: 167, status:'core',     locked: true,  stock:'low' },
  { sku:'MZ899', name:'Beard Balm',                   category:'Beard Care', brandPrice: 22, brandCost: 7.75, margin: 65, vendor:'Northbridge Beauty Wholesale', adopted: 10, priceCompliant: 10, netRev: 3658, units: 166, status:'core',     locked: true,  stock:'critical', vendorIssue:true },
  { sku:'MZ890', name:'Styling Pomade',               category:'Styling',    brandPrice: 18, brandCost: 6.50, margin: 64, vendor:'ProEdge Distribution',         adopted: 10, priceCompliant:  9, netRev: 3567, units: 198, status:'core',     locked: true,  stock:'low',      flag:'price-drift' },
  { sku:'MZ906', name:'Travel Pomade',                category:'Travel',     brandPrice: 25, brandCost: 9.85, margin: 61, vendor:'Cedar & Co Retail Brands',     adopted:  8, priceCompliant:  8, netRev: 1540, units:  62, status:'pilot',    locked: false, stock:'healthy' },
];

// Inventory health — most-watched SKUs across the network
const INVENTORY_HEALTH = [
  { sku:'MZ899', name:'Beard Balm',           stockoutShops: 2, lowShops: 1, healthyShops: 7, totalUnits:  84, dayOfStock:  5, status:'critical', vendorIssue:true },
  { sku:'MZ890', name:'Styling Pomade',       stockoutShops: 1, lowShops: 1, healthyShops: 8, totalUnits:  96, dayOfStock:  8, status:'low' },
  { sku:'MZ888', name:'Product Conditioner',  stockoutShops: 0, lowShops: 3, healthyShops: 7, totalUnits: 132, dayOfStock:  9, status:'watch' },
  { sku:'MZ897', name:'Sea Salt Spray',       stockoutShops: 1, lowShops: 0, healthyShops: 9, totalUnits: 118, dayOfStock:  7, status:'low',      vendorIssue:true },
  { sku:'MZ887', name:'Product Shampoo',      stockoutShops: 0, lowShops: 0, healthyShops:10, totalUnits: 178, dayOfStock: 14, status:'healthy' },
  { sku:'MZ902', name:'Beard Conditioner',    stockoutShops: 0, lowShops: 0, healthyShops:10, totalUnits: 152, dayOfStock: 12, status:'healthy' },
];

// ── Sub-components ──────────────────────────────────────────────────────

const CatalogKpis = () => {
  const k = CATALOG_KPIS;
  return (
    <div className="cat-kpis">
      <div className="cat-kpi">
        <div className="cat-kpi-l">Required services <InfoDot tip="Services every shop must offer at the brand-set price. These can't be removed locally."/></div>
        <div className="cat-kpi-v">{k.brandServicesLocked} / {k.brandServices}</div>
        <div className="cat-kpi-sub"><Icon name="shield" size={11} stroke={2.2}/> {k.brandServicesLocked} locked at brand price</div>
      </div>
      <div className="cat-kpi cat-kpi-warn">
        <div className="cat-kpi-l">Off-brand pricing <InfoDot tip="Shops selling a brand-priced service outside the allowed ±5% band. Off-brand pricing erodes consistency and confuses clients."/></div>
        <div className="cat-kpi-v">{k.priceDriftShops} shops</div>
        <div className="cat-kpi-sub">Selling outside ±5% brand band</div>
      </div>
      <div className="cat-kpi">
        <div className="cat-kpi-l">Approved suppliers <InfoDot tip="Suppliers HQ has cleared for the network. Shops can only place orders with suppliers on this list."/></div>
        <div className="cat-kpi-v">{k.vendors}</div>
        <div className="cat-kpi-sub">1 pending HQ review</div>
      </div>
      <div className="cat-kpi cat-kpi-urgent">
        <div className="cat-kpi-l">Orders awaiting your OK <InfoDot tip="Purchase orders over the HQ threshold ($1,500) need your sign-off before going to the supplier."/></div>
        <div className="cat-kpi-v">{k.pendingPOs}</div>
        <div className="cat-kpi-sub">{fmtMoneyFull(k.pendingPOValue)} total · 2 over 3d</div>
      </div>
      <div className="cat-kpi cat-kpi-warn">
        <div className="cat-kpi-l">Out-of-stock risk <InfoDot tip="Shops with at least one brand product running critically low or already out."/></div>
        <div className="cat-kpi-v">{k.stockoutShops} shops</div>
        <div className="cat-kpi-sub">2 SKUs critical · vendor SLA issue</div>
      </div>
    </div>
  );
};

const ServicesTab = ({ onOpen }) => {
  const [filter, setFilter] = React.useState('all');
  const rows = MASTER_SERVICES.filter(s => {
    if (filter === 'core') return s.status === 'core';
    if (filter === 'pilot') return s.status === 'pilot';
    if (filter === 'drift') return s.priceCompliant < s.adopted;
    return true;
  });
  return (
    <section className="card">
      <header className="card-head">
        <div className="card-head-left">
          <Icon name="scissors" size={16} stroke={2}/>
          <h2>Master service menu</h2>
          <InfoDot tip="HQ-defined catalog of services. 'Locked' services can't be removed by a location; the brand-price band auto-flags drift."/>
          <span className="card-head-count">{rows.length} services</span>
        </div>
        <div className="card-head-right">
          <div className="seg-group small">
            {[['all','All'],['core','Core'],['pilot','Pilot'],['drift','Price drift']].map(([k,lbl]) => (
              <button key={k} className={'seg' + (filter === k ? ' is-on' : '')} onClick={() => setFilter(k)}>{lbl}</button>
            ))}
          </div>
          <button className="ghost-btn small"><Icon name="plus" size={12} stroke={2.4}/> Add service</button>
        </div>
      </header>

      <div className="lb-table-wrap">
        <table className="lb-table cat-table">
          <thead>
            <tr>
              <th>Service</th>
              <th>Category</th>
              <th className="num">Brand price <InfoDot tip="The price every shop should be selling this service at. Tracked across the network."/></th>
              <th>Shops offering it <InfoDot tip="How many of the 10 shops have this service on their menu."/></th>
              <th>Selling at brand price <InfoDot tip="Of the shops offering this service, how many are within ±5% of the brand price."/></th>
              <th className="num">Sales (MTD, network) <InfoDot tip="Revenue from this service month-to-date across all 10 shops."/></th>
              <th>Status</th>
              <th></th>
            </tr>
          </thead>
          <tbody>
            {rows.map(s => (
              <tr key={s.name} className="lb-row" onClick={() => onOpen(s)}>
                <td><div className="lb-name">{s.name}</div>{s.flag === 'price-drift' && <div className="cat-flag">⚠ Off brand price — see per-shop view</div>}</td>
                <td><span className="pill" style={{ background:'#F1F5F9', color:'#475569' }}>{s.category}</span></td>
                <td className="num strong">${s.brandPrice}</td>
                <td>
                  <div className="cat-meter">
                    <div className="cat-meter-bar"><div className="cat-meter-fill" style={{ width: (s.adopted/10*100) + '%', background: s.adopted === 10 ? '#16A34A' : s.adopted >= 8 ? '#0EA5E9' : '#F59E0B' }}/></div>
                    <span>{s.adopted}/10</span>
                  </div>
                </td>
                <td>
                  <div className="cat-meter">
                    <div className="cat-meter-bar"><div className="cat-meter-fill" style={{ width: (s.priceCompliant/s.adopted*100) + '%', background: s.priceCompliant === s.adopted ? '#16A34A' : s.priceCompliant/s.adopted >= 0.8 ? '#F59E0B' : '#EF4444' }}/></div>
                    <span>{s.priceCompliant}/{s.adopted}</span>
                  </div>
                </td>
                <td className="num">{fmtMoneyFull(s.netRev)}</td>
                <td>
                  {s.locked && <span className="pill" style={{ background:'#DBEAFE', color:'#1E3A8A' }}><Icon name="shield" size={10} stroke={2.4}/> Locked</span>}
                  {!s.locked && s.status === 'pilot' && <span className="pill" style={{ background:'#FEF3C7', color:'#92400E' }}>Pilot</span>}
                  {!s.locked && s.status === 'optional' && <span className="pill" style={{ background:'#F1F5F9', color:'#475569' }}>Optional</span>}
                </td>
                <td className="lb-open"><Icon name="arrow-right" size={14} stroke={2}/></td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </section>
  );
};

const VendorsTab = () => (
  <section className="card">
    <header className="card-head">
      <div className="card-head-left">
        <Icon name="building" size={16} stroke={2}/>
        <h2>Approved vendor list</h2>
        <InfoDot tip="Vendors approved at the brand level. Locations can only place POs against this list — keeps quality and pricing consistent network-wide."/>
        <span className="card-head-count">{NETWORK_VENDORS.length} vendors</span>
      </div>
      <div className="card-head-right">
        <button className="ghost-btn small"><Icon name="plus" size={12} stroke={2.4}/> Add vendor</button>
      </div>
    </header>

    <div className="lb-table-wrap">
      <table className="lb-table cat-table">
        <thead>
          <tr>
            <th>Vendor</th>
            <th>Tier</th>
            <th>Terms</th>
            <th className="num">Shops served</th>
            <th className="num">Spend this month <InfoDot tip="Total purchase-order value with this supplier, month-to-date."/></th>
            <th>On-time deliveries <InfoDot tip="% of orders this supplier delivered by the promised date over the last 90 days."/></th>
            <th>Status</th>
            <th></th>
          </tr>
        </thead>
        <tbody>
          {NETWORK_VENDORS.map(v => (
            <tr key={v.name}>
              <td>
                <div className="lb-name">{v.name}{v.primary && <span className="cat-primary">PRIMARY</span>}</div>
                {v.flag === 'sla-breach' && <div className="cat-flag">⚠ Missed delivery promise — 14d cover missed</div>}
                {v.flag === 'sla-watch'  && <div className="cat-flag cat-flag-warn">⚠ Late on recent deliveries</div>}
              </td>
              <td><span className="pill" style={{ background: v.tier === 'Core' ? '#DCFCE7' : v.tier === 'Specialty' ? '#E0E7FF' : v.tier === 'Regional' ? '#FEF3C7' : '#F1F5F9', color: v.tier === 'Core' ? '#166534' : v.tier === 'Specialty' ? '#3730A3' : v.tier === 'Regional' ? '#92400E' : '#475569' }}>{v.tier}</span></td>
              <td>{v.terms}</td>
              <td className="num">{v.shops}/10</td>
              <td className="num">{fmtMoneyFull(v.mtdSpend)}</td>
              <td>
                {v.onTime > 0 ? (
                  <div className="cat-meter">
                    <div className="cat-meter-bar"><div className="cat-meter-fill" style={{ width: v.onTime + '%', background: v.onTime >= 95 ? '#16A34A' : v.onTime >= 85 ? '#F59E0B' : '#EF4444' }}/></div>
                    <span>{v.onTime}%</span>
                  </div>
                ) : <span className="muted">—</span>}
              </td>
              <td>
                {v.status === 'approved' && <span className="pill" style={{ background:'#DCFCE7', color:'#166534' }}><span className="pill-dot" style={{ background:'#16A34A' }}/>Approved</span>}
                {v.status === 'review' && <span className="pill" style={{ background:'#FEF3C7', color:'#92400E' }}><span className="pill-dot" style={{ background:'#F59E0B' }}/>Under review</span>}
                {v.status === 'pending-approval' && <span className="pill" style={{ background:'#FEE2E2', color:'#B91C1C' }}><span className="pill-dot" style={{ background:'#DC2626' }}/>Pending approval</span>}
              </td>
              <td className="lb-open"><Icon name="arrow-right" size={14} stroke={2}/></td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  </section>
);

const POApprovalsTab = ({ onOpenLoc }) => {
  const total = PENDING_POS.reduce((a, p) => a + p.total, 0);
  return (
    <section className="card">
      <header className="card-head">
        <div className="card-head-left">
          <Icon name="warn" size={16} stroke={2}/>
          <h2>PO approval queue</h2>
          <InfoDot tip={`POs above $${PO_THRESHOLD.toLocaleString()} require HQ approval before going to the vendor. Auto-POs from low-stock alerts bypass approval when under threshold.`}/>
          <span className="card-head-count">{PENDING_POS.filter(p => p.total >= PO_THRESHOLD).length} awaiting approval · {fmtMoneyFull(total)}</span>
        </div>
        <div className="card-head-right">
          <button className="ghost-btn small">Bulk approve under $2k</button>
          <button className="ghost-btn small">Set threshold</button>
        </div>
      </header>

      <div className="po-list">
        {PENDING_POS.map(p => {
          const above = p.total >= PO_THRESHOLD;
          const oldAge = p.age === '3d' || p.age === '4d';
          return (
            <article key={p.id} className={'po-row' + (above ? ' is-above' : ' is-auto') + (p.flag ? ' is-flagged' : '')}>
              <div className="po-row-l">
                <div className="po-id">{p.id}</div>
                <div className={'po-priority po-' + p.priority}>{p.priority === 'rush' ? '🚨 RUSH' : 'STANDARD'}</div>
                {p.auto && <div className="po-auto">AUTO · UNDER THRESHOLD</div>}
              </div>
              <div className="po-row-main">
                <div className="po-vendor">{p.vendor}</div>
                <div className="po-meta">
                  <span className="po-loc" onClick={(e) => { e.stopPropagation(); const loc = window.FRANCHISE_DATA.LOCATIONS.find(l => l.id === p.location); if (loc) onOpenLoc(loc); }}>
                    <Icon name="pin" size={11} stroke={2}/> {p.locationName}
                  </span>
                  <span>{p.items} line items</span>
                  <span>Submitted {p.submitted} ({p.age} ago)</span>
                  <span>By {p.requestor}</span>
                </div>
                {p.flag === 'unapproved-vendor' && (
                  <div className="po-flag po-flag-bad">⚠ Vendor not on approved list. Required HQ exception to proceed.</div>
                )}
                {p.flag === 'vendor-sla' && (
                  <div className="po-flag po-flag-warn">⚠ Supplier missed last 3 delivery dates.</div>
                )}
                {oldAge && (
                  <div className="po-flag po-flag-warn">⏱ Aging — sitting {p.age}; blocking shop operations if approved late.</div>
                )}
              </div>
              <div className="po-row-r">
                <div className="po-total">{fmtMoneyFull(p.total)}</div>
                {above ? (
                  <div className="po-actions">
                    <button className="primary-btn"><Icon name="check" size={12} stroke={2.4}/> Approve</button>
                    <button className="ghost-btn small">Decline</button>
                    <button className="ghost-btn small">Open</button>
                  </div>
                ) : (
                  <div className="po-actions">
                    <span className="po-auto-note">Auto-fired</span>
                    <button className="ghost-btn small">Open</button>
                  </div>
                )}
              </div>
            </article>
          );
        })}
      </div>
    </section>
  );
};

// ── Products tab ────────────────────────────────────────────────────────
const ProductsTab = ({ onOpen }) => {
  const [filter, setFilter] = React.useState('all');
  const rows = MASTER_PRODUCTS.filter(p => {
    if (filter === 'core') return p.status === 'core';
    if (filter === 'pilot') return p.status === 'pilot';
    if (filter === 'drift') return p.priceCompliant < p.adopted;
    if (filter === 'stock') return p.stock !== 'healthy';
    return true;
  });
  return (
    <section className="card">
      <header className="card-head">
        <div className="card-head-left">
          <Icon name="box" size={16} stroke={2}/>
          <h2>Master retail catalog</h2>
          <InfoDot tip="Every retail SKU HQ manages. 'Locked' SKUs can't be removed by a location; the brand-price band auto-flags drift."/>
          <span className="card-head-count">{rows.length} products</span>
        </div>
        <div className="card-head-right">
          <div className="seg-group small">
            {[['all','All'],['core','Core'],['pilot','Pilot'],['drift','Price drift'],['stock','Stock issue']].map(([k,lbl]) => (
              <button key={k} className={'seg' + (filter === k ? ' is-on' : '')} onClick={() => setFilter(k)}>{lbl}</button>
            ))}
          </div>
          <button className="ghost-btn small"><Icon name="plus" size={12} stroke={2.4}/> Add product</button>
        </div>
      </header>

      <div className="lb-table-wrap">
        <table className="lb-table cat-table">
          <thead>
            <tr>
              <th>Product</th>
              <th>Category</th>
              <th className="num">Brand price <InfoDot tip="The price every shop should be selling this product at, network-wide."/></th>
              <th className="num">Margin <InfoDot tip="Gross margin at brand price = (price − unit cost) ÷ price."/></th>
              <th>Primary vendor</th>
              <th>Shops carrying it <InfoDot tip="How many of the 10 shops stock this product."/></th>
              <th>Selling at brand price <InfoDot tip="Of the shops carrying this product, how many are within ±5% of the brand price."/></th>
              <th className="num">Sales (MTD) <InfoDot tip="Revenue from this SKU across the network, month-to-date."/></th>
              <th>Stock</th>
              <th></th>
            </tr>
          </thead>
          <tbody>
            {rows.map(p => (
              <tr key={p.sku} className="lb-row" onClick={() => onOpen(p)}>
                <td>
                  <div className="lb-name">{p.name}</div>
                  <div className="lb-sub">{p.sku}</div>
                  {p.flag === 'price-drift' && <div className="cat-flag">⚠ Off brand price — see per-shop view</div>}
                </td>
                <td><span className="pill" style={{ background:'#F1F5F9', color:'#475569' }}>{p.category}</span></td>
                <td className="num strong">${p.brandPrice}</td>
                <td className="num">{p.margin}%</td>
                <td><span className="muted" style={{ fontSize: 12 }}>{p.vendor}</span></td>
                <td>
                  <div className="cat-meter">
                    <div className="cat-meter-bar"><div className="cat-meter-fill" style={{ width: (p.adopted/10*100) + '%', background: p.adopted === 10 ? '#16A34A' : p.adopted >= 8 ? '#0EA5E9' : '#F59E0B' }}/></div>
                    <span>{p.adopted}/10</span>
                  </div>
                </td>
                <td>
                  <div className="cat-meter">
                    <div className="cat-meter-bar"><div className="cat-meter-fill" style={{ width: (p.priceCompliant/p.adopted*100) + '%', background: p.priceCompliant === p.adopted ? '#16A34A' : p.priceCompliant/p.adopted >= 0.8 ? '#F59E0B' : '#EF4444' }}/></div>
                    <span>{p.priceCompliant}/{p.adopted}</span>
                  </div>
                </td>
                <td className="num">{fmtMoneyFull(p.netRev)}</td>
                <td>
                  {p.stock === 'healthy'  && <span className="pill" style={{ background:'#DCFCE7', color:'#166534' }}><span className="pill-dot" style={{ background:'#16A34A' }}/>Healthy</span>}
                  {p.stock === 'watch'    && <span className="pill" style={{ background:'#FEF3C7', color:'#92400E' }}><span className="pill-dot" style={{ background:'#F59E0B' }}/>Watch</span>}
                  {p.stock === 'low'      && <span className="pill" style={{ background:'#FFEDD5', color:'#9A3412' }}><span className="pill-dot" style={{ background:'#F97316' }}/>Low</span>}
                  {p.stock === 'critical' && <span className="pill" style={{ background:'#FEE2E2', color:'#B91C1C' }}><span className="pill-dot" style={{ background:'#DC2626' }}/>Critical</span>}
                </td>
                <td className="lb-open"><Icon name="arrow-right" size={14} stroke={2}/></td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </section>
  );
};

// ── Service/Product detail drawer ───────────────────────────────────────
// Per-shop adoption + price compliance breakdown for a given catalog item.
const SHOP_LIST = [
  { id:'HB001', name:'Toronto Downtown', type:'corporate'  },
  { id:'HB002', name:'Mississauga',      type:'corporate'  },
  { id:'HB003', name:'Oakville',         type:'franchised' },
  { id:'HB004', name:'Burlington',       type:'franchised' },
  { id:'HB005', name:'Hamilton',         type:'franchised' },
  { id:'HB006', name:'Vaughan',          type:'franchised' },
  { id:'HB007', name:'Markham',          type:'franchised' },
  { id:'HB008', name:'Brampton',         type:'franchised' },
  { id:'HB009', name:'Richmond Hill',    type:'franchised' },
  { id:'HB010', name:'Scarborough',      type:'franchised' },
];

function shopBreakdown(item, kind) {
  // Deterministic per-shop adoption + per-shop selling price
  const seed = (item.name || item.sku || 'x').split('').reduce((a,c) => a + c.charCodeAt(0), 0);
  const rng = (i) => ((seed * 9301 + i * 49297) % 233280) / 233280;
  return SHOP_LIST.map((shop, i) => {
    const offers = i < item.adopted;
    if (!offers) return { ...shop, offers:false };
    const compliant = i < item.priceCompliant;
    const drift = compliant ? (rng(i) * 0.04 - 0.02) : (rng(i) * 0.12 - 0.06);
    const localPrice = Math.round(item.brandPrice * (1 + drift) * 100) / 100;
    const trend = Array.from({ length: 8 }, (_, k) => Math.round((item.netRev / 10) * (0.65 + rng(i + k) * 0.7) / 8));
    const sold = Math.round((item.units || item.netRev / 30) * (0.4 + rng(i + 11) * 1.2) / item.adopted);
    return { ...shop, offers:true, compliant, localPrice, trend, sold };
  });
}

const ItemDetail = ({ item, kind, onClose }) => {
  if (!item) return null;
  const breakdown = shopBreakdown(item, kind);
  const offering = breakdown.filter(b => b.offers);
  const compliantCount = offering.filter(b => b.compliant).length;
  const avgLocalPrice = offering.length ? (offering.reduce((a, b) => a + b.localPrice, 0) / offering.length) : item.brandPrice;
  // 12-week network revenue trend (deterministic)
  const seed = (item.name || item.sku).length;
  const trend = Array.from({ length: 12 }, (_, i) => Math.round((item.netRev / 12) * (0.7 + ((i * 17 + seed) % 11) / 14)));
  const maxTrend = Math.max(...trend);

  return (
    <div className="overlay" onClick={onClose}>
      <aside className="detail" onClick={(e) => e.stopPropagation()}>
        <div className="detail-head">
          <div>
            <button className="detail-back" onClick={onClose}><Icon name="arrow-right" size={12} style={{ transform: 'rotate(180deg)' }}/> Back to {kind === 'service' ? 'services' : 'products'}</button>
            <div className="detail-title-row">
              <div className="detail-shop-mark"><Icon name={kind === 'service' ? 'scissors' : 'box'} size={20} stroke={2}/></div>
              <div>
                <h2>{item.name}</h2>
                <div className="detail-shop-meta">
                  {item.sku && <span><b>SKU</b>&nbsp;{item.sku}</span>}
                  <span><b>Category</b>&nbsp;{item.category}</span>
                  <span><b>Brand price</b>&nbsp;${item.brandPrice}{kind === 'product' && <span style={{ color:'#94A3B8' }}> · {item.margin}% margin</span>}</span>
                  <span>
                    {item.locked && <span className="pill" style={{ background:'#DBEAFE', color:'#1E3A8A' }}><Icon name="shield" size={10} stroke={2.4}/> Locked</span>}
                    {!item.locked && item.status === 'pilot' && <span className="pill" style={{ background:'#FEF3C7', color:'#92400E' }}>Pilot</span>}
                    {!item.locked && item.status === 'optional' && <span className="pill" style={{ background:'#F1F5F9', color:'#475569' }}>Optional</span>}
                  </span>
                </div>
              </div>
            </div>
          </div>
          <div className="detail-head-right">
            <button className="ghost-btn small">Edit</button>
            <button className="ghost-btn small"><Icon name="megaphone" size={12} stroke={2.2}/> Push to all shops</button>
            <button className="icon-btn" onClick={onClose}><Icon name="close" size={16}/></button>
          </div>
        </div>

        <div className="detail-body">
          <div className="detail-kpis">
            <div className="dk"><div className="dk-l">Network revenue (MTD)</div><div className="dk-v">{fmtMoneyFull(item.netRev)}</div><div className="dk-sub">All 10 shops</div></div>
            <div className="dk"><div className="dk-l">Shops offering</div><div className="dk-v">{item.adopted}/10</div><div className="dk-sub">{10 - item.adopted} not adopting</div></div>
            <div className="dk"><div className="dk-l">At brand price</div><div className="dk-v">{compliantCount}/{item.adopted}</div><div className={'dk-sub' + (compliantCount < item.adopted ? ' is-bad' : ' is-good')}>{compliantCount < item.adopted ? `${item.adopted - compliantCount} drifting` : 'In control'}</div></div>
            <div className="dk"><div className="dk-l">Avg local price</div><div className="dk-v">${avgLocalPrice.toFixed(2)}</div><div className="dk-sub">vs ${item.brandPrice} brand</div></div>
            {kind === 'product' ? (
              <React.Fragment>
                <div className="dk"><div className="dk-l">Units (MTD)</div><div className="dk-v">{item.units}</div><div className="dk-sub">Across network</div></div>
                <div className="dk"><div className="dk-l">Stock posture</div><div className="dk-v" style={{ fontSize: 15 }}>{item.stock.toUpperCase()}</div><div className={'dk-sub' + (item.stock === 'critical' || item.stock === 'low' ? ' is-bad' : ' is-good')}>{item.vendor}</div></div>
              </React.Fragment>
            ) : (
              <React.Fragment>
                <div className="dk"><div className="dk-l">Status</div><div className="dk-v" style={{ fontSize: 15 }}>{(item.status || 'core').toUpperCase()}</div><div className="dk-sub">{item.locked ? 'Brand-locked' : 'Operator-optional'}</div></div>
                <div className="dk"><div className="dk-l">Network share</div><div className="dk-v">{((item.netRev / 24000) * 100).toFixed(1)}%</div><div className="dk-sub">Of typical-day {kind === 'service' ? 'service' : 'product'} revenue</div></div>
              </React.Fragment>
            )}
          </div>

          <div className="detail-grid">
            <div className="detail-block detail-block-wide">
              <h3>Per-shop adoption & price compliance <InfoDot tip="Each row is a shop. Local price within ±5% of brand price is compliant; further out is drift."/></h3>
              <div className="lb-table-wrap">
                <table className="lb-table cat-table">
                  <thead>
                    <tr>
                      <th>Shop</th>
                      <th>Type</th>
                      <th>Offering</th>
                      <th className="num">Local price</th>
                      <th className="num">Drift</th>
                      <th className="num">{kind === 'product' ? 'Units (MTD)' : 'Bookings (MTD)'}</th>
                      <th>Compliance</th>
                    </tr>
                  </thead>
                  <tbody>
                    {breakdown.map(b => {
                      if (!b.offers) {
                        return (
                          <tr key={b.id} style={{ opacity: 0.6 }}>
                            <td><div className="lb-name">{b.name}</div><div className="lb-sub">{b.id}</div></td>
                            <td><span className={'type-badge type-' + b.type}>{b.type}</span></td>
                            <td><span className="muted">Not offering</span></td>
                            <td className="num muted">—</td>
                            <td className="num muted">—</td>
                            <td className="num muted">—</td>
                            <td><span className="pill" style={{ background:'#F1F5F9', color:'#94A3B8' }}>Not in menu</span></td>
                          </tr>
                        );
                      }
                      const drift = ((b.localPrice - item.brandPrice) / item.brandPrice) * 100;
                      return (
                        <tr key={b.id}>
                          <td><div className="lb-name">{b.name}</div><div className="lb-sub">{b.id}</div></td>
                          <td><span className={'type-badge type-' + b.type}>{b.type}</span></td>
                          <td><Icon name="check" size={14} stroke={2.4} style={{ color: '#16A34A' }}/></td>
                          <td className="num strong">${b.localPrice.toFixed(2)}</td>
                          <td className="num" style={{ color: b.compliant ? '#16A34A' : '#DC2626', fontWeight: 600 }}>{drift > 0 ? '+' : ''}{drift.toFixed(1)}%</td>
                          <td className="num">{b.sold}</td>
                          <td>
                            {b.compliant
                              ? <span className="pill" style={{ background:'#DCFCE7', color:'#166534' }}><span className="pill-dot" style={{ background:'#16A34A' }}/>Within band</span>
                              : <span className="pill" style={{ background:'#FEE2E2', color:'#B91C1C' }}><span className="pill-dot" style={{ background:'#DC2626' }}/>Off-brand</span>
                            }
                          </td>
                        </tr>
                      );
                    })}
                  </tbody>
                </table>
              </div>
            </div>

            <div className="detail-block">
              <h3>Network revenue — last 12 weeks</h3>
              <div className="traj-chart" style={{ gridTemplateColumns: 'repeat(12, 1fr)' }}>
                {trend.map((v, i) => (
                  <div key={i} className="traj-col">
                    <div className="traj-bar-wrap">
                      <div className="traj-bar" style={{ height: ((v / maxTrend) * 100) + '%' }}/>
                    </div>
                    <div className="traj-week">W{i+1}</div>
                  </div>
                ))}
              </div>
              <div className="traj-meta">12-week network revenue · MTD = {fmtMoneyFull(item.netRev)}</div>
            </div>

            <div className="detail-block">
              <h3>HQ actions</h3>
              <div className="hq-actions">
                <button className="hq-action"><Icon name="megaphone" size={16} stroke={2}/><div><b>Push to all shops</b><span>Broadcast {kind === 'product' ? 'this SKU' : 'this service'} to every operator's menu</span></div></button>
                <button className="hq-action"><Icon name="dollar" size={16} stroke={2}/><div><b>Set brand price</b><span>Change the brand price &amp; band; rolls out to all shops</span></div></button>
                <button className="hq-action"><Icon name="shield" size={16} stroke={2}/><div><b>{item.locked ? 'Unlock' : 'Lock'} at brand price</b><span>{item.locked ? 'Allow operators to override' : 'Prevent local price overrides'}</span></div></button>
                <button className="hq-action"><Icon name="warn" size={16} stroke={2}/><div><b>Open drift report</b><span>Email franchisees outside the ±5% band</span></div></button>
              </div>
            </div>
          </div>
        </div>
      </aside>
    </div>
  );
};

const InventoryTab = () => (
  <section className="card">
    <header className="card-head">
      <div className="card-head-left">
        <Icon name="box" size={16} stroke={2}/>
        <h2>Network inventory health</h2>
        <InfoDot tip="Stock posture for every brand SKU across all 10 locations. Vendor-issue flag means stockout traces back to a supplier SLA problem."/>
        <span className="card-head-count">{INVENTORY_HEALTH.length} SKUs · 2 critical</span>
      </div>
      <div className="card-head-right">
        <button className="ghost-btn small">Export</button>
      </div>
    </header>

    <div className="inv-grid">
      {INVENTORY_HEALTH.map(s => (
        <article key={s.sku} className={'inv-card inv-' + s.status}>
          <div className="inv-card-head">
            <div>
              <div className="inv-card-name">{s.name}</div>
              <div className="inv-card-sku">{s.sku}</div>
            </div>
            <div className={'inv-status inv-status-' + s.status}>{s.status.toUpperCase()}</div>
          </div>
          <div className="inv-shops">
            <div className="inv-shop-bar">
              <div className="inv-shop-seg inv-seg-stockout" style={{ flex: s.stockoutShops }}/>
              <div className="inv-shop-seg inv-seg-low"      style={{ flex: s.lowShops }}/>
              <div className="inv-shop-seg inv-seg-healthy"  style={{ flex: s.healthyShops }}/>
            </div>
            <div className="inv-shop-legend">
              <span><i className="inv-dot inv-seg-stockout"/>{s.stockoutShops} stockout</span>
              <span><i className="inv-dot inv-seg-low"/>{s.lowShops} low</span>
              <span><i className="inv-dot inv-seg-healthy"/>{s.healthyShops} healthy</span>
            </div>
          </div>
          <div className="inv-stats">
            <div><span>Network units</span><b>{s.totalUnits}</b></div>
            <div><span>Days of stock <InfoDot tip="How many days the current stock will last at the network's recent sell-through rate."/></span><b className={s.dayOfStock < 7 ? 'is-bad' : ''}>{s.dayOfStock}d</b></div>
          </div>
          {s.vendorIssue && <div className="inv-vendor-flag"><Icon name="warn" size={11} stroke={2.4}/> Vendor SLA issue — auto-POs fired, awaiting fulfillment</div>}
        </article>
      ))}
    </div>
  </section>
);

// ── Main ────────────────────────────────────────────────────────────────
const CatalogPage = ({ onOpenLoc }) => {
  const [tab, setTab] = React.useState('services');
  const [openItem, setOpenItem] = React.useState(null); // { item, kind }
  return (
    <div className="page">
      <div className="pageheader">
        <div>
          <h1 className="pageheader-title">Brand Catalog & Supply</h1>
          <p className="pageheader-sub">Master service menu, retail product catalog, approved vendor list, PO approvals over the HQ threshold, and network inventory health.</p>
        </div>
      </div>

      <CatalogKpis/>

      <div className="cat-tabs">
        {[
          ['services', 'Services', 'scissors', MASTER_SERVICES.length],
          ['products', 'Products', 'box',      MASTER_PRODUCTS.length],
          ['vendors',  'Vendors',  'building', NETWORK_VENDORS.length],
          ['pos',      'PO approvals', 'warn', PENDING_POS.filter(p => p.total >= PO_THRESHOLD).length],
          ['inventory','Inventory health', 'box', INVENTORY_HEALTH.filter(s => s.status !== 'healthy').length],
        ].map(([id, label, icon, count]) => (
          <button key={id} className={'cat-tab' + (tab === id ? ' is-on' : '')} onClick={() => setTab(id)}>
            <Icon name={icon} size={14} stroke={2}/>
            <span>{label}</span>
            {count > 0 && <span className="cat-tab-count">{count}</span>}
          </button>
        ))}
      </div>

      {tab === 'services' && <ServicesTab onOpen={(s) => setOpenItem({ item: s, kind: 'service' })}/>}
      {tab === 'products' && <ProductsTab onOpen={(p) => setOpenItem({ item: p, kind: 'product' })}/>}
      {tab === 'vendors' && <VendorsTab/>}
      {tab === 'pos' && <POApprovalsTab onOpenLoc={onOpenLoc}/>}
      {tab === 'inventory' && <InventoryTab/>}

      {openItem && <ItemDetail item={openItem.item} kind={openItem.kind} onClose={() => setOpenItem(null)}/>}
    </div>
  );
};

Object.assign(window, { CatalogPage });
