// Shared stock + i18n strings.
//
// ─────────────────────────────────────────────────────────────────────
// GOOGLE SHEETS — jak podłączyć stronę do swojego arkusza
// ─────────────────────────────────────────────────────────────────────
// 1) W Google Sheets załóż arkusz z dokładnie tymi kolumnami w nagłówku:
//
//       SKU         Nazwa         Zdjęcie                    Dostępność
//       STK-0421    Mind 001 …    https://drive.google.com…  Dostępne
//
//    Wartości w kolumnie "Dostępność":
//      • "Dostępne" / "Możliwe do zamówienia" / "available"
//          → wyświetla się jako „Możliwe do zamówienia"
//      • "Chwilowy brak" / "Brak" / "oos"
//          → wyświetla się jako „Chwilowy brak" (na stocku)
//
//    Wartości w kolumnie "Zdjęcie": link do pliku z grafiką.
//      • Google Drive: udostępnij plik "Każdy z linkiem", potem wklej
//        link (typu https://drive.google.com/file/d/XXXXX/view).
//        Strona sama go zamieni na działający.
//      • Albo bezpośredni URL do .png / .jpg / .webp.
//
// 2) Plik → Udostępnij → Opublikuj w internecie →
//    Wybierz arkusz → "Wartości oddzielone przecinkami (.csv)" → Opublikuj.
//    Skopiuj wygenerowany URL.
//
// 3) Wklej ten URL poniżej w SHEETS_CSV_URL i zapisz plik.
//    Tyle. Strona od tej pory ciągnie produkty z arkusza.
//
// 4) Gdy SHEETS_CSV_URL jest pusty (lub strona otwierana offline jako
//    załącznik mailowy), używany jest stock zaszyty na stałe w pliku.

const SHEETS_CSV_URL = 'https://docs.google.com/spreadsheets/d/1tmg85Dq97hvkWTtA3MuI36FlFihwrVe30K0qhD53ebc/gviz/tq?tqx=out:csv';   // ← URL CSV z Google Sheets

// ─────────────────────────────────────────────────────────────────────

// Fallback stock — używany gdy SHEETS_CSV_URL jest pusty, albo gdy
// pobranie z arkusza się nie powiedzie (np. offline).
const STOCK = [
  { code: 'STK-0421', model: 'Mind 001 · Black',          imgKey: 'mind-black',   bg: '#ebe6dc', availability: 'available' },
  { code: 'STK-0418', model: 'Mind 001 · Red',            imgKey: 'mind-red',     bg: '#f7d7d2', availability: 'available' },
  { code: 'STK-0414', model: 'Jordan 4 · Dark Mocha',     imgKey: 'jordan4-dark', bg: '#e8e3dd', availability: 'available' },
  { code: 'STK-0410', model: 'Jordan 4 · Red Cement',     imgKey: 'jordan4-red',  bg: '#f7ece4', availability: 'available' },
  { code: 'STK-0407', model: 'Mind 001 · Mint',           imgKey: 'mind-mint',    bg: '#e6f5ec', availability: 'available' },
  { code: 'STK-0402', model: 'Mind 001 · Pink',           imgKey: 'mind-pink',    bg: '#f7e8e8', availability: 'oos'       },
  { code: 'STK-0398', model: 'Mind 001 · Grey',           imgKey: 'mind-grey',    bg: '#ecebe9', availability: 'available' },
  { code: 'STK-0395', model: 'Mind 001 · Green',          imgKey: 'mind-green',   bg: '#dde9e3', availability: 'available' },
];

// Resolve image source: prefer the base64 dictionary baked into the
// bundle (window.IMAGES) so the file is offline-safe; fall back to the
// regular product path or an arbitrary URL coming from Sheets.
function resolveImg(item) {
  if (!item) return null;
  if (item.img) return item.img;
  if (item.imgKey) {
    if (typeof window !== 'undefined' && window.IMAGES && window.IMAGES[item.imgKey]) {
      return window.IMAGES[item.imgKey];
    }
    return `products/${item.imgKey}.webp`;
  }
  return null;
}

// — Google Sheets CSV loader —————————————————————————————
// Parses a small CSV string into a list of objects keyed by header.
// Handles quoted fields with embedded commas / newlines / double-quotes.
function parseCSV(text) {
  const rows = [];
  let cur = ''; let row = []; let q = false;
  for (let i = 0; i < text.length; i++) {
    const c = text[i], n = text[i+1];
    if (q) {
      if (c === '"' && n === '"') { cur += '"'; i++; }
      else if (c === '"') { q = false; }
      else { cur += c; }
    } else {
      if (c === '"') q = true;
      else if (c === ',') { row.push(cur); cur = ''; }
      else if (c === '\r') { /* skip */ }
      else if (c === '\n') { row.push(cur); rows.push(row); cur = ''; row = []; }
      else cur += c;
    }
  }
  if (cur.length || row.length) { row.push(cur); rows.push(row); }
  if (!rows.length) return [];
  const headers = rows[0].map(h => h.trim().toLowerCase());
  return rows.slice(1).filter(r => r.some(c => c && c.trim())).map(r => {
    const o = {};
    headers.forEach((h, i) => o[h] = (r[i] || '').trim());
    return o;
  });
}

// Convert a Google Drive share URL into a format that works for
// hot-linking <img src>. Google blocks drive.google.com/thumbnail
// for many embeds now, but the Google-CDN endpoint
// https://lh3.googleusercontent.com/d/<ID>=w800 stays reliable
// (it's what Drive itself serves preview thumbnails from). Handles:
//   • /file/d/<ID>/view              (manual share link)
//   • /uc?export=…&id=<ID>           (Apps Script download URL)
//   • /thumbnail?id=<ID>             (older bot output)
//   • lh3.googleusercontent.com URLs (pass through)
//   • bare http(s)://… image URLs    (pass through)
function normalizeImageUrl(url) {
  if (!url) return null;
  if (/lh3\.googleusercontent\.com/.test(url)) return url;
  // /file/d/<ID>/view
  let m = url.match(/drive\.google\.com\/file\/d\/([^/?]+)/);
  if (m) return `https://lh3.googleusercontent.com/d/${m[1]}=w1200`;
  // /thumbnail?id=<ID> or /uc?id=<ID>
  m = url.match(/[?&]id=([^&]+)/);
  if (m && /drive\.google\.com/.test(url)) return `https://lh3.googleusercontent.com/d/${m[1]}=w1200`;
  // /open?id=<ID>
  m = url.match(/drive\.google\.com\/open\?id=([^&]+)/);
  if (m) return `https://lh3.googleusercontent.com/d/${m[1]}=w1200`;
  return url;
}

// Map a header row's cells (case-insensitive, PL+EN names) to our schema.
// Designed for the live ad sheet which has the following columns:
//   SEND | STATUS | DETECTED AT | THUMBNAIL | FILE NAME | FILE ID |
//   IMAGE URL | PRODUCT | SKU | PRICE PLN | … | AVAILABILITY
// We accept both that layout and a simpler {Nazwa, SKU, Zdjęcie,
// Dostępność} layout, so the integration survives the user renaming
// columns later.
function rowToStockItem(r) {
  const get = (...keys) => {
    for (const k of keys) {
      if (r[k] !== undefined && r[k] !== '') return r[k];
    }
    return '';
  };
  const status = get('status').toLowerCase();
  const send   = get('send').toLowerCase();
  // Skip placeholder rows that haven't been pushed to Discord yet,
  // or rows the operator explicitly marked SEND=FALSE.
  if (status && status !== 'sent') return null;
  if (send === 'false') return null;

  const av = get('availability','dostępność','dostepnosc','status').toLowerCase();
  const availability =
      /brak|out|oos|sold/.test(av) ? 'oos'
    : 'available';

  const model = get('product','nazwa','model','name');
  if (!model) return null;

  // SKU column is often empty in the ad sheet — fall back to the
  // first few chars of the Drive file id so every card still shows
  // a stable code (and the search box can match it).
  let code = get('sku','kod','code');
  if (!code) {
    const fid = get('file id','fileid','id');
    if (fid) code = 'STK-' + fid.slice(0, 6).toUpperCase();
  }

  return {
    code: code || '',
    model,
    img: normalizeImageUrl(get('image url','image','zdjęcie','zdjecie','foto','photo','link')),
    availability,
    fromSheet: true,
  };
}

async function fetchStockFromSheet(url) {
  if (!url) return null;
  try {
    const res = await fetch(url, { cache: 'no-store' });
    if (!res.ok) return null;
    const text = await res.text();
    const rows = parseCSV(text);
    const items = rows.map(rowToStockItem).filter(Boolean);
    return items.length ? items : null;
  } catch (e) {
    console.warn('[InStock] Nie udało się pobrać arkusza:', e);
    return null;
  }
}

// — localStorage cache —
// We cache the parsed sheet rows so a repeat visit can paint the real
// product list on the FIRST frame, before the sheet fetch completes.
// In the background we still re-fetch and update if anything changed.
// Cache TTL is 7 days — long enough to survive infrequent visitors,
// short enough that stale entries get cleaned up eventually.
const STOCK_CACHE_KEY = 'instock-stock-cache-v2';
const STOCK_CACHE_TTL_MS = 7 * 24 * 60 * 60 * 1000;

function readStockCache() {
  if (typeof localStorage === 'undefined') return null;
  try {
    const raw = localStorage.getItem(STOCK_CACHE_KEY);
    if (!raw) return null;
    const { ts, items } = JSON.parse(raw);
    if (!Array.isArray(items) || items.length === 0) return null;
    if (Date.now() - (ts || 0) > STOCK_CACHE_TTL_MS) return null;
    return items;
  } catch (e) { return null; }
}

function writeStockCache(items) {
  if (typeof localStorage === 'undefined') return;
  try {
    localStorage.setItem(STOCK_CACHE_KEY, JSON.stringify({ ts: Date.now(), items }));
  } catch (e) { /* quota exceeded — ignore */ }
}

// React hook — returns { items, ready }.
//   • If we have a fresh cache, items is populated on the very first
//     render → no skeleton flash on repeat visits.
//   • Otherwise items is [] and ready=false → the UI shows a skeleton.
//   • Sheet fetch runs in background regardless; once it lands we
//     update the list (and refresh the cache).
//   • If the sheet is unreachable AND we have no cache, we fall back
//     to STOCK_SNAPSHOT (the baked offline copy) if present,
//     otherwise to the embedded STOCK list above.
function useStock() {
  const initial = React.useMemo(readStockCache, []);
  const offlineFallback = (typeof window !== 'undefined' && Array.isArray(window.STOCK_SNAPSHOT) && window.STOCK_SNAPSHOT.length)
    ? window.STOCK_SNAPSHOT
    : STOCK;
  const [items, setItems] = React.useState(initial || offlineFallback);
  const [ready, setReady] = React.useState(true);

  React.useEffect(() => {
    let cancelled = false;
    if (!SHEETS_CSV_URL) return;
    fetchStockFromSheet(SHEETS_CSV_URL).then(rows => {
      if (cancelled) return;
      if (rows && rows.length) {
        setItems(rows);
        writeStockCache(rows);
      }
    });
    return () => { cancelled = true; };
  }, []);

  return { items, ready };
}

const FAQ = [
  { q: {
      pl: 'Kto może kupować?',
      en: 'Who can buy?',
      fr: 'Qui peut acheter ?',
      it: 'Chi può acquistare?',
      es: '¿Quién puede comprar?',
      pt: 'Quem pode comprar?',
      cs: 'Kdo může nakupovat?',
      sv: 'Vem kan köpa?',
      da: 'Hvem kan købe?',
      nl: 'Wie kan kopen?',
    },
    a: {
      pl: 'Celujemy we współpracę z zarejestrowanymi sklepami, resellerami i podmiotami B2B z aktywnym NIP / VAT EU. Zgłoszenia detaliczne rozpatrywane indywidualnie.',
      en: 'We focus on cooperation with registered shops, resellers and B2B entities with an active EU VAT number. Retail enquiries handled on a case-by-case basis.',
      fr: 'Nous travaillons avec des boutiques enregistrées, revendeurs et entités B2B disposant d\u2019un numéro de TVA UE actif. Les demandes au détail sont étudiées au cas par cas.',
      it: 'Lavoriamo con negozi registrati, rivenditori ed entità B2B con partita IVA UE attiva. Le richieste al dettaglio sono valutate caso per caso.',
      es: 'Trabajamos con tiendas registradas, revendedores y empresas B2B con NIF / IVA UE activo. Las consultas minoristas se gestionan caso por caso.',
      pt: 'Trabalhamos com lojas registadas, revendedores e entidades B2B com NIF / IVA UE ativo. Pedidos a retalho são tratados caso a caso.',
      cs: 'Spolupracujeme s registrovanými obchody, resellery a B2B subjekty s platným DIČ / EU VAT. Maloobchodní dotazy řešíme individuálně.',
      sv: 'Vi samarbetar med registrerade butiker, återförsäljare och B2B-företag med aktivt EU-VAT. Detaljhandelsfrågor hanteras från fall till fall.',
      da: 'Vi samarbejder med registrerede butikker, forhandlere og B2B-virksomheder med aktivt EU-momsnummer. Detailhenvendelser behandles individuelt.',
      nl: 'We werken met geregistreerde winkels, resellers en B2B-bedrijven met een actief EU-btw-nummer. Particuliere aanvragen behandelen we per geval.',
  } },
  { q: {
      pl: 'Jakie są minimalne zamówienia?',
      en: 'What is the minimum order?',
      fr: 'Quel est le minimum de commande ?',
      it: 'Qual è l\u2019ordine minimo?',
      es: '¿Cuál es el pedido mínimo?',
      pt: 'Qual é o pedido mínimo?',
      cs: 'Jaké je minimální objednávkové množství?',
      sv: 'Vad är minsta orderkvantitet?',
      da: 'Hvad er minimumsbestillingen?',
      nl: 'Wat is de minimale bestelling?',
    },
    a: {
      pl: 'Wszystkie szczegóły odnośnie zamówień znajdziesz na naszym Discordzie oraz WhatsAppie.',
      en: 'All order details are available on our Discord and WhatsApp.',
      fr: 'Tous les détails des commandes sont disponibles sur notre Discord et WhatsApp.',
      it: 'Tutti i dettagli sugli ordini sono disponibili sul nostro Discord e WhatsApp.',
      es: 'Encontrarás todos los detalles sobre pedidos en nuestro Discord y WhatsApp.',
      pt: 'Todos os detalhes sobre encomendas estão no nosso Discord e WhatsApp.',
      cs: 'Veškeré detaily k objednávkám najdete na našem Discordu a WhatsAppu.',
      sv: 'All information om beställningar finns på vår Discord och WhatsApp.',
      da: 'Alle ordredetaljer finder du på vores Discord og WhatsApp.',
      nl: 'Alle bestelinformatie vind je op onze Discord en WhatsApp.',
  } },
  { q: {
      pl: 'Jak działa proces?',
      en: 'How does the process work?',
      fr: 'Comment fonctionne le processus ?',
      it: 'Come funziona il processo?',
      es: '¿Cómo funciona el proceso?',
      pt: 'Como funciona o processo?',
      cs: 'Jak proces funguje?',
      sv: 'Hur fungerar processen?',
      da: 'Hvordan fungerer processen?',
      nl: 'Hoe werkt het proces?',
    },
    a: {
      pl: 'Wybierasz modele, wysyłasz listę WTB, uzgadniamy szczegóły i po opłaceniu nadajemy przesyłkę kurierem. Czas do wysyłki: w PL do 48h roboczych, w EU do 5 dni roboczych (czas kuriera doliczany osobno).',
      en: 'Pick models, send a WTB list, we agree the details, and after payment we hand the parcel over to a courier. Time to dispatch: PL within 48 business hours, EU within 5 business days (courier transit time additional).',
      fr: 'Choisissez les modèles, envoyez la liste WTB, nous convenons des détails, et après paiement nous remettons le colis au transporteur. Délai d\u2019expédition : PL sous 48h ouvrées, UE sous 5 jours ouvrés (transit transporteur en sus).',
      it: 'Scegli i modelli, invii la lista WTB, concordiamo i dettagli e dopo il pagamento consegniamo il pacco al corriere. Tempo di spedizione: PL entro 48h lavorative, UE entro 5 giorni lavorativi (tempo di transito a parte).',
      es: 'Elige los modelos, envía la lista WTB, acordamos los detalles y, tras el pago, entregamos el paquete al transportista. Plazo de envío: PL en 48h laborables, UE en 5 días laborables (transporte aparte).',
      pt: 'Escolhe os modelos, envia a lista WTB, acertamos os detalhes e, após pagamento, entregamos a encomenda à transportadora. Prazo de envio: PL em 48h úteis, UE em 5 dias úteis (transporte à parte).',
      cs: 'Vyberete modely, pošlete WTB seznam, dohodneme detaily a po platbě předáme zásilku kurýrovi. Doba expedice: PL do 48h pracovních, EU do 5 pracovních dnů (doba kurýra navíc).',
      sv: 'Välj modeller, skicka WTB-listan, vi kommer överens om detaljerna och efter betalning lämnar vi paketet till kuriren. Leveranstid: PL inom 48 arbetstimmar, EU inom 5 arbetsdagar (kurirtid tillkommer).',
      da: 'Vælg modeller, send WTB-listen, vi aftaler detaljerne, og efter betaling afleverer vi pakken til kureren. Forsendelsestid: PL inden for 48 arbejdstimer, EU inden for 5 arbejdsdage (kurértid kommer oveni).',
      nl: 'Kies modellen, stuur de WTB-lijst, we regelen de details en na betaling geven we het pakket af bij de koerier. Verzendtijd: PL binnen 48 werkuren, EU binnen 5 werkdagen (transittijd komt erbij).',
  } },
  { q: {
      pl: 'Skąd pochodzi towar?',
      en: 'Where does the stock come from?',
      fr: 'D\u2019où provient le stock ?',
      it: 'Da dove proviene la merce?',
      es: '¿De dónde procede el stock?',
      pt: 'De onde vem o stock?',
      cs: 'Odkud zboží pochází?',
      sv: 'Var kommer lagret ifrån?',
      da: 'Hvor kommer varerne fra?',
      nl: 'Waar komt de voorraad vandaan?',
    },
    a: {
      pl: 'Bezpośrednio od autoryzowanych dystrybutorów EU oraz weryfikowanych źródeł hurtowych. 100% autentyczność, każda para z dokumentem zakupu.',
      en: 'Directly from authorised EU distributors and verified wholesale sources. 100% authentic, every pair shipped with a proof of purchase.',
      fr: 'Directement auprès de distributeurs UE agréés et de sources grossistes vérifiées. 100% authentique, chaque paire livrée avec preuve d\u2019achat.',
      it: 'Direttamente da distributori UE autorizzati e fonti all\u2019ingrosso verificate. 100% autentico, ogni paio con prova d\u2019acquisto.',
      es: 'Directamente de distribuidores UE autorizados y fuentes mayoristas verificadas. 100% auténtico, cada par con prueba de compra.',
      pt: 'Diretamente de distribuidores UE autorizados e fontes grossistas verificadas. 100% autêntico, cada par com prova de compra.',
      cs: 'Přímo od autorizovaných EU distributorů a ověřených velkoobchodních zdrojů. 100% originál, každý pár s dokladem o nákupu.',
      sv: 'Direkt från auktoriserade EU-distributörer och verifierade grossistkällor. 100% äkta, varje par med inköpsbevis.',
      da: 'Direkte fra autoriserede EU-distributører og verificerede engros-kilder. 100% ægte, hvert par med købsbevis.',
      nl: 'Rechtstreeks van geautoriseerde EU-distributeurs en geverifieerde groothandelsbronnen. 100% authentiek, elk paar met aankoopbewijs.',
  } },
  { q: {
      pl: 'Czy mogę zwrócić towar?',
      en: 'Can I return goods?',
      fr: 'Puis-je retourner la marchandise ?',
      it: 'Posso restituire la merce?',
      es: '¿Puedo devolver la mercancía?',
      pt: 'Posso devolver mercadoria?',
      cs: 'Mohu zboží vrátit?',
      sv: 'Kan jag returnera varorna?',
      da: 'Kan jeg returnere varerne?',
      nl: 'Kan ik retourneren?',
    },
    a: {
      pl: 'Zwroty B2B przyjmujemy w ciągu 7 dni od dostawy, towar w pełnym DSWT (deadstock, nieużywany, z metką).',
      en: 'B2B returns within 7 days of delivery, DSWT only (deadstock, unworn, with original tag).',
      fr: 'Retours B2B sous 7 jours après livraison, uniquement DSWT (deadstock, neuf, avec étiquette d\u2019origine).',
      it: 'Resi B2B entro 7 giorni dalla consegna, solo DSWT (deadstock, non indossato, con cartellino).',
      es: 'Devoluciones B2B en un plazo de 7 días desde la entrega, solo DSWT (deadstock, sin usar, con etiqueta original).',
      pt: 'Devoluções B2B até 7 dias após entrega, apenas DSWT (deadstock, novo, com etiqueta original).',
      cs: 'B2B vrácení do 7 dnů od dodání, pouze DSWT (deadstock, nenošené, s původním štítkem).',
      sv: 'B2B-returer inom 7 dagar efter leverans, endast DSWT (deadstock, oanvänd, med originaltagg).',
      da: 'B2B-returneringer inden for 7 dage efter levering, kun DSWT (deadstock, ubrugt, med original-tag).',
      nl: 'B2B-retour binnen 7 dagen na levering, alleen DSWT (deadstock, ongedragen, met originele tag).',
  } },
];

const PROCESS = [
  { n: '01',
    t: {
      pl: 'Zarejestruj firmę',
      en: 'Register your business',
      fr: 'Enregistrez votre entreprise',
      it: 'Registra la tua azienda',
      es: 'Registra tu empresa',
      pt: 'Regista a tua empresa',
      cs: 'Zaregistrujte firmu',
      sv: 'Registrera ditt företag',
      da: 'Registrér din virksomhed',
      nl: 'Registreer je bedrijf',
    },
    d: {
      pl: 'Krótki formularz B2B — NIP, dane sklepu. Weryfikacja do 24h.',
      en: 'Short B2B form — VAT, shop details. Verified within 24h.',
      fr: 'Court formulaire B2B — TVA, infos boutique. Vérification sous 24h.',
      it: 'Breve modulo B2B — partita IVA, dati negozio. Verifica entro 24h.',
      es: 'Formulario B2B breve — IVA, datos de la tienda. Verificación en 24h.',
      pt: 'Formulário B2B breve — IVA, dados da loja. Verificação em 24h.',
      cs: 'Krátký B2B formulář — DIČ, údaje obchodu. Ověření do 24h.',
      sv: 'Kort B2B-formulär — VAT, butiksinfo. Verifierad inom 24h.',
      da: 'Kort B2B-formular — moms, butiksinfo. Verificeret inden for 24t.',
      nl: 'Kort B2B-formulier — btw, winkelinfo. Geverifieerd binnen 24u.',
  } },
  { n: '02',
    t: {
      pl: 'Wybierz lub wyślij WTB',
      en: 'Pick or send a WTB',
      fr: 'Choisissez ou envoyez un WTB',
      it: 'Scegli o invia un WTB',
      es: 'Elige o envía un WTB',
      pt: 'Escolhe ou envia um WTB',
      cs: 'Vyberte nebo pošlete WTB',
      sv: 'Välj eller skicka en WTB',
      da: 'Vælg eller send en WTB',
      nl: 'Kies of stuur een WTB',
    },
    d: {
      pl: 'Przeglądasz aktualny stock albo wysyłasz listę „Want To Buy". Odpisujemy z dostępnością i propozycją ceny.',
      en: 'Browse current stock or send a Want To Buy list. We reply with availability and a price proposal.',
      fr: 'Parcourez le stock actuel ou envoyez une liste « Want To Buy ». Nous répondons avec la disponibilité et un prix.',
      it: 'Sfoglia lo stock attuale o invia una lista "Want To Buy". Rispondiamo con disponibilità e proposta di prezzo.',
      es: 'Consulta el stock actual o envía una lista "Want To Buy". Respondemos con disponibilidad y propuesta de precio.',
      pt: 'Vê o stock atual ou envia uma lista "Want To Buy". Respondemos com disponibilidade e proposta de preço.',
      cs: 'Procházíte aktuální sklad nebo pošlete „Want To Buy" seznam. Odpovíme s dostupností a cenovou nabídkou.',
      sv: 'Kolla aktuellt lager eller skicka en "Want To Buy"-lista. Vi svarar med tillgänglighet och prisförslag.',
      da: 'Se det aktuelle lager eller send en "Want To Buy"-liste. Vi svarer med tilgængelighed og pristilbud.',
      nl: 'Bekijk de actuele voorraad of stuur een "Want To Buy"-lijst. We reageren met beschikbaarheid en prijsvoorstel.',
  } },
  { n: '03',
    t: {
      pl: 'Pakujemy i nadajemy',
      en: 'Pack & dispatch',
      fr: 'Emballage et expédition',
      it: 'Imballaggio e spedizione',
      es: 'Embalaje y envío',
      pt: 'Embalagem e envio',
      cs: 'Balíme a odesíláme',
      sv: 'Packning och leverans',
      da: 'Pakker og afsender',
      nl: 'Inpakken en versturen',
    },
    d: {
      pl: 'Pakujemy i nadajemy przesyłkę. Czas do wysyłki: PL do 2 dni roboczych, EU do 5 dni roboczych.',
      en: 'We pack and hand over to the courier. Time to dispatch: PL within 2 business days, EU within 5 business days.',
      fr: 'Nous emballons et remettons au transporteur. Délai d\u2019expédition : PL sous 2 jours ouvrés, UE sous 5 jours ouvrés.',
      it: 'Imballiamo e consegniamo al corriere. Tempo di spedizione: PL entro 2 giorni lavorativi, UE entro 5 giorni lavorativi.',
      es: 'Embalamos y entregamos al transportista. Plazo de envío: PL en 2 días laborables, UE en 5 días laborables.',
      pt: 'Embalamos e entregamos à transportadora. Prazo de envio: PL em 2 dias úteis, UE em 5 dias úteis.',
      cs: 'Balíme a předáváme kurýrovi. Doba expedice: PL do 2 pracovních dnů, EU do 5 pracovních dnů.',
      sv: 'Vi packar och lämnar till kuriren. Leveranstid: PL inom 2 arbetsdagar, EU inom 5 arbetsdagar.',
      da: 'Vi pakker og afleverer til kureren. Forsendelsestid: PL inden for 2 arbejdsdage, EU inden for 5 arbejdsdage.',
      nl: 'We pakken in en geven af bij de koerier. Verzendtijd: PL binnen 2 werkdagen, EU binnen 5 werkdagen.',
  } },
];

// Available UI languages. Order here defines the order in the picker.
// `code` is what we store/look up I18N by. `label` is what we display
// in the dropdown trigger and list.
const LANGUAGES = [
  { code: 'pl', label: 'Polski' },
  { code: 'en', label: 'English' },
  { code: 'fr', label: 'Français' },
  { code: 'it', label: 'Italiano' },
  { code: 'es', label: 'Español' },
  { code: 'pt', label: 'Português' },
  { code: 'cs', label: 'Čeština' },
  { code: 'sv', label: 'Svenska' },
  { code: 'da', label: 'Dansk' },
  { code: 'nl', label: 'Nederlands' },
];

const I18N = {
  pl: {
    locale: 'pl-PL', country: 'Polska',
    nav_stock: 'Stock', nav_wtb: 'Wyślij WTB', nav_how: 'Jak to działa', nav_about: 'O nas', nav_faq: 'FAQ', nav_contact: 'Kontakt', nav_login: 'B2B Panel',
    hero_eyebrow: 'B2B sneaker wholesale · od 2021',
    hero_h1_a: 'Hurtowy stock sneakersów. Bez teatru, bez retuszu.',
    hero_h1_b: 'STOCK. CENA. WYSYŁKA.',
    hero_h1_c: 'In-stock. Authentic. Ready to ship.',
    hero_sub: 'InStock Trade. Codzienna aktualizacja ofert. Kontakt Discord, WhatsApp lub mail.',
    cta_discord: 'Dołącz na Discord',
    cta_wtb: 'Wyślij listę WTB',
    cta_stock: 'Zobacz pełny stock',
    section_stock: 'Popularne oferty',
    section_how: 'Jak to działa',
    section_about: 'O nas',
    section_faq: 'FAQ',
    section_contact: 'Kontakt',
    updated_daily: 'aktualizowane codziennie',
    form_title: 'Wyślij listę WTB',
    form_sub: 'Wpisz modele, rozmiary i ilości. Odezwiemy się do 24h, najczęściej szybciej.',
    form_shop: 'Nazwa sklepu',
    form_vat: 'NIP / VAT EU',
    form_email: 'E-mail kontaktowy',
    form_brands: 'Wybrane marki',
    form_brands_ph: 'Wybierz marki…',
    form_brands_selected: 'wybranych',
    form_brands_all: 'Zaznacz wszystkie',
    form_brands_clear: 'Wyczyść',
    form_brands_done: 'Gotowe',
    form_list: 'Lista WTB — model, rozmiar, ilość',
    form_list_ph: 'np.\nCourt Low OG Bone — 42, 43, 44 × 3\nRunner V3 Ash — 42 × 6\nHeritage Hi Black/Cream — 43, 44',
    form_send: 'Wyślij zapytanie',
    form_sending: 'WYSYŁANIE…',
    error_rate: 'Za dużo zgłoszeń — spróbuj ponownie za kilka minut.',
    error_send: 'Coś poszło nie tak. Spróbuj ponownie lub napisz na Discord/WhatsApp.',
    error_network: 'Brak połączenia. Sprawdź internet i spróbuj ponownie.',
    sent_title: 'Zapytanie wysłane',
    sent_sub: 'Odpiszemy możliwie jak najszybciej (max 24h). Dołącz na Discord/WhatsApp po szybsze odpowiedzi.',
    about_p1: 'Jako InStock Trade jesteśmy hurtownią obsługującą sklepy i resellerów w Polsce oraz w całej Europie. Współpracujemy bezpośrednio z autoryzowanymi dystrybutorami i zweryfikowanymi źródłami hurtowymi.',
    about_p2: 'Zależy nam na efektywnej współpracy — wybór, szczegóły, wysyłka.',
    back_home: "Strona główna",
    catalogue_live: "Pełny katalog · live",
    full_stock_title: "Pełny stock",
    availability_label: "Dostępność",
    filter_all: "Wszystko",
    search_label: "Szukaj",
    search_ph: "Nazwa lub SKU…",
    no_matches: "Brak pasujących modeli",
    ask_about: "Zapytaj o ten model",
    ask_about_sub: "Po kliknięciu kopiujemy nazwę modelu do schowka i otwieramy wybrany kanał — wystarczy wkleić wiadomość.",
    ask_msg_prefix: "Cześć! Pytam o:",
    copied_label: "Skopiowano:",
    stock_available: 'Możliwe do zamówienia', stock_low: 'Możliwe do zamówienia', stock_oos: 'Chwilowy brak',
    foot_address: 'Adres', foot_hours: 'Godziny',
    foot_rights: 'Wszystkie prawa zastrzeżone',
    foot_legal: '',
  },
  en: {
    locale: 'en-GB', country: 'Poland',
    nav_stock: 'Stock', nav_wtb: 'Send WTB', nav_how: 'How it works', nav_about: 'About', nav_faq: 'FAQ', nav_contact: 'Contact', nav_login: 'B2B Login',
    hero_eyebrow: 'B2B sneaker wholesale · since 2021',
    hero_h1_a: 'Sneaker wholesale stock. No theatre, no retouch.',
    hero_h1_b: 'STOCK. PRICE. SHIPPED.',
    hero_h1_c: 'In-stock. Authentic. Ready to ship.',
    hero_sub: 'InStock Trade. Stock refreshed daily. Contact via Discord, WhatsApp or email.',
    cta_discord: 'Join Discord',
    cta_wtb: 'Send WTB list',
    cta_stock: 'See full stock',
    section_stock: 'Popular drops',
    section_how: 'How it works',
    section_about: 'About',
    section_faq: 'FAQ',
    section_contact: 'Contact',
    updated_daily: 'updated daily',
    form_title: 'Send WTB list',
    form_sub: 'Drop models, sizes and quantities. We reply within 24h, often sooner.',
    form_shop: 'Shop name',
    form_vat: 'VAT / EU VAT',
    form_email: 'Contact email',
    form_brands: 'Selected brands',
    form_brands_ph: 'Choose brands…',
    form_brands_selected: 'selected',
    form_brands_all: 'Select all',
    form_brands_clear: 'Clear',
    form_brands_done: 'Done',
    form_list: 'WTB list — model, size, quantity',
    form_list_ph: 'e.g.\nCourt Low OG Bone — 42, 43, 44 × 3\nRunner V3 Ash — 42 × 6\nHeritage Hi Black/Cream — 43, 44',
    form_send: 'Send request',
    form_sending: 'SENDING…',
    error_rate: 'Too many submissions — try again in a few minutes.',
    error_send: 'Something went wrong. Try again or message us on Discord/WhatsApp.',
    error_network: 'Network error. Check your connection and try again.',
    sent_title: 'Request sent',
    sent_sub: 'We will reply as soon as possible (max 24h). Join Discord/WhatsApp for faster responses.',
    about_p1: 'As InStock Trade, we are a wholesale serving shops and resellers in Poland and across Europe. We cooperate directly with authorised distributors and verified wholesale sources.',
    about_p2: 'We care about effective cooperation — picking, details, shipping.',
    back_home: "Home",
    catalogue_live: "Full catalogue · live",
    full_stock_title: "Full stock",
    availability_label: "Availability",
    filter_all: "All",
    search_label: "Search",
    search_ph: "Name or SKU…",
    no_matches: "No matching models",
    ask_about: "Ask about this model",
    ask_about_sub: "On click we copy the model name to your clipboard and open the chosen channel — just paste the message.",
    ask_msg_prefix: "Hi! Asking about:",
    copied_label: "Copied:",
    stock_available: 'Available to order', stock_low: 'Available to order', stock_oos: 'Currently out',
    foot_address: 'Address', foot_hours: 'Hours',
    foot_rights: 'All rights reserved',
    foot_legal: '',
  },
  fr: {
    locale: 'fr-FR', country: 'Pologne',
    nav_stock: 'Stock', nav_wtb: 'Envoyer WTB', nav_how: 'Comment ça marche', nav_about: 'À propos', nav_faq: 'FAQ', nav_contact: 'Contact', nav_login: 'Espace B2B',
    hero_eyebrow: 'Grossiste sneakers B2B · depuis 2021',
    hero_h1_a: 'Stock grossiste de sneakers. Sans esbroufe, sans retouche.',
    hero_h1_b: 'STOCK. PRIX. EXPÉDIÉ.',
    hero_h1_c: 'En stock. Authentique. Prêt à expédier.',
    hero_sub: 'InStock Trade. Stock mis à jour quotidiennement. Contact via Discord, WhatsApp ou e-mail.',
    cta_discord: 'Rejoindre Discord',
    cta_wtb: 'Envoyer la liste WTB',
    cta_stock: 'Voir tout le stock',
    section_stock: 'Offres populaires',
    section_how: 'Comment ça marche',
    section_about: 'À propos',
    section_faq: 'FAQ',
    section_contact: 'Contact',
    updated_daily: 'mis à jour chaque jour',
    form_title: 'Envoyer la liste WTB',
    form_sub: 'Indiquez modèles, tailles et quantités. Nous répondons sous 24h, souvent plus vite.',
    form_shop: 'Nom de la boutique',
    form_vat: 'TVA / TVA UE',
    form_email: 'E-mail de contact',
    form_brands: 'Marques choisies',
    form_brands_ph: 'Choisir des marques…',
    form_brands_selected: 'choisies',
    form_brands_all: 'Tout sélectionner',
    form_brands_clear: 'Effacer',
    form_brands_done: 'Terminé',
    form_list: 'Liste WTB — modèle, taille, quantité',
    form_list_ph: 'ex.\nCourt Low OG Bone — 42, 43, 44 × 3\nRunner V3 Ash — 42 × 6\nHeritage Hi Black/Cream — 43, 44',
    form_send: 'Envoyer la demande',
    form_sending: 'ENVOI…',
    error_rate: 'Trop de demandes — réessayez dans quelques minutes.',
    error_send: 'Une erreur est survenue. Réessayez ou écrivez-nous sur Discord/WhatsApp.',
    error_network: 'Pas de connexion. Vérifiez Internet et réessayez.',
    sent_title: 'Demande envoyée',
    sent_sub: 'Nous répondrons dès que possible (max 24h). Rejoignez Discord/WhatsApp pour des réponses plus rapides.',
    about_p1: 'InStock Trade est un grossiste au service des boutiques et revendeurs en Pologne et dans toute l\u2019Europe. Nous collaborons directement avec des distributeurs autorisés et des sources grossistes vérifiées.',
    about_p2: 'Nous misons sur une coopération efficace — sélection, détails, expédition.',
    back_home: "Accueil",
    catalogue_live: "Catalogue complet · live",
    full_stock_title: "Stock complet",
    availability_label: "Disponibilité",
    filter_all: "Tout",
    search_label: "Recherche",
    search_ph: "Nom ou SKU…",
    no_matches: "Aucun modèle ne correspond",
    ask_about: "Demander sur ce modèle",
    ask_about_sub: "Au clic, nous copions le nom du modèle dans le presse-papiers et ouvrons le canal choisi — il suffit de coller le message.",
    ask_msg_prefix: "Salut ! Je demande pour :",
    copied_label: "Copié :",
    stock_available: 'Disponible à la commande', stock_low: 'Disponible à la commande', stock_oos: 'Rupture temporaire',
    foot_address: 'Adresse', foot_hours: 'Horaires',
    foot_rights: 'Tous droits réservés',
    foot_legal: '',
  },
  it: {
    locale: 'it-IT', country: 'Polonia',
    nav_stock: 'Stock', nav_wtb: 'Invia WTB', nav_how: 'Come funziona', nav_about: 'Chi siamo', nav_faq: 'FAQ', nav_contact: 'Contatti', nav_login: 'Area B2B',
    hero_eyebrow: 'Grossista sneakers B2B · dal 2021',
    hero_h1_a: 'Stock all\u2019ingrosso di sneakers. Senza fronzoli, senza ritocchi.',
    hero_h1_b: 'STOCK. PREZZO. SPEDITO.',
    hero_h1_c: 'Disponibile. Autentico. Pronto a partire.',
    hero_sub: 'InStock Trade. Stock aggiornato ogni giorno. Contatti via Discord, WhatsApp o e-mail.',
    cta_discord: 'Entra su Discord',
    cta_wtb: 'Invia lista WTB',
    cta_stock: 'Vedi tutto lo stock',
    section_stock: 'Offerte popolari',
    section_how: 'Come funziona',
    section_about: 'Chi siamo',
    section_faq: 'FAQ',
    section_contact: 'Contatti',
    updated_daily: 'aggiornato ogni giorno',
    form_title: 'Invia lista WTB',
    form_sub: 'Indica modelli, taglie e quantità. Rispondiamo entro 24h, spesso prima.',
    form_shop: 'Nome del negozio',
    form_vat: 'P. IVA / IVA UE',
    form_email: 'E-mail di contatto',
    form_brands: 'Marchi selezionati',
    form_brands_ph: 'Scegli i marchi…',
    form_brands_selected: 'selezionati',
    form_brands_all: 'Seleziona tutti',
    form_brands_clear: 'Pulisci',
    form_brands_done: 'Fatto',
    form_list: 'Lista WTB — modello, taglia, quantità',
    form_list_ph: 'es.\nCourt Low OG Bone — 42, 43, 44 × 3\nRunner V3 Ash — 42 × 6\nHeritage Hi Black/Cream — 43, 44',
    form_send: 'Invia richiesta',
    form_sending: 'INVIO…',
    error_rate: 'Troppe richieste — riprova tra qualche minuto.',
    error_send: 'Qualcosa è andato storto. Riprova o scrivici su Discord/WhatsApp.',
    error_network: 'Nessuna connessione. Controlla Internet e riprova.',
    sent_title: 'Richiesta inviata',
    sent_sub: 'Risponderemo il prima possibile (max 24h). Entra su Discord/WhatsApp per risposte più rapide.',
    about_p1: 'InStock Trade è un grossista che serve negozi e rivenditori in Polonia e in tutta Europa. Collaboriamo direttamente con distributori autorizzati e fonti all\u2019ingrosso verificate.',
    about_p2: 'Puntiamo a una cooperazione efficace — selezione, dettagli, spedizione.',
    back_home: "Home",
    catalogue_live: "Catalogo completo · live",
    full_stock_title: "Stock completo",
    availability_label: "Disponibilità",
    filter_all: "Tutto",
    search_label: "Cerca",
    search_ph: "Nome o SKU…",
    no_matches: "Nessun modello corrisponde",
    ask_about: "Chiedi su questo modello",
    ask_about_sub: "Al clic copiamo il nome del modello negli appunti e apriamo il canale scelto — basta incollare il messaggio.",
    ask_msg_prefix: "Ciao! Chiedo per:",
    copied_label: "Copiato:",
    stock_available: 'Ordinabile', stock_low: 'Ordinabile', stock_oos: 'Momentaneamente esaurito',
    foot_address: 'Indirizzo', foot_hours: 'Orari',
    foot_rights: 'Tutti i diritti riservati',
    foot_legal: '',
  },
  es: {
    locale: 'es-ES', country: 'Polonia',
    nav_stock: 'Stock', nav_wtb: 'Enviar WTB', nav_how: 'Cómo funciona', nav_about: 'Nosotros', nav_faq: 'FAQ', nav_contact: 'Contacto', nav_login: 'Panel B2B',
    hero_eyebrow: 'Mayorista de sneakers B2B · desde 2021',
    hero_h1_a: 'Stock mayorista de sneakers. Sin teatro, sin retoque.',
    hero_h1_b: 'STOCK. PRECIO. ENVÍO.',
    hero_h1_c: 'En stock. Auténtico. Listo para enviar.',
    hero_sub: 'InStock Trade. Stock actualizado a diario. Contacto vía Discord, WhatsApp o e-mail.',
    cta_discord: 'Únete a Discord',
    cta_wtb: 'Enviar lista WTB',
    cta_stock: 'Ver todo el stock',
    section_stock: 'Ofertas populares',
    section_how: 'Cómo funciona',
    section_about: 'Nosotros',
    section_faq: 'FAQ',
    section_contact: 'Contacto',
    updated_daily: 'actualizado cada día',
    form_title: 'Enviar lista WTB',
    form_sub: 'Indica modelos, tallas y cantidades. Respondemos en 24h, a menudo antes.',
    form_shop: 'Nombre de la tienda',
    form_vat: 'NIF / IVA UE',
    form_email: 'E-mail de contacto',
    form_brands: 'Marcas seleccionadas',
    form_brands_ph: 'Elige marcas…',
    form_brands_selected: 'seleccionadas',
    form_brands_all: 'Seleccionar todas',
    form_brands_clear: 'Limpiar',
    form_brands_done: 'Hecho',
    form_list: 'Lista WTB — modelo, talla, cantidad',
    form_list_ph: 'ej.\nCourt Low OG Bone — 42, 43, 44 × 3\nRunner V3 Ash — 42 × 6\nHeritage Hi Black/Cream — 43, 44',
    form_send: 'Enviar solicitud',
    form_sending: 'ENVIANDO…',
    error_rate: 'Demasiadas solicitudes — inténtalo de nuevo en unos minutos.',
    error_send: 'Algo salió mal. Vuelve a intentarlo o escríbenos en Discord/WhatsApp.',
    error_network: 'Sin conexión. Comprueba Internet y reintenta.',
    sent_title: 'Solicitud enviada',
    sent_sub: 'Responderemos lo antes posible (máx. 24h). Únete a Discord/WhatsApp para respuestas más rápidas.',
    about_p1: 'En InStock Trade somos un mayorista que atiende a tiendas y revendedores en Polonia y en toda Europa. Colaboramos directamente con distribuidores autorizados y fuentes mayoristas verificadas.',
    about_p2: 'Apostamos por una cooperación eficaz — selección, detalles, envío.',
    back_home: "Inicio",
    catalogue_live: "Catálogo completo · live",
    full_stock_title: "Stock completo",
    availability_label: "Disponibilidad",
    filter_all: "Todo",
    search_label: "Buscar",
    search_ph: "Nombre o SKU…",
    no_matches: "No hay modelos que coincidan",
    ask_about: "Preguntar por este modelo",
    ask_about_sub: "Al hacer clic copiamos el nombre del modelo al portapapeles y abrimos el canal elegido — solo pega el mensaje.",
    ask_msg_prefix: "¡Hola! Pregunto por:",
    copied_label: "Copiado:",
    stock_available: 'Disponible para pedir', stock_low: 'Disponible para pedir', stock_oos: 'Agotado temporalmente',
    foot_address: 'Dirección', foot_hours: 'Horario',
    foot_rights: 'Todos los derechos reservados',
    foot_legal: '',
  },
  pt: {
    locale: 'pt-PT', country: 'Polónia',
    nav_stock: 'Stock', nav_wtb: 'Enviar WTB', nav_how: 'Como funciona', nav_about: 'Sobre nós', nav_faq: 'FAQ', nav_contact: 'Contacto', nav_login: 'Painel B2B',
    hero_eyebrow: 'Grossista de sneakers B2B · desde 2021',
    hero_h1_a: 'Stock grossista de sneakers. Sem teatro, sem retoque.',
    hero_h1_b: 'STOCK. PREÇO. ENVIADO.',
    hero_h1_c: 'Em stock. Autêntico. Pronto a enviar.',
    hero_sub: 'InStock Trade. Stock atualizado diariamente. Contacto via Discord, WhatsApp ou e-mail.',
    cta_discord: 'Entra no Discord',
    cta_wtb: 'Enviar lista WTB',
    cta_stock: 'Ver todo o stock',
    section_stock: 'Ofertas populares',
    section_how: 'Como funciona',
    section_about: 'Sobre nós',
    section_faq: 'FAQ',
    section_contact: 'Contacto',
    updated_daily: 'atualizado todos os dias',
    form_title: 'Enviar lista WTB',
    form_sub: 'Indica modelos, tamanhos e quantidades. Respondemos em 24h, normalmente antes.',
    form_shop: 'Nome da loja',
    form_vat: 'NIF / IVA UE',
    form_email: 'E-mail de contacto',
    form_brands: 'Marcas selecionadas',
    form_brands_ph: 'Escolher marcas…',
    form_brands_selected: 'selecionadas',
    form_brands_all: 'Selecionar tudo',
    form_brands_clear: 'Limpar',
    form_brands_done: 'Concluído',
    form_list: 'Lista WTB — modelo, tamanho, quantidade',
    form_list_ph: 'ex.\nCourt Low OG Bone — 42, 43, 44 × 3\nRunner V3 Ash — 42 × 6\nHeritage Hi Black/Cream — 43, 44',
    form_send: 'Enviar pedido',
    form_sending: 'A ENVIAR…',
    error_rate: 'Demasiados pedidos — tenta novamente em alguns minutos.',
    error_send: 'Algo correu mal. Tenta de novo ou contacta-nos no Discord/WhatsApp.',
    error_network: 'Sem ligação. Verifica a Internet e tenta de novo.',
    sent_title: 'Pedido enviado',
    sent_sub: 'Respondemos o mais rapidamente possível (máx. 24h). Entra no Discord/WhatsApp para respostas mais rápidas.',
    about_p1: 'A InStock Trade é uma grossista ao serviço de lojas e revendedores em Portugal, Polónia e em toda a Europa. Trabalhamos diretamente com distribuidores autorizados e fontes grossistas verificadas.',
    about_p2: 'Apostamos numa cooperação eficaz — seleção, detalhes, envio.',
    back_home: "Início",
    catalogue_live: "Catálogo completo · live",
    full_stock_title: "Stock completo",
    availability_label: "Disponibilidade",
    filter_all: "Tudo",
    search_label: "Procurar",
    search_ph: "Nome ou SKU…",
    no_matches: "Nenhum modelo corresponde",
    ask_about: "Perguntar sobre este modelo",
    ask_about_sub: "Ao clicar, copiamos o nome do modelo para a área de transferência e abrimos o canal escolhido — basta colar a mensagem.",
    ask_msg_prefix: "Olá! Pergunto sobre:",
    copied_label: "Copiado:",
    stock_available: 'Disponível para encomenda', stock_low: 'Disponível para encomenda', stock_oos: 'Esgotado momentaneamente',
    foot_address: 'Morada', foot_hours: 'Horário',
    foot_rights: 'Todos os direitos reservados',
    foot_legal: '',
  },
  cs: {
    locale: 'cs-CZ', country: 'Polsko',
    nav_stock: 'Sklad', nav_wtb: 'Poslat WTB', nav_how: 'Jak to funguje', nav_about: 'O nás', nav_faq: 'FAQ', nav_contact: 'Kontakt', nav_login: 'B2B panel',
    hero_eyebrow: 'B2B velkoobchod sneakers · od 2021',
    hero_h1_a: 'Velkoobchodní sklad sneakers. Bez divadla, bez retuší.',
    hero_h1_b: 'SKLAD. CENA. ODESLÁNO.',
    hero_h1_c: 'Skladem. Originál. Připraveno k expedici.',
    hero_sub: 'InStock Trade. Sklad denně aktualizován. Kontakt přes Discord, WhatsApp nebo e-mail.',
    cta_discord: 'Přidat se na Discord',
    cta_wtb: 'Poslat WTB seznam',
    cta_stock: 'Zobrazit celý sklad',
    section_stock: 'Populární nabídky',
    section_how: 'Jak to funguje',
    section_about: 'O nás',
    section_faq: 'FAQ',
    section_contact: 'Kontakt',
    updated_daily: 'denně aktualizováno',
    form_title: 'Poslat WTB seznam',
    form_sub: 'Napiš modely, velikosti a počty. Odpovíme do 24h, často dříve.',
    form_shop: 'Název obchodu',
    form_vat: 'DIČ / EU VAT',
    form_email: 'Kontaktní e-mail',
    form_brands: 'Vybrané značky',
    form_brands_ph: 'Vyber značky…',
    form_brands_selected: 'vybráno',
    form_brands_all: 'Vybrat vše',
    form_brands_clear: 'Vymazat',
    form_brands_done: 'Hotovo',
    form_list: 'WTB seznam — model, velikost, množství',
    form_list_ph: 'např.\nCourt Low OG Bone — 42, 43, 44 × 3\nRunner V3 Ash — 42 × 6\nHeritage Hi Black/Cream — 43, 44',
    form_send: 'Odeslat poptávku',
    form_sending: 'ODESÍLÁNÍ…',
    error_rate: 'Příliš mnoho pokusů — zkus to za pár minut.',
    error_send: 'Něco se nepovedlo. Zkus to znovu nebo nám napiš na Discord/WhatsApp.',
    error_network: 'Bez připojení. Zkontroluj internet a zkus to znovu.',
    sent_title: 'Poptávka odeslána',
    sent_sub: 'Odpovíme co nejdříve (max 24h). Přidej se na Discord/WhatsApp pro rychlejší odpovědi.',
    about_p1: 'InStock Trade je velkoobchod obsluhující obchody a resellery v Polsku a v celé Evropě. Spolupracujeme přímo s autorizovanými distributory a ověřenými velkoobchodními zdroji.',
    about_p2: 'Záleží nám na efektivní spolupráci — výběr, detaily, doprava.',
    back_home: "Domů",
    catalogue_live: "Plný katalog · live",
    full_stock_title: "Plný sklad",
    availability_label: "Dostupnost",
    filter_all: "Vše",
    search_label: "Hledat",
    search_ph: "Název nebo SKU…",
    no_matches: "Žádné odpovídající modely",
    ask_about: "Zeptat se na tento model",
    ask_about_sub: "Po kliknutí zkopírujeme název modelu do schránky a otevřeme zvolený kanál — stačí vložit zprávu.",
    ask_msg_prefix: "Ahoj! Ptám se na:",
    copied_label: "Zkopírováno:",
    stock_available: 'Lze objednat', stock_low: 'Lze objednat', stock_oos: 'Momentálně nedostupné',
    foot_address: 'Adresa', foot_hours: 'Otevírací doba',
    foot_rights: 'Všechna práva vyhrazena',
    foot_legal: '',
  },
  sv: {
    locale: 'sv-SE', country: 'Polen',
    nav_stock: 'Lager', nav_wtb: 'Skicka WTB', nav_how: 'Så funkar det', nav_about: 'Om oss', nav_faq: 'FAQ', nav_contact: 'Kontakt', nav_login: 'B2B-panel',
    hero_eyebrow: 'B2B sneaker-grossist · sedan 2021',
    hero_h1_a: 'Grossistlager med sneakers. Utan teater, utan retusch.',
    hero_h1_b: 'LAGER. PRIS. LEVERANS.',
    hero_h1_c: 'I lager. Äkta. Redo att skickas.',
    hero_sub: 'InStock Trade. Lager uppdateras dagligen. Kontakt via Discord, WhatsApp eller e-post.',
    cta_discord: 'Gå med på Discord',
    cta_wtb: 'Skicka WTB-lista',
    cta_stock: 'Se hela lagret',
    section_stock: 'Populära erbjudanden',
    section_how: 'Så funkar det',
    section_about: 'Om oss',
    section_faq: 'FAQ',
    section_contact: 'Kontakt',
    updated_daily: 'uppdateras dagligen',
    form_title: 'Skicka WTB-lista',
    form_sub: 'Skriv modeller, storlekar och antal. Vi svarar inom 24h, oftast snabbare.',
    form_shop: 'Butikens namn',
    form_vat: 'VAT / EU-VAT',
    form_email: 'Kontakt-e-post',
    form_brands: 'Valda märken',
    form_brands_ph: 'Välj märken…',
    form_brands_selected: 'valda',
    form_brands_all: 'Markera alla',
    form_brands_clear: 'Rensa',
    form_brands_done: 'Klar',
    form_list: 'WTB-lista — modell, storlek, antal',
    form_list_ph: 't.ex.\nCourt Low OG Bone — 42, 43, 44 × 3\nRunner V3 Ash — 42 × 6\nHeritage Hi Black/Cream — 43, 44',
    form_send: 'Skicka förfrågan',
    form_sending: 'SKICKAR…',
    error_rate: 'För många försök — försök igen om några minuter.',
    error_send: 'Något gick fel. Försök igen eller skriv till oss på Discord/WhatsApp.',
    error_network: 'Ingen anslutning. Kontrollera internet och försök igen.',
    sent_title: 'Förfrågan skickad',
    sent_sub: 'Vi svarar så snart vi kan (max 24h). Gå med på Discord/WhatsApp för snabbare svar.',
    about_p1: 'InStock Trade är en grossist som betjänar butiker och återförsäljare i Polen och hela Europa. Vi samarbetar direkt med auktoriserade distributörer och verifierade grossistkällor.',
    about_p2: 'Vi värnar om effektivt samarbete — urval, detaljer, leverans.',
    back_home: "Hem",
    catalogue_live: "Hela katalogen · live",
    full_stock_title: "Hela lagret",
    availability_label: "Tillgänglighet",
    filter_all: "Allt",
    search_label: "Sök",
    search_ph: "Namn eller SKU…",
    no_matches: "Inga matchande modeller",
    ask_about: "Fråga om denna modell",
    ask_about_sub: "Vid klick kopierar vi modellnamnet till urklipp och öppnar den valda kanalen — klistra bara in meddelandet.",
    ask_msg_prefix: "Hej! Frågar om:",
    copied_label: "Kopierat:",
    stock_available: 'Tillgänglig att beställa', stock_low: 'Tillgänglig att beställa', stock_oos: 'Slut för tillfället',
    foot_address: 'Adress', foot_hours: 'Tider',
    foot_rights: 'Alla rättigheter förbehållna',
    foot_legal: '',
  },
  da: {
    locale: 'da-DK', country: 'Polen',
    nav_stock: 'Lager', nav_wtb: 'Send WTB', nav_how: 'Sådan fungerer det', nav_about: 'Om os', nav_faq: 'FAQ', nav_contact: 'Kontakt', nav_login: 'B2B-panel',
    hero_eyebrow: 'B2B sneaker-engros · siden 2021',
    hero_h1_a: 'Engros-lager af sneakers. Uden teater, uden retouchering.',
    hero_h1_b: 'LAGER. PRIS. AFSENDT.',
    hero_h1_c: 'På lager. Ægte. Klar til afsendelse.',
    hero_sub: 'InStock Trade. Lager opdateres dagligt. Kontakt via Discord, WhatsApp eller e-mail.',
    cta_discord: 'Tilslut Discord',
    cta_wtb: 'Send WTB-liste',
    cta_stock: 'Se hele lageret',
    section_stock: 'Populære tilbud',
    section_how: 'Sådan fungerer det',
    section_about: 'Om os',
    section_faq: 'FAQ',
    section_contact: 'Kontakt',
    updated_daily: 'opdateres dagligt',
    form_title: 'Send WTB-liste',
    form_sub: 'Skriv modeller, størrelser og antal. Vi svarer inden for 24t, ofte hurtigere.',
    form_shop: 'Butikkens navn',
    form_vat: 'CVR / EU-moms',
    form_email: 'Kontakt-e-mail',
    form_brands: 'Valgte mærker',
    form_brands_ph: 'Vælg mærker…',
    form_brands_selected: 'valgt',
    form_brands_all: 'Vælg alle',
    form_brands_clear: 'Ryd',
    form_brands_done: 'Færdig',
    form_list: 'WTB-liste — model, størrelse, antal',
    form_list_ph: 'f.eks.\nCourt Low OG Bone — 42, 43, 44 × 3\nRunner V3 Ash — 42 × 6\nHeritage Hi Black/Cream — 43, 44',
    form_send: 'Send forespørgsel',
    form_sending: 'SENDER…',
    error_rate: 'For mange forsøg — prøv igen om et par minutter.',
    error_send: 'Noget gik galt. Prøv igen eller skriv til os på Discord/WhatsApp.',
    error_network: 'Ingen forbindelse. Tjek internettet og prøv igen.',
    sent_title: 'Forespørgsel sendt',
    sent_sub: 'Vi svarer så hurtigt som muligt (maks. 24t). Tilslut Discord/WhatsApp for hurtigere svar.',
    about_p1: 'InStock Trade er en grossist, der betjener butikker og forhandlere i Polen og i hele Europa. Vi samarbejder direkte med autoriserede distributører og verificerede engros-kilder.',
    about_p2: 'Vi sætter pris på effektivt samarbejde — udvalg, detaljer, levering.',
    back_home: "Hjem",
    catalogue_live: "Fuldt katalog · live",
    full_stock_title: "Fuldt lager",
    availability_label: "Tilgængelighed",
    filter_all: "Alt",
    search_label: "Søg",
    search_ph: "Navn eller SKU…",
    no_matches: "Ingen matchende modeller",
    ask_about: "Spørg om denne model",
    ask_about_sub: "Når du klikker, kopierer vi modelnavnet til udklipsholderen og åbner den valgte kanal — du skal bare indsætte beskeden.",
    ask_msg_prefix: "Hej! Spørger om:",
    copied_label: "Kopieret:",
    stock_available: 'Kan bestilles', stock_low: 'Kan bestilles', stock_oos: 'Midlertidigt udsolgt',
    foot_address: 'Adresse', foot_hours: 'Tider',
    foot_rights: 'Alle rettigheder forbeholdes',
    foot_legal: '',
  },
  nl: {
    locale: 'nl-NL', country: 'Polen',
    nav_stock: 'Voorraad', nav_wtb: 'Stuur WTB', nav_how: 'Hoe het werkt', nav_about: 'Over ons', nav_faq: 'FAQ', nav_contact: 'Contact', nav_login: 'B2B-paneel',
    hero_eyebrow: 'B2B sneaker-groothandel · sinds 2021',
    hero_h1_a: 'Groothandelsvoorraad sneakers. Geen theater, geen retouches.',
    hero_h1_b: 'VOORRAAD. PRIJS. VERZONDEN.',
    hero_h1_c: 'Op voorraad. Authentiek. Klaar om te verzenden.',
    hero_sub: 'InStock Trade. Voorraad dagelijks bijgewerkt. Contact via Discord, WhatsApp of e-mail.',
    cta_discord: 'Join Discord',
    cta_wtb: 'Stuur WTB-lijst',
    cta_stock: 'Bekijk de volledige voorraad',
    section_stock: 'Populaire aanbiedingen',
    section_how: 'Hoe het werkt',
    section_about: 'Over ons',
    section_faq: 'FAQ',
    section_contact: 'Contact',
    updated_daily: 'dagelijks bijgewerkt',
    form_title: 'Stuur WTB-lijst',
    form_sub: 'Geef modellen, maten en aantallen op. We reageren binnen 24u, vaak sneller.',
    form_shop: 'Naam van de winkel',
    form_vat: 'BTW / EU-BTW',
    form_email: 'Contact-e-mail',
    form_brands: 'Geselecteerde merken',
    form_brands_ph: 'Kies merken…',
    form_brands_selected: 'geselecteerd',
    form_brands_all: 'Alles selecteren',
    form_brands_clear: 'Wissen',
    form_brands_done: 'Klaar',
    form_list: 'WTB-lijst — model, maat, aantal',
    form_list_ph: 'bv.\nCourt Low OG Bone — 42, 43, 44 × 3\nRunner V3 Ash — 42 × 6\nHeritage Hi Black/Cream — 43, 44',
    form_send: 'Aanvraag versturen',
    form_sending: 'VERZENDEN…',
    error_rate: 'Te veel pogingen — probeer het over enkele minuten opnieuw.',
    error_send: 'Er ging iets mis. Probeer opnieuw of stuur ons een bericht op Discord/WhatsApp.',
    error_network: 'Geen verbinding. Controleer internet en probeer opnieuw.',
    sent_title: 'Aanvraag verzonden',
    sent_sub: 'We reageren zo snel mogelijk (max. 24u). Join Discord/WhatsApp voor snellere antwoorden.',
    about_p1: 'InStock Trade is een groothandel die winkels en wederverkopers in Polen en heel Europa bedient. We werken rechtstreeks samen met geautoriseerde distributeurs en geverifieerde groothandelsbronnen.',
    about_p2: 'Wij hechten waarde aan efficiënte samenwerking — selectie, details, verzending.',
    back_home: "Home",
    catalogue_live: "Volledige catalogus · live",
    full_stock_title: "Volledige voorraad",
    availability_label: "Beschikbaarheid",
    filter_all: "Alles",
    search_label: "Zoeken",
    search_ph: "Naam of SKU…",
    no_matches: "Geen overeenkomende modellen",
    ask_about: "Vraag over dit model",
    ask_about_sub: "Bij klikken kopiëren we de modelnaam naar je klembord en openen we het gekozen kanaal — plak gewoon het bericht.",
    ask_msg_prefix: "Hoi! Ik vraag over:",
    copied_label: "Gekopieerd:",
    stock_available: 'Te bestellen', stock_low: 'Te bestellen', stock_oos: 'Tijdelijk uitverkocht',
    foot_address: 'Adres', foot_hours: 'Tijden',
    foot_rights: 'Alle rechten voorbehouden',
    foot_legal: '',
  },
};

// Helper: returns translations for a language, with English as fallback
// for any keys not yet translated. Safer than direct I18N[lang] access.
function getT(lang) {
  return { ...I18N.en, ...(I18N[lang] || {}) };
}

// Sneaker imagery slot. When `src` is provided, renders the real
// product photo on a tinted backdrop; otherwise falls back to a
// diagonal-striped placeholder with a monospace label.
function SneakerPlaceholder({ label, bg, src, alt }) {
  if (src) {
    return (
      <div style={{
        position: 'relative', width: '100%', height: '100%',
        background: bg || '#ebe7df', display: 'flex', alignItems: 'center', justifyContent: 'center',
        overflow: 'hidden',
      }}>
        <img src={src} alt={alt || label || ''} style={{
          width: '92%', height: '92%', objectFit: 'contain', display: 'block',
          mixBlendMode: 'darken',
        }} />
      </div>
    );
  }
  return (
    <div className="sneaker-ph" data-label={label || 'sneaker shot'} style={{ '--ph-bg': bg || '#ebe7df' }}>
      <svg viewBox="0 0 200 100" fill="none" aria-hidden="true">
        <rect x="20" y="60" width="160" height="2" fill="rgba(0,0,0,.18)" />
        <path d="M30 60 Q 30 30 70 30 L 110 30 Q 130 30 145 45 L 175 55 Q 175 60 175 60 Z"
              fill="rgba(0,0,0,.10)" stroke="rgba(0,0,0,.22)" strokeWidth="1.2" />
      </svg>
    </div>
  );
}

// — Image-load-failure tracking —
// When a Drive image fails to load (404 / private file / dead webp
// thumbnail), we want the homepage to silently roll over to the next
// product instead of displaying a broken card. We expose a global
// Set + a React hook so any page can `const broken = useBrokenImages()`
// and filter that product out at the data layer.
const BROKEN_IMG_CODES = new Set();
const BROKEN_IMG_LISTENERS = new Set();
function markImageBroken(code) {
  if (!code || BROKEN_IMG_CODES.has(code)) return;
  BROKEN_IMG_CODES.add(code);
  BROKEN_IMG_LISTENERS.forEach(fn => fn());
}
function useBrokenImages() {
  const [, force] = React.useReducer(x => x + 1, 0);
  React.useEffect(() => {
    BROKEN_IMG_LISTENERS.add(force);
    return () => { BROKEN_IMG_LISTENERS.delete(force); };
  }, []);
  return BROKEN_IMG_CODES;
}
// Samples the dominant colour of a product image, ignoring near-white
// background pixels (most sneaker product shots ship on solid white).
// Returns [r,g,b] or null while loading / on CORS failure.
function useDominantColor(src) {
  const [rgb, setRgb] = React.useState(null);
  React.useEffect(() => {
    if (!src) { setRgb(null); return; }
    let cancelled = false;
    const img = new Image();
    img.crossOrigin = 'anonymous';
    img.onload = () => {
      try {
        const size = 32;
        const c = document.createElement('canvas');
        c.width = size; c.height = size;
        const ctx = c.getContext('2d');
        ctx.drawImage(img, 0, 0, size, size);
        const data = ctx.getImageData(0, 0, size, size).data;
        let r = 0, g = 0, b = 0, n = 0;
        for (let i = 0; i < data.length; i += 4) {
          const R = data[i], G = data[i+1], B = data[i+2], A = data[i+3];
          if (A < 200) continue;
          const luma = (R*0.2126 + G*0.7152 + B*0.0722);
          if (luma > 235) continue;  // skip near-white background
          if (luma < 18)  continue;  // skip near-black to avoid murky tones
          r += R; g += G; b += B; n++;
        }
        if (!cancelled && n) setRgb([Math.round(r/n), Math.round(g/n), Math.round(b/n)]);
      } catch (e) { /* CORS or canvas tainted — fall through */ }
    };
    // Try the canvas-readable endpoint first; if it fails (e.g. Drive
    // blocks cross-origin reads for that file), give up silently and
    // let the card fall back to neutral charcoal dots.
    img.src = src;
    return () => { cancelled = true; };
  }, [src]);
  return rgb;
}

// — PatternedSneakerSlot —
// Drop-in replacement for the SneakerPlaceholder image area used on
// every product card across the site (homepage + full stock).
// Design rules (per user feedback):
//   • Card base is ALWAYS the same warm cream — never blends into the
//     shoe, no matter what colour the shoe is.
//   • The shoe's dominant colour drives the PATTERN ACCENTS only:
//     halftone dots + a chunky diagonal "ticker" stripe in a strip
//     down the right edge. That gives every card its own colour
//     identity without putting that colour behind the product.
//   • If the image fails to load (private Drive file, dead .webp
//     thumbnail) we register the SKU in BROKEN_IMG_CODES so the
//     homepage can roll over to the next product, and show a
//     monospace placeholder mark in place of the photo.
//   • Pattern is generated from RGB at runtime — no per-product config
//     needed in the sheet, every new product gets its tint for free.
function PatternedSneakerSlot({ item }) {
  const src = resolveImg(item);
  const dom = useDominantColor(src);
  const [failed, setFailed] = React.useState(false);

  // Reset failure state when the item changes — same instance can be
  // recycled for a different product.
  React.useEffect(() => { setFailed(false); }, [src]);

  // Always-cream base, with a hint of darker cream for tonal depth.
  const base = '#f1ede4';
  const baseDeep = '#e7e2d4';

  // Extract a "punchy" version of the dominant colour for the dot
  // pattern. We saturate it slightly so very muted product photos
  // (e.g. Jordan 4 Dark Mocha) still produce visible pattern accents.
  const accents = React.useMemo(() => {
    if (!dom) return {
      dot: 'rgba(22,17,13,0.18)',
      stripe: 'rgba(22,17,13,0.10)',
    };
    const [r, g, b] = dom;
    // Saturation boost — push channels away from grey.
    const max = Math.max(r, g, b);
    const avg = (r + g + b) / 3;
    const boost = (c) => {
      const diff = c - avg;
      return Math.max(0, Math.min(255, Math.round(avg + diff * 1.4)));
    };
    const R = boost(r), G = boost(g), B = boost(b);
    return {
      dot:    `rgba(${R}, ${G}, ${B}, 0.55)`,
      stripe: `rgba(${R}, ${G}, ${B}, 0.18)`,
    };
  }, [dom]);

  // Tile: small offset halftone dots + a single chunky diagonal slash
  // off the corner. Inline SVG, encoded as data URI for background-image.
  const tile = 18;
  const svg = encodeURIComponent(
    `<svg xmlns='http://www.w3.org/2000/svg' width='${tile}' height='${tile}' viewBox='0 0 ${tile} ${tile}'>` +
      `<circle cx='4' cy='4' r='1.8' fill='${accents.dot}'/>` +
      `<circle cx='13' cy='13' r='1.8' fill='${accents.dot}'/>` +
      `<line x1='-2' y1='4' x2='4' y2='-2' stroke='${accents.stripe}' stroke-width='1.4'/>` +
    `</svg>`
  );

  return (
    <div style={{
      position: 'relative', width: '100%', height: '100%',
      overflow: 'hidden',
      backgroundColor: base,
      backgroundImage:
        `url("data:image/svg+xml,${svg}"), ` +
        `linear-gradient(135deg, ${base} 0%, ${base} 70%, ${baseDeep} 100%)`,
      backgroundSize: `${tile}px ${tile}px, 100% 100%`,
      transition: 'background-image .35s',
    }}>
      {src && !failed && (
        <div style={{
          position: 'absolute', inset: 0,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          padding: '8%',
        }}>
          <img
            src={src}
            alt={item.model || ''}
            onError={() => { setFailed(true); markImageBroken(item.code); }}
            style={{
              maxWidth: '100%', maxHeight: '100%', width: 'auto', height: 'auto',
              objectFit: 'contain', display: 'block',
              mixBlendMode: 'darken',
              filter: 'drop-shadow(0 6px 12px rgba(22,17,13,0.20))',
            }}
          />
        </div>
      )}
      {(failed || !src) && (
        <div style={{
          position: 'absolute', inset: 0,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          flexDirection: 'column', gap: 6,
          fontFamily: "'JetBrains Mono', monospace",
          color: 'rgba(22,17,13,0.45)',
        }}>
          <svg width="48" height="48" viewBox="0 0 48 48" fill="none" aria-hidden="true">
            <rect x="6" y="32" width="36" height="2" fill="currentColor" />
            <path d="M8 32 Q 8 18 22 18 L 30 18 Q 36 18 40 24 L 42 30 Q 42 32 42 32 Z"
              fill="none" stroke="currentColor" strokeWidth="1.5" />
          </svg>
          <span style={{ fontSize: 10, letterSpacing: '.16em', textTransform: 'uppercase' }}>brak zdjęcia</span>
        </div>
      )}
    </div>
  );
}

// — SkeletonCard —
// Renders in place of a product while we wait for the sheet to load
// (first visit only — repeat visits paint from cache). Same pattern
// background as a real card; the text rows are flat charcoal bars
// that pulse gently. No "old" content ever leaks through.
function SkeletonCard({ rule, bg }) {
  return (
    <div style={{
      padding: 0, position: 'relative', background: bg || '#f1ede4',
    }}>
      <div style={{ aspectRatio: '4 / 3', borderBottom: rule, position: 'relative' }}>
        <PatternedSneakerSlot item={null} />
      </div>
      <div style={{ padding: '14px 14px 16px', display: 'flex', flexDirection: 'column', gap: 8 }}>
        <div className="va-skel" style={{ height: 16, width: '70%', background: 'rgba(22,17,13,.10)' }}></div>
        <div className="va-skel" style={{ height: 11, width: '40%', background: 'rgba(22,17,13,.08)' }}></div>
        <div className="va-skel" style={{ height: 11, width: '55%', background: 'rgba(22,17,13,.08)' }}></div>
      </div>
    </div>
  );
}
window.SkeletonCard = SkeletonCard;
window.FAQ = FAQ;
window.PROCESS = PROCESS;
window.I18N = I18N;
window.SneakerPlaceholder = SneakerPlaceholder;
window.resolveImg = resolveImg;
window.useStock = useStock;
window.useDominantColor = useDominantColor;
window.PatternedSneakerSlot = PatternedSneakerSlot;
window.useBrokenImages = useBrokenImages;
