// ====== MOCK DATA — Bar/Restaurant procurement ======
const BRL = (n) => 'R$ ' + (n ?? 0).toLocaleString('pt-BR', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
const BRLk = (n) => {
  if (Math.abs(n) >= 1000) return 'R$ ' + (n / 1000).toLocaleString('pt-BR', { maximumFractionDigits: 1 }) + 'k';
  return 'R$ ' + n.toLocaleString('pt-BR', { maximumFractionDigits: 0 });
};
const pad = (n, w = 3) => String(n).padStart(w, '0');

const COMPANY = {
  name: 'Restaurante Casa do José',
  cnpj: '32.481.902/0001-55',
  owner: 'José Alberto',
  role: 'Administrador',
  email: 'jose@casadojose.com.br',
  city: 'São José do Rio Preto · SP',
};

const CATEGORIES = [
  { key: 'hortifruti', label: 'Hortifruti', tone: 'emerald' },
  { key: 'bebidas',    label: 'Bebidas',    tone: 'sky'     },
  { key: 'carnes',     label: 'Carnes',     tone: 'coral'   },
  { key: 'secos',      label: 'Secos e Molhados', tone: 'amber' },
  { key: 'limpeza',    label: 'Limpeza',    tone: 'violet'  },
  { key: 'descartaveis', label: 'Descartáveis', tone: 'sky' },
  { key: 'laticinios', label: 'Laticínios', tone: 'amber'   },
  { key: 'paes',       label: 'Pães e Confeitaria', tone: 'amber' },
];

const PRODUCTS = [
  { id: 'P-001', code: '7891000', name: 'Filé Mignon Bovino kg',     cat: 'carnes',     unit: 'kg',    brand: 'Friboi',         stock: 12, min: 20, lastPrice: 78.90, avgPrice: 82.40, supplier: 'Friboi Distribuidora' },
  { id: 'P-002', code: '7891001', name: 'Picanha Maturada kg',        cat: 'carnes',     unit: 'kg',    brand: 'JBS',            stock: 8,  min: 15, lastPrice: 96.50, avgPrice: 99.20, supplier: 'JBS Premium' },
  { id: 'P-003', code: '7891002', name: 'Frango Inteiro Resfriado',   cat: 'carnes',     unit: 'kg',    brand: 'Sadia',          stock: 28, min: 25, lastPrice: 13.40, avgPrice: 14.10, supplier: 'Sadia Atacado' },
  { id: 'P-004', code: '7891003', name: 'Tomate Italiano',            cat: 'hortifruti', unit: 'kg',    brand: 'In natura',      stock: 18, min: 30, lastPrice: 6.80,  avgPrice: 7.60,  supplier: 'CEAGESP Box 12' },
  { id: 'P-005', code: '7891004', name: 'Alface Crespa',              cat: 'hortifruti', unit: 'pé',    brand: 'Orgânico',       stock: 14, min: 24, lastPrice: 2.50,  avgPrice: 2.90,  supplier: 'Sítio Verde' },
  { id: 'P-006', code: '7891005', name: 'Cebola Branca',              cat: 'hortifruti', unit: 'kg',    brand: 'In natura',      stock: 32, min: 20, lastPrice: 4.20,  avgPrice: 4.80,  supplier: 'CEAGESP Box 12' },
  { id: 'P-007', code: '7891006', name: 'Batata Inglesa',             cat: 'hortifruti', unit: 'kg',    brand: 'In natura',      stock: 65, min: 50, lastPrice: 4.90,  avgPrice: 5.40,  supplier: 'Hortifruti Norte' },
  { id: 'P-008', code: '7894900', name: 'Cerveja Heineken 600ml',     cat: 'bebidas',    unit: 'cx 12', brand: 'Heineken',       stock: 22, min: 30, lastPrice: 78.00, avgPrice: 82.50, supplier: 'AmBev Distrib' },
  { id: 'P-009', code: '7894901', name: 'Cerveja Original 600ml',     cat: 'bebidas',    unit: 'cx 12', brand: 'Antarctica',     stock: 18, min: 20, lastPrice: 65.40, avgPrice: 68.90, supplier: 'AmBev Distrib' },
  { id: 'P-010', code: '7894902', name: 'Refrigerante Coca 2L',       cat: 'bebidas',    unit: 'cx 6',  brand: 'Coca-Cola',      stock: 28, min: 40, lastPrice: 48.00, avgPrice: 51.20, supplier: 'Coca-Cola FEMSA' },
  { id: 'P-011', code: '7894903', name: 'Água Mineral 500ml',         cat: 'bebidas',    unit: 'cx 12', brand: 'Crystal',        stock: 12, min: 30, lastPrice: 14.50, avgPrice: 16.20, supplier: 'Crystal Águas' },
  { id: 'P-012', code: '7894904', name: 'Vinho Tinto Casa Valduga',   cat: 'bebidas',    unit: 'un',    brand: 'Casa Valduga',   stock: 9,  min: 12, lastPrice: 89.90, avgPrice: 94.00, supplier: 'Decanter Wines' },
  { id: 'P-013', code: '7896500', name: 'Azeite Extra Virgem 500ml',  cat: 'secos',      unit: 'un',    brand: 'Andorinha',      stock: 11, min: 18, lastPrice: 32.80, avgPrice: 36.20, supplier: 'Andorinha Brasil' },
  { id: 'P-014', code: '7896501', name: 'Arroz Tio João 5kg',         cat: 'secos',      unit: 'pct',   brand: 'Tio João',       stock: 26, min: 20, lastPrice: 28.40, avgPrice: 30.50, supplier: 'Camil Atacado' },
  { id: 'P-015', code: '7896502', name: 'Feijão Carioca 1kg',         cat: 'secos',      unit: 'pct',   brand: 'Camil',          stock: 34, min: 40, lastPrice: 8.20,  avgPrice: 9.10,  supplier: 'Camil Atacado' },
  { id: 'P-016', code: '7896503', name: 'Sal Refinado 1kg',           cat: 'secos',      unit: 'pct',   brand: 'Cisne',          stock: 19, min: 15, lastPrice: 3.80,  avgPrice: 4.10,  supplier: 'Cisne Sais' },
  { id: 'P-017', code: '7896504', name: 'Açúcar Cristal 5kg',         cat: 'secos',      unit: 'pct',   brand: 'União',          stock: 14, min: 20, lastPrice: 22.50, avgPrice: 24.80, supplier: 'União Atacado' },
  { id: 'P-018', code: '7897700', name: 'Queijo Mussarela kg',        cat: 'laticinios', unit: 'kg',    brand: 'Tirolez',        stock: 17, min: 25, lastPrice: 34.20, avgPrice: 37.80, supplier: 'Tirolez Direto' },
  { id: 'P-019', code: '7897701', name: 'Leite Integral 1L',          cat: 'laticinios', unit: 'cx 12', brand: 'Itambé',         stock: 13, min: 20, lastPrice: 58.00, avgPrice: 62.40, supplier: 'Itambé Atacado' },
  { id: 'P-020', code: '7897702', name: 'Manteiga com Sal 200g',      cat: 'laticinios', unit: 'un',    brand: 'Aviação',        stock: 22, min: 18, lastPrice: 12.40, avgPrice: 13.20, supplier: 'Aviação Premium' },
  { id: 'P-021', code: '7898800', name: 'Detergente Neutro 5L',       cat: 'limpeza',    unit: 'gl',    brand: 'Ypê',            stock: 6,  min: 12, lastPrice: 28.40, avgPrice: 31.20, supplier: 'Limpar Já' },
  { id: 'P-022', code: '7898801', name: 'Álcool 70º 5L',              cat: 'limpeza',    unit: 'gl',    brand: 'Itajá',          stock: 10, min: 15, lastPrice: 38.00, avgPrice: 41.50, supplier: 'Limpar Já' },
  { id: 'P-023', code: '7899900', name: 'Guardanapo Folha Dupla',     cat: 'descartaveis', unit: 'fdo 50', brand: 'Mili',         stock: 11, min: 20, lastPrice: 18.20, avgPrice: 19.80, supplier: 'Embalux SP' },
  { id: 'P-024', code: '7899901', name: 'Copo Descartável 200ml',     cat: 'descartaveis', unit: 'pct 100', brand: 'Copobras',    stock: 8, min: 15, lastPrice: 6.20, avgPrice: 7.10, supplier: 'Embalux SP' },
  { id: 'P-025', code: '7895500', name: 'Pão Francês Congelado',      cat: 'paes',       unit: 'kg',    brand: 'Panco',          stock: 24, min: 20, lastPrice: 14.50, avgPrice: 15.20, supplier: 'Panificadora Real' },
];

const SUPPLIERS = [
  { id: 'F-01', name: 'Friboi Distribuidora',  cnpj: '02.916.265/0001-60', city: 'São Paulo · SP',  cats: ['carnes'], score: 92, wins: 48, response: 96, status: 'Ativo',  avgDelivery: '24h', contact: 'Carlos M.', whats: '(11) 9 8821-4499', email: 'comercial@friboi.com.br', address: 'Av. Marginal Tietê, 1500 · Vila Maria · São Paulo · SP · CEP 02112-000' },
  { id: 'F-02', name: 'JBS Premium',           cnpj: '02.916.265/0001-61', city: 'Barueri · SP',    cats: ['carnes'], score: 88, wins: 32, response: 91, status: 'Ativo',  avgDelivery: '24h', contact: 'Renato P.', whats: '(11) 9 8542-1027', email: 'pedidos@jbspremium.com', address: 'Rod. Castelo Branco, km 27 · Barueri · SP · CEP 06420-000' },
  { id: 'F-03', name: 'Sadia Atacado',         cnpj: '20.730.099/0001-94', city: 'São Paulo · SP',  cats: ['carnes', 'laticinios'], score: 85, wins: 21, response: 88, status: 'Ativo',  avgDelivery: '48h', contact: 'Beatriz L.', whats: '(11) 9 9112-8800', email: 'b.lima@sadia.com.br', address: 'R. Joaquim Floriano, 920 · Itaim Bibi · São Paulo · SP · CEP 04534-002' },
  { id: 'F-04', name: 'CEAGESP Box 12',        cnpj: '14.829.471/0001-08', city: 'São Paulo · SP',  cats: ['hortifruti'], score: 76, wins: 38, response: 82, status: 'Ativo',  avgDelivery: '12h', contact: 'Sr. Antônio', whats: '(11) 9 7421-3088', email: 'box12@ceagesp.gov.br', address: 'Av. Dr. Gastão Vidigal, 1946 · Vila Leopoldina · São Paulo · SP · CEP 05316-900' },
  { id: 'F-05', name: 'Sítio Verde',           cnpj: '21.554.872/0001-10', city: 'Mogi das Cruzes · SP', cats: ['hortifruti'], score: 81, wins: 16, response: 94, status: 'Ativo',  avgDelivery: '12h', contact: 'Dona Helena', whats: '(11) 9 8830-7122', email: 'helena@sitioverde.com.br', address: 'Estrada do Taboão, s/n · Zona Rural · Mogi das Cruzes · SP · CEP 08725-000' },
  { id: 'F-06', name: 'Hortifruti Norte',      cnpj: '11.448.221/0001-44', city: 'Guarulhos · SP',  cats: ['hortifruti'], score: 68, wins: 12, response: 74, status: 'Em Avaliação', avgDelivery: '24h', contact: 'José A.', whats: '(11) 9 9221-4400', email: 'contato@hortifrutinorte.com', address: 'R. das Hortências, 88 · Cumbica · Guarulhos · SP · CEP 07182-110' },
  { id: 'F-07', name: 'AmBev Distrib',         cnpj: '07.526.557/0001-00', city: 'Jundiaí · SP',    cats: ['bebidas'], score: 95, wins: 54, response: 98, status: 'Ativo',  avgDelivery: '48h', contact: 'Equipe AmBev', whats: '(11) 4 0040-7700', email: 'b2b@ambev.com.br', address: 'R. Dr. Renato Paes de Barros, 1017 · Itaim Bibi · São Paulo · SP · CEP 04530-001' },
  { id: 'F-08', name: 'Coca-Cola FEMSA',       cnpj: '47.866.934/0001-74', city: 'Itapecerica · SP', cats: ['bebidas'], score: 90, wins: 27, response: 95, status: 'Ativo',  avgDelivery: '48h', contact: 'Atendimento', whats: '0800 770 2622', email: 'sac@kof.com.mx', address: 'Av. Pres. Juscelino Kubitschek, 1455 · Vila Nova Conceição · São Paulo · SP · CEP 04543-011' },
  { id: 'F-09', name: 'Crystal Águas',         cnpj: '60.409.075/0001-52', city: 'Caçapava · SP',   cats: ['bebidas'], score: 79, wins: 14, response: 86, status: 'Ativo',  avgDelivery: '24h', contact: 'Lúcia S.', whats: '(12) 9 8001-2244', email: 'comercial@crystal.com.br', address: 'Rod. Pres. Dutra, km 132 · Caçapava · SP · CEP 12281-000' },
  { id: 'F-10', name: 'Decanter Wines',        cnpj: '88.121.745/0001-22', city: 'São Paulo · SP',  cats: ['bebidas'], score: 87, wins: 9,  response: 92, status: 'Ativo',  avgDelivery: '72h', contact: 'Marcelo V.', whats: '(11) 9 7700-3120', email: 'marcelo@decanterwines.com.br', address: 'R. Pamplona, 1325 · Jardim Paulista · São Paulo · SP · CEP 01405-002' },
  { id: 'F-11', name: 'Andorinha Brasil',      cnpj: '47.123.890/0001-35', city: 'Santos · SP',     cats: ['secos'], score: 84, wins: 22, response: 90, status: 'Ativo',  avgDelivery: '48h', contact: 'Importadora AB', whats: '(13) 3 233-9090', email: 'vendas@andorinha.com.br', address: 'R. Visconde de São Leopoldo, 540 · Vila Belmiro · Santos · SP · CEP 11075-440' },
  { id: 'F-12', name: 'Camil Atacado',         cnpj: '64.904.295/0001-03', city: 'Itaquaquecetuba · SP', cats: ['secos'], score: 89, wins: 29, response: 93, status: 'Ativo',  avgDelivery: '48h', contact: 'Equipe Camil', whats: '(11) 4 770-9900', email: 'atacado@camil.com.br', address: 'Av. Itaquaquecetuba, 2000 · Distrito Industrial · Itaquaquecetuba · SP · CEP 08572-280' },
  { id: 'F-13', name: 'Cisne Sais',            cnpj: '92.110.554/0001-89', city: 'Cabo Frio · RJ',  cats: ['secos'], score: 72, wins: 8,  response: 80, status: 'Ativo',  avgDelivery: '72h', contact: 'Cisne S.A.', whats: '(22) 2 644-7700', email: 'contato@cisnesais.com.br', address: 'Av. Salinas, 1200 · Salinas · Cabo Frio · RJ · CEP 28909-000' },
  { id: 'F-14', name: 'União Atacado',         cnpj: '60.523.211/0001-12', city: 'Limeira · SP',    cats: ['secos'], score: 83, wins: 19, response: 88, status: 'Ativo',  avgDelivery: '48h', contact: 'União Cosan', whats: '(19) 3 555-7800', email: 'atacado@uniaocosan.com.br', address: 'Av. Brasil, 880 · Centro · Limeira · SP · CEP 13480-200' },
  { id: 'F-15', name: 'Tirolez Direto',        cnpj: '44.118.776/0001-50', city: 'Tiete · SP',      cats: ['laticinios'], score: 91, wins: 24, response: 96, status: 'Ativo',  avgDelivery: '48h', contact: 'Pedro T.', whats: '(15) 9 8800-4422', email: 'pedro@tirolez.com.br', address: 'Estrada Tirolez, 100 · Zona Rural · Tietê · SP · CEP 18530-000' },
  { id: 'F-16', name: 'Itambé Atacado',        cnpj: '17.211.339/0001-66', city: 'Pará de Minas · MG', cats: ['laticinios'], score: 86, wins: 18, response: 89, status: 'Ativo',  avgDelivery: '72h', contact: 'Equipe Itambé', whats: '(31) 3 233-2200', email: 'b2b@itambe.com.br', address: 'Av. dos Lácteos, 2500 · Distrito Industrial · Pará de Minas · MG · CEP 35660-000' },
  { id: 'F-17', name: 'Aviação Premium',       cnpj: '52.330.097/0001-18', city: 'Patrocínio · MG', cats: ['laticinios'], score: 80, wins: 11, response: 85, status: 'Ativo',  avgDelivery: '72h', contact: 'Sandra M.', whats: '(34) 9 8442-6611', email: 'sandra@aviacaopremium.com.br', address: 'Fazenda Aviação · Zona Rural · Patrocínio · MG · CEP 38740-000' },
  { id: 'F-18', name: 'Limpar Já',             cnpj: '67.881.220/0001-09', city: 'Diadema · SP',    cats: ['limpeza'], score: 74, wins: 13, response: 81, status: 'Ativo',  avgDelivery: '48h', contact: 'Roberto F.', whats: '(11) 9 8221-7700', email: 'pedidos@limparja.com.br', address: 'R. das Indústrias, 1450 · Centro · Diadema · SP · CEP 09910-410' },
  { id: 'F-19', name: 'Embalux SP',            cnpj: '33.220.991/0001-77', city: 'São Bernardo · SP', cats: ['descartaveis'], score: 78, wins: 17, response: 84, status: 'Ativo',  avgDelivery: '48h', contact: 'Comercial EB', whats: '(11) 4 332-8800', email: 'vendas@embalux.com.br', address: 'Av. Faria Lima, 4500 · Itaim Bibi · São Paulo · SP · CEP 04538-132' },
  { id: 'F-20', name: 'Panificadora Real',     cnpj: '21.119.802/0001-44', city: 'Mogi das Cruzes · SP', cats: ['paes'], score: 88, wins: 15, response: 94, status: 'Ativo',  avgDelivery: '24h', contact: 'João R.', whats: '(11) 9 7330-2299', email: 'joao@panreal.com.br', address: 'R. Coronel Almeida, 220 · Centro · Mogi das Cruzes · SP · CEP 08710-000' },
  { id: 'F-21', name: 'Mercado Premium Vix',   cnpj: '09.443.221/0001-31', city: 'Vitória · ES',    cats: ['hortifruti', 'secos'], score: 65, wins: 4,  response: 70, status: 'Em Avaliação', avgDelivery: '96h', contact: 'Marcos V.', whats: '(27) 9 8721-3300', email: 'marcos@premiumvix.com.br', address: 'Av. Beira-Mar, 1800 · Praia do Canto · Vitória · ES · CEP 29055-110' },
  { id: 'F-22', name: 'Frigorífico Sul',       cnpj: '78.221.443/0001-25', city: 'Pelotas · RS',    cats: ['carnes'], score: 55, wins: 2,  response: 60, status: 'Bloqueado', avgDelivery: '120h', contact: 'Frigo Sul', whats: '(53) 3 222-7700', email: 'comercial@frigosul.com.br', address: 'Av. Bento Gonçalves, 4500 · Centro · Pelotas · RS · CEP 96015-560' },
];

// Bids for the active quotation (the showcase)
const ACTIVE_QUOTATION = {
  id: 'COT-2026-0148',
  title: 'Cotação Semanal · Bebidas e Hortifruti',
  status: 'aberta', // aberta · analise · fechada
  createdAt: '13/05/2026 09:14',
  deadline: '15/05/2026 18:00',
  buyer: 'José Alberto',
  obs: 'Pagamento 28 dias · Entrega na Rua Carlos Gomes, 1244 · Receber entre 8h e 11h',
  items: [
    { id: 'P-008', name: 'Cerveja Heineken 600ml',  unit: 'cx 12',  qty: 30, lastPrice: 78.00 },
    { id: 'P-009', name: 'Cerveja Original 600ml',  unit: 'cx 12',  qty: 20, lastPrice: 65.40 },
    { id: 'P-010', name: 'Refrigerante Coca 2L',    unit: 'cx 6',   qty: 40, lastPrice: 48.00 },
    { id: 'P-011', name: 'Água Mineral 500ml',      unit: 'cx 12',  qty: 30, lastPrice: 14.50 },
    { id: 'P-004', name: 'Tomate Italiano',         unit: 'kg',     qty: 30, lastPrice: 6.80  },
    { id: 'P-005', name: 'Alface Crespa',           unit: 'pé',     qty: 24, lastPrice: 2.50  },
    { id: 'P-006', name: 'Cebola Branca',           unit: 'kg',     qty: 20, lastPrice: 4.20  },
    { id: 'P-007', name: 'Batata Inglesa',          unit: 'kg',     qty: 50, lastPrice: 4.90  },
  ],
  suppliers: ['F-07', 'F-08', 'F-09', 'F-10', 'F-04', 'F-05', 'F-06'],
  bids: {
    // sup-id -> { product-id: { price, alt, notes, status } }
    'F-07': { // AmBev — bebidas
      _status: 'respondida', _at: '13/05 14:22',
      'P-008': { price: 75.40 },
      'P-009': { price: 63.20 },
      'P-010': { price: null, skip: true },
      'P-011': { price: 13.80 },
    },
    'F-08': { // Coca-Cola FEMSA — bebidas
      _status: 'respondida', _at: '13/05 16:08',
      'P-008': { price: null, skip: true },
      'P-009': { price: null, skip: true },
      'P-010': { price: 45.20 },
      'P-011': { price: null, skip: true },
    },
    'F-09': { // Crystal — bebidas
      _status: 'respondida', _at: '14/05 09:55',
      'P-008': { price: null, skip: true },
      'P-009': { price: null, skip: true },
      'P-010': { price: 49.50 },
      'P-011': { price: 12.90 },
    },
    'F-10': { // Decanter — bebidas premium (cervejas premium)
      _status: 'respondida', _at: '14/05 11:12',
      'P-008': { price: 77.20, alt: 'Heineken Long Neck 330ml cx 24' },
      'P-009': { price: 64.90 },
      'P-010': { price: null, skip: true },
      'P-011': { price: null, skip: true },
    },
    'F-04': { // CEAGESP — hortifruti
      _status: 'respondida', _at: '13/05 11:40',
      'P-004': { price: 6.20 },
      'P-005': { price: 2.30 },
      'P-006': { price: 3.80 },
      'P-007': { price: 4.70 },
    },
    'F-05': { // Sítio Verde — hortifruti
      _status: 'respondida', _at: '13/05 18:30',
      'P-004': { price: 5.90 },
      'P-005': { price: 2.10 },
      'P-006': { price: 4.10 },
      'P-007': { price: 4.95 },
    },
    'F-06': { // Hortifruti Norte — pendente
      _status: 'pendente', _at: null,
    },
  },
};

// Other quotations (list page)
const QUOTATIONS = [
  { id: 'COT-2026-0148', title: 'Cotação Semanal · Bebidas e Hortifruti', status: 'analise', items: 8, suppliers: 7, responded: 6, total: 7820.50, saving: 422.30, deadline: '15/05/2026', createdAt: '13/05/2026' },
  { id: 'COT-2026-0147', title: 'Reposição Carnes — Final de Semana',     status: 'fechada', items: 5, suppliers: 4, responded: 4, total: 12480.00, saving: 1148.00, deadline: '12/05/2026', createdAt: '10/05/2026' },
  { id: 'COT-2026-0146', title: 'Limpeza e Descartáveis · Mensal',         status: 'fechada', items: 12, suppliers: 5, responded: 4, total: 3220.40, saving: 488.20, deadline: '08/05/2026', createdAt: '05/05/2026' },
  { id: 'COT-2026-0145', title: 'Laticínios — Reposição Semanal',          status: 'fechada', items: 6, suppliers: 4, responded: 4, total: 4180.90, saving: 312.50, deadline: '06/05/2026', createdAt: '04/05/2026' },
  { id: 'COT-2026-0144', title: 'Cotação Express · Frutas',                status: 'aberta',  items: 4, suppliers: 3, responded: 1, total: null,    saving: null,    deadline: '16/05/2026', createdAt: '13/05/2026' },
  { id: 'COT-2026-0143', title: 'Secos e Molhados · Estoque Geral',        status: 'fechada', items: 14, suppliers: 6, responded: 5, total: 6840.10, saving: 924.80, deadline: '02/05/2026', createdAt: '29/04/2026' },
  { id: 'COT-2026-0142', title: 'Bebidas Premium · Carta de Vinhos',       status: 'fechada', items: 9, suppliers: 4, responded: 3, total: 8990.00, saving: 380.00, deadline: '28/04/2026', createdAt: '26/04/2026' },
  { id: 'COT-2026-0141', title: 'Cerveja · Reposição Urgente',             status: 'cancelada', items: 3, suppliers: 2, responded: 1, total: null, saving: null,    deadline: '25/04/2026', createdAt: '24/04/2026' },
];

const ORDERS = [
  { id: 'PC-2026-0312', supplier: 'AmBev Distrib',     items: 4,  total: 4530.00, status: 'Em Trânsito', eta: '15/05/2026', emitido: '13/05/2026', cotacao: 'COT-2026-0148' },
  { id: 'PC-2026-0311', supplier: 'Sítio Verde',       items: 3,  total: 322.80,  status: 'Confirmado', eta: '14/05/2026', emitido: '13/05/2026', cotacao: 'COT-2026-0148' },
  { id: 'PC-2026-0310', supplier: 'CEAGESP Box 12',    items: 4,  total: 568.40,  status: 'Entregue',  eta: '13/05/2026', emitido: '12/05/2026', cotacao: 'COT-2026-0148' },
  { id: 'PC-2026-0309', supplier: 'Friboi Distribuidora', items: 3, total: 5288.20, status: 'Entregue', eta: '12/05/2026', emitido: '10/05/2026', cotacao: 'COT-2026-0147' },
  { id: 'PC-2026-0308', supplier: 'JBS Premium',       items: 2,  total: 7191.80, status: 'Entregue',  eta: '12/05/2026', emitido: '10/05/2026', cotacao: 'COT-2026-0147' },
  { id: 'PC-2026-0307', supplier: 'Limpar Já',         items: 6,  total: 1822.40, status: 'Entregue',  eta: '09/05/2026', emitido: '05/05/2026', cotacao: 'COT-2026-0146' },
  { id: 'PC-2026-0306', supplier: 'Embalux SP',        items: 6,  total: 1398.00, status: 'Cancelado', eta: '—',          emitido: '05/05/2026', cotacao: 'COT-2026-0146' },
  { id: 'PC-2026-0305', supplier: 'Tirolez Direto',    items: 3,  total: 2480.00, status: 'Entregue',  eta: '07/05/2026', emitido: '04/05/2026', cotacao: 'COT-2026-0145' },
  { id: 'PC-2026-0304', supplier: 'Itambé Atacado',    items: 2,  total: 1100.90, status: 'Entregue',  eta: '07/05/2026', emitido: '04/05/2026', cotacao: 'COT-2026-0145' },
  { id: 'PC-2026-0303', supplier: 'Aviação Premium',   items: 1,  total: 600.00,  status: 'Entregue',  eta: '07/05/2026', emitido: '04/05/2026', cotacao: 'COT-2026-0145' },
];

// Monthly savings (last 6 months)
const SAVINGS_HISTORY = [
  { m: 'Dez/25', value: 2890, quotes: 18 },
  { m: 'Jan/26', value: 3210, quotes: 22 },
  { m: 'Fev/26', value: 4150, quotes: 24 },
  { m: 'Mar/26', value: 3680, quotes: 21 },
  { m: 'Abr/26', value: 5240, quotes: 28 },
  { m: 'Mai/26', value: 4422, quotes: 19 },
];

const SAVINGS_HISTORY_12M = [
  { m: 'Jun/25', value: 1820, quotes: 12 },
  { m: 'Jul/25', value: 2110, quotes: 14 },
  { m: 'Ago/25', value: 2480, quotes: 16 },
  { m: 'Set/25', value: 2740, quotes: 17 },
  { m: 'Out/25', value: 3050, quotes: 19 },
  { m: 'Nov/25', value: 2630, quotes: 16 },
  { m: 'Dez/25', value: 2890, quotes: 18 },
  { m: 'Jan/26', value: 3210, quotes: 22 },
  { m: 'Fev/26', value: 4150, quotes: 24 },
  { m: 'Mar/26', value: 3680, quotes: 21 },
  { m: 'Abr/26', value: 5240, quotes: 28 },
  { m: 'Mai/26', value: 4422, quotes: 19 },
];

const SAVINGS_HISTORY_YEAR = [
  { m: '2023', value: 18420, quotes: 142 },
  { m: '2024', value: 24890, quotes: 188 },
  { m: '2025', value: 31420, quotes: 224 },
  { m: '2026 YTD', value: 20702, quotes: 114 },
];

// Distribution by category (last 30 days)
const CATEGORY_SHARE = [
  { cat: 'carnes', label: 'Carnes', value: 18420, tone: 'coral' },
  { cat: 'bebidas', label: 'Bebidas', value: 14820, tone: 'sky' },
  { cat: 'hortifruti', label: 'Hortifruti', value: 6420, tone: 'emerald' },
  { cat: 'secos', label: 'Secos', value: 5210, tone: 'amber' },
  { cat: 'laticinios', label: 'Laticínios', value: 4720, tone: 'amber' },
  { cat: 'limpeza', label: 'Limpeza', value: 2280, tone: 'violet' },
  { cat: 'descartaveis', label: 'Descartáveis', value: 1410, tone: 'sky' },
];

// Top winners + most quoted
const TOP_SUPPLIERS = [
  { name: 'AmBev Distrib',        wins: 54, share: 100 },
  { name: 'Friboi Distribuidora', wins: 48, share: 89 },
  { name: 'CEAGESP Box 12',       wins: 38, share: 70 },
  { name: 'JBS Premium',          wins: 32, share: 59 },
  { name: 'Camil Atacado',        wins: 29, share: 54 },
  { name: 'Coca-Cola FEMSA',      wins: 27, share: 50 },
  { name: 'Tirolez Direto',       wins: 24, share: 44 },
  { name: 'Andorinha Brasil',     wins: 22, share: 41 },
  { name: 'Sadia Atacado',        wins: 21, share: 39 },
  { name: 'União Atacado',        wins: 19, share: 35 },
];

const TOP_PRODUCTS = [
  { name: 'Cerveja Heineken 600ml',  quotes: 18, vol: 540 },
  { name: 'Filé Mignon Bovino',      quotes: 16, vol: 320 },
  { name: 'Tomate Italiano',         quotes: 15, vol: 460 },
  { name: 'Queijo Mussarela',        quotes: 14, vol: 280 },
  { name: 'Refrigerante Coca 2L',    quotes: 13, vol: 380 },
  { name: 'Cerveja Original 600ml',  quotes: 12, vol: 420 },
  { name: 'Frango Inteiro',          quotes: 11, vol: 310 },
  { name: 'Arroz Tio João 5kg',      quotes: 10, vol: 240 },
  { name: 'Picanha Maturada',        quotes:  9, vol: 180 },
  { name: 'Azeite Extra Virgem',     quotes:  9, vol: 210 },
];

// Distribution by supplier (last 30 days)
const SUPPLIER_SHARE = [
  { sid: 'F-07', label: 'AmBev Distrib',        value: 12480, tone: 'sky'     },
  { sid: 'F-01', label: 'Friboi Distribuidora', value: 10220, tone: 'coral'   },
  { sid: 'F-04', label: 'CEAGESP Box 12',       value:  5240, tone: 'emerald' },
  { sid: 'F-02', label: 'JBS Premium',          value:  7388, tone: 'coral'   },
  { sid: 'F-12', label: 'Camil Atacado',        value:  3120, tone: 'amber'   },
  { sid: 'F-15', label: 'Tirolez Direto',       value:  2480, tone: 'amber'   },
  { sid: 'F-08', label: 'Coca-Cola FEMSA',      value:  2340, tone: 'sky'     },
  { sid: 'F-18', label: 'Limpar Já',            value:  1822, tone: 'violet'  },
];

// Price evolution for "Filé Mignon" — line chart
const PRICE_HISTORY = [
  { d: '12 sem', v: 86.40 },
  { d: '10 sem', v: 84.20 },
  { d: '8 sem',  v: 88.10 },
  { d: '6 sem',  v: 85.50 },
  { d: '4 sem',  v: 81.20 },
  { d: '2 sem',  v: 79.80 },
  { d: 'agora',  v: 78.90 },
];

// Alerts feed
const ALERTS = [
  { id: 1, kind: 'estoque',  text: 'Detergente Neutro 5L abaixo do mínimo (6 / 12)', at: 'há 5 min', tone: 'amber' },
  { id: 2, kind: 'cotacao',  text: 'COT-2026-0144 sem resposta de 2 fornecedores', at: 'há 1h', tone: 'amber' },
  { id: 3, kind: 'pedido',   text: 'PC-2026-0312 entregue parcialmente — 2 itens em divergência', at: 'há 2h', tone: 'coral' },
  { id: 4, kind: 'ia',       text: 'IA sugere fechar COT-2026-0148 com economia de R$ 422,30', at: 'há 3h', tone: 'emerald' },
  { id: 5, kind: 'fornec',   text: 'Hortifruti Norte ainda não respondeu — lembrete enviado', at: 'há 4h', tone: 'amber' },
];

// Notifications feed
const NOTIFICATIONS = [
  { id: 1, icon: 'sparkle', title: 'IA finalizou análise de COT-2026-0148', sub: 'Economia projetada: R$ 422,30 (5,4%)', at: '14:08', tone: 'emerald', unread: true },
  { id: 2, icon: 'truck',   title: 'PC-2026-0312 em trânsito',              sub: 'AmBev Distrib · previsão 15/05 às 09h',  at: '13:42', tone: 'sky',     unread: true },
  { id: 3, icon: 'reply',   title: 'Sítio Verde respondeu COT-2026-0148',   sub: '4 itens preenchidos',                    at: '13:30', tone: 'emerald', unread: true },
  { id: 4, icon: 'warn',    title: 'Estoque crítico: 3 produtos',           sub: 'Sugerimos abrir nova cotação',           at: '11:15', tone: 'amber',   unread: false },
  { id: 5, icon: 'check',   title: 'PC-2026-0310 entregue',                 sub: 'CEAGESP Box 12 · conferência ok',        at: 'ontem', tone: 'emerald', unread: false },
];

// === Stock receivings ===
const RECEIVINGS = [
  { id: 'REC-0118', order: 'PC-2026-0310', supplier: 'CEAGESP Box 12', items: 4, status: 'Aprovado',   div: 0, at: '13/05 09:40' },
  { id: 'REC-0117', order: 'PC-2026-0312', supplier: 'AmBev Distrib',  items: 4, status: 'Pendente',   div: 2, at: '—' },
  { id: 'REC-0116', order: 'PC-2026-0309', supplier: 'Friboi Distrib.', items: 3, status: 'Aprovado',   div: 1, at: '12/05 07:55' },
  { id: 'REC-0115', order: 'PC-2026-0308', supplier: 'JBS Premium',    items: 2, status: 'Aprovado',   div: 0, at: '12/05 08:10' },
  { id: 'REC-0114', order: 'PC-2026-0307', supplier: 'Limpar Já',      items: 6, status: 'Aprovado',   div: 0, at: '09/05 14:22' },
];

// === Period filter (dashboard) ===
// Reference "today" for relative date filtering on the dashboard.
const TODAY = new Date(2026, 4, 15); // Maio = month 4 (0-indexed)

// Parse "DD/MM/YYYY" -> Date
const parseBR = (s) => {
  if (!s) return null;
  const [d, m, y] = s.split('/').map(Number);
  return new Date(y, m - 1, d);
};

const daysBetween = (a, b) => Math.floor((a - b) / 86400000);

const PERIODS = {
  hoje:  { label: 'Hoje',     mult: 0.04, days: 1,  sub: 'Hoje',                 short: 'hoje',     compare: '0%' },
  '7d':  { label: '7 dias',   mult: 0.22, days: 7,  sub: 'Últimos 7 dias',       short: '7d',       compare: '-2% vs. anterior' },
  '30d': { label: '30 dias',  mult: 1,    days: 30, sub: 'Últimos 30 dias',      short: '30d',      compare: '+18% vs. anterior' },
  '90d': { label: '90 dias',  mult: 3.1,  days: 90, sub: 'Últimos 90 dias',      short: '90d',      compare: '+27% vs. anterior' },
};

// Filter the quotations table rows by createdAt within N days from TODAY.
const filterQuotationsByDays = (rows, days) => {
  return rows.filter(q => {
    const d = parseBR(q.createdAt);
    if (!d) return true;
    const diff = daysBetween(TODAY, d);
    return diff >= 0 && diff <= days;
  });
};

// "kind" of alert -> destination route on the SPA
const ALERT_ROUTE = {
  estoque: 'stock',
  cotacao: 'quotations',
  pedido:  'orders',
  ia:      'quotationDetail', // routed via openQuotation
  fornec:  'suppliers',
};

// "cat" key (donut) -> products screen category context
const CATEGORY_ROUTE = 'reports';

window.SCP = {
  BRL, BRLk, pad,
  COMPANY, CATEGORIES, PRODUCTS, SUPPLIERS,
  ACTIVE_QUOTATION, QUOTATIONS, ORDERS, RECEIVINGS,
  SAVINGS_HISTORY, SAVINGS_HISTORY_12M, SAVINGS_HISTORY_YEAR,
  CATEGORY_SHARE, SUPPLIER_SHARE, TOP_SUPPLIERS, TOP_PRODUCTS, PRICE_HISTORY,
  ALERTS, NOTIFICATIONS,
  PERIODS, TODAY, filterQuotationsByDays, parseBR, daysBetween,
  ALERT_ROUTE, CATEGORY_ROUTE,
};
