// =============================================================================
// VITRINE DE ITENS — emotes (danças) e itens avulsos dentro da Z Shop
// =============================================================================
// Mesmo layout master-detail da Concessionária e do canil (`animalshop.jsx`):
//   ESQUERDA = os cards da seção (3D girando, borda na cor da raridade)
//   DIREITA  = palco do selecionado (3D grande, ficha, botão de compra)
//
// Por que não reusa o grid antigo de "PRATELEIRA": aquele grid é um card chapado
// sem 3D — foi feito quando os itens eram só texto. Emote e Caixa A.U.R.A. têm
// modelo, e modelo é o que o jogador compra com os olhos.
//
// 🔑 Zero tabela de produto aqui. Título, preço, modelo e os "fatos" saem do
// `metadata` do próprio produto — igual `carshop.jsx` e `animalshop.jsx`.
// Duplicar dado no JS é o erro que já mordeu o projeto: a UI passa a mentir no
// dia em que o banco muda.
// =============================================================================

const IT_RARIDADE = {
  comum:    { label: 'COMUM',    cor: '#B2B2B2' },
  incomum:  { label: 'INCOMUM',  cor: '#4CE64C' },
  raro:     { label: 'RARO',     cor: '#3075FF' },
  epico:    { label: 'EPICO',    cor: '#B34CE6' },
  lendario: { label: 'LENDARIO', cor: '#FFA000' },
};
function itRar(r) { return IT_RARIDADE[r] || { label: (r || '').toUpperCase(), cor: '#B2B2B2' }; }
function itFmt(n) { return Number(n || 0).toLocaleString('pt-BR'); }

// --- CSS próprio --------------------------------------------------------------
// 🪤 Antes esta vitrine usava as classes `gz-cs-*` da Concessionária, e a
// Concessionária só injeta o CSS dela quando ELA aparece. Com a loja de carros
// desligada (`car_shop_config.enabled = false`, que é exatamente o estado até o
// Henrique abrir), emotes e itens perdiam o grid e viravam uma coluna esticada —
// sem erro nenhum no console. Agora a seção não depende de outra seção.
function ensureItensCss() {
  if (document.getElementById('gz-itens-css')) return;
  const st = document.createElement('style');
  st.id = 'gz-itens-css';
  st.textContent = `
    @keyframes gzItFadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
    .gz-it-wrap { display: grid; grid-template-columns: minmax(300px, 480px) minmax(0, 1fr); gap: 18px; align-items: stretch; }
    /* 🪤 align-content:start deixava o card com a altura MINIMA e a area 3D ficava
       com 156px — a Aurora dancando saia com a cabeca cortada. A vitrine de animais
       (que ele apontou como referencia) usa stretch, e la a area 3D mede 218px.
       Medido nos dois em 23/08. A altura vem do minHeight da area 3D do card, NAO de
       align-content:stretch -- com 2 cards numa linha so, stretch estica a linha ate a
       altura do palco e o card sai com 672px (medido).
       🚨 CUIDADO: este bloco e' um TEMPLATE LITERAL. Acento grave aqui dentro FECHA
       a string e quebra o arquivo -- foi o que aconteceu ao escrever este comentario. */
    .gz-it-list { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; align-content: start; }
    .gz-it-item { cursor: pointer; }
    .gz-it-item model-viewer { pointer-events: none; }
    .gz-it-fade { animation: gzItFadeIn .3s ease; }
    .gz-it-chips { display: flex; gap: 7px; flex-wrap: wrap; }
    .gz-it-chip { background: none; padding: 0; cursor: pointer; line-height: 0; transition: transform .15s ease, box-shadow .15s ease; }
    .gz-it-chip:hover { transform: translateY(-2px); }
    @media (max-width: 920px) { .gz-it-wrap { grid-template-columns: 1fr; } }
    @media (max-width: 430px) { .gz-it-list { grid-template-columns: 1fr; } }
  `;
  document.head.appendChild(st);
}

// --- enquadramento: MEDIR, nunca cravar --------------------------------------
// A Aurora tem ~1,8 de altura e a caixa ~0,5. `camera-target` fixo enquadra um e
// corta o outro, então a página mede a caixa do modelo quando ele carrega e mira
// no centro dela. Fator MAIOR = objeto mais baixo no quadro.
const IT_OLHAR_PALCO = 0.86;
const IT_OLHAR_CARD = 0.92;

function itMirar(mv, fator) {
  if (!mv || mv._genzMirado) return;
  mv._genzMirado = true;
  mv.addEventListener('load', () => {
    try {
      const c = mv.getBoundingBoxCenter();
      mv.cameraTarget = `${c.x.toFixed(3)}m ${(c.y * fator).toFixed(3)}m ${c.z.toFixed(3)}m`;
      mv.jumpCameraToGoal();
    } catch (e) { /* sem caixa ainda: o padrão do model-viewer já centraliza */ }
  });
}

// Borda: 3px em cima na cor da raridade, 1px nos outros lados.
// 🪤 LONGHAND de propósito — `border` + `borderTop` no mesmo objeto de estilo faz
// o React avisar "mixing shorthand and non-shorthand", e o aviso é legítimo: numa
// re-renderização a ordem não é garantida e a borda fica com a cor do card anterior.
function itBorda(cor, selecionado) {
  const lado = selecionado ? cor : cor + '33';
  return {
    borderStyle: 'solid',
    borderTopWidth: 3, borderRightWidth: 1, borderBottomWidth: 1, borderLeftWidth: 1,
    borderTopColor: cor, borderRightColor: lado, borderBottomColor: lado, borderLeftColor: lado,
  };
}

// --- os "fatos" da ficha ------------------------------------------------------
// Não são barras (emote e caixa não têm escala de 0 a 100 — comparar dança com
// dança por barra seria inventar número). São pares rótulo/valor lidos do
// metadata, na ordem em que interessam.
function itFatos(md) {
  const f = [];
  if (md.musicas) f.push(['MÚSICAS', md.musicas + ' aleatórias']);
  if (md.addon_de) f.push(['ADDON DE', md.addon_de]);
  if (md.capacidade) f.push(['ESPAÇO', md.capacidade + ' (o dobro da caixa militar)']);
  if (md.empilha) f.push(['EMPILHA', 'até ' + md.empilha]);
  if (md.tranca) f.push(['TRANCA', md.tranca]);
  return f;
}

// --- famílias: 100 linhas no banco, UM card na tela ---------------------------
// A Caixa A.U.R.A. são 10 cores × 10 marcas = 100 itens DIFERENTES no jogo, e a
// entrega é indexada pelo SKU — por isso são 100 produtos. Mas 100 cards seria
// uma parede de caixa igual: o jogador escolhe cor e marca, não "produto 47".
// Agrupa por `metadata.grupo`; produto sem grupo continua sendo o próprio card.
function itAgrupar(lista) {
  const ordem = [], por = {};
  (lista || []).forEach(p => {
    const md = p.metadata || {};
    const id = md.grupo ? ('g:' + md.grupo) : p.sku;
    if (!por[id]) {
      por[id] = { id, grupo: md.grupo || null, titulo: md.grupo_titulo || p.title, variantes: [] };
      ordem.push(id);
    }
    por[id].variantes.push(p);
  });
  return ordem.map(id => por[id]);
}

// As opções de um eixo (cor, marca), na ordem em que o catálogo as declarou e
// sem repetir. Sai das PRÓPRIAS variantes: nenhuma lista de cor escrita no JS.
function itEixo(variantes, chave, rotulo, extra) {
  const visto = {}, saida = [];
  variantes.forEach(p => {
    const md = p.metadata || {};
    const k = md[chave];
    if (k && !visto[k]) { visto[k] = 1; saida.push({ k, nome: md[rotulo] || k, extra: md[extra] }); }
  });
  return saida;
}

// --- pintar o 3D ao vivo ------------------------------------------------------
// Mesmo mecanismo que a Concessionária já usa pra trocar a pintura do carro:
// `createTexture` + `setTexture` no material pelo NOME. Aqui são dois materiais
// (a caixa e o decalque do símbolo), e os nomes vêm do metadata — nada de string
// mágica no JS.
// 🪤 Clique rápido dispara vários `await` que voltam fora de ordem: sem o
// carimbo, a última cor clicada podia perder pra uma anterior que demorou mais.
async function itPintar(mv, pinturas, chave) {
  if (!mv || !mv.model || !pinturas || !pinturas.length) return;
  mv._genzPintura = chave;
  for (const p of pinturas) {
    const m = (mv.model.materials || []).find(x => x.name === p.material);
    if (!m) { console.warn('[GZ] o glb não tem o material', p.material); continue; }
    const slot = m.pbrMetallicRoughness && m.pbrMetallicRoughness.baseColorTexture;
    if (!slot) { console.warn('[GZ] material sem slot de cor:', p.material); continue; }
    try {
      const tex = await mv.createTexture(p.url);
      if (mv._genzPintura !== chave) return;   // já pediram outra coisa
      slot.setTexture(tex);
    } catch (e) { console.warn('[GZ] textura não carregou:', p.url, e); }
  }
}

function itPinturas(md) {
  const mat = md.materiais;
  if (!mat) return null;
  const out = [];
  if (mat.cor && md.textura) out.push({ material: mat.cor, url: md.textura });
  if (mat.simbolo && md.simbolo) out.push({ material: mat.simbolo, url: md.simbolo });
  return out.length ? out : null;
}

// --- 3D, ou um lugar honesto no lugar dele -----------------------------------
// Enquanto o modelo não existe, o palco NÃO fica vazio: um buraco leva o olho a
// achar que a arte quebrou. Diz o que vai estar ali.
function ItPalco3D({ produto, fator, orbita, controles, pinturas }) {
  const md = produto.metadata || {};
  const [morreu, setMorreu] = React.useState(false);
  const mvRef = React.useRef(null);
  const chave = (pinturas || []).map(x => x.material + '=' + x.url).join('|');

  // 🪤 Este efeito fica ANTES do return de "sem modelo": hook depois de return
  // condicional muda a ordem dos hooks entre renderizações e o React quebra.
  React.useEffect(() => {
    const mv = mvRef.current;
    if (!mv || !chave) return;
    let vivo = true;
    const aplicar = () => { if (vivo) itPintar(mv, pinturas, chave); };
    if (mv.model) aplicar();          // já carregado: pinta agora
    mv.addEventListener('load', aplicar);
    return () => { vivo = false; mv.removeEventListener('load', aplicar); };
  }, [chave]);

  if (!md.model || morreu) {
    return (
      <div style={{
        width: '100%', height: '100%', display: 'flex', flexDirection: 'column',
        alignItems: 'center', justifyContent: 'center', gap: 8, textAlign: 'center', padding: 16,
      }}>
        <div style={{ fontFamily: 'Share Tech Mono', fontSize: 10, letterSpacing: '.16em', color: 'rgba(255,255,255,.32)' }}>3D</div>
        <div style={{ fontFamily: 'Rajdhani', fontWeight: 700, fontSize: 15, textTransform: 'uppercase', color: 'rgba(255,255,255,.5)', lineHeight: 1.2 }}>
          {md.model3d_texto || 'modelo a caminho'}
        </div>
      </div>
    );
  }
  // 🪤 `onError` de JSX NAO funciona em custom element no React 18 (vira
  // atributo e nunca dispara). O aviso de modelo que nao carregou tem que ser
  // ouvido no proprio elemento — senao o palco fica com um buraco preto e
  // parece que a pagina quebrou.
  const ligar = (el) => {
    if (!el) return;
    mvRef.current = el;
    itMirar(el, fator);
    if (!el._genzErro) {
      el._genzErro = true;
      el.addEventListener('error', () => setMorreu(true));
    }
  };

  return (
    <model-viewer src={md.model} alt={produto.title} loading="lazy"
      animation-name={md.anim || undefined} autoplay={md.anim ? '' : undefined}
      auto-rotate="" auto-rotate-delay="0" rotation-per-second={controles ? '8deg' : '20deg'}
      camera-controls={controles ? '' : undefined} disable-zoom={controles ? '' : undefined}
      disable-pan={controles ? '' : undefined}
      interaction-prompt="none" shadow-intensity={controles ? '1' : '0.7'} exposure="1.1"
      camera-orbit={orbita} min-camera-orbit="auto auto 55%"
      orientation={md.orient || undefined}
      ref={ligar}
      style={{ width: '100%', height: '100%', background: 'transparent' }} />
  );
}

// --- card da lista ------------------------------------------------------------
// `p` é a variante em foco (num grupo, a combinação escolhida); `titulo`/`sub`
// são o que aparece escrito, que num grupo é o nome da família + a escolha.
function ItemCard({ p, id, titulo, sub, selected, onSelect }) {
  const r = itRar(p.rarity);
  const md = p.metadata || {};
  const ref = React.useRef(null);

  const onMove = (e) => {
    const el = ref.current; if (!el) return;
    const b = el.getBoundingClientRect();
    const px = (e.clientX - b.left) / b.width;
    const py = (e.clientY - b.top) / b.height;
    const MAX = 8;
    el.style.transform = `rotateX(${((0.5 - py) * 2 * MAX).toFixed(2)}deg) rotateY(${((px - 0.5) * 2 * MAX).toFixed(2)}deg) scale(1.03)`;
    el.style.setProperty('--gx', (px * 100).toFixed(1) + '%');
    el.style.setProperty('--gy', (py * 100).toFixed(1) + '%');
  };
  const reset = () => { if (ref.current) ref.current.style.transform = 'rotateX(0deg) rotateY(0deg) scale(1)'; };

  return (
    <div className="gz-it-item" style={{ perspective: 900 }} onClick={() => onSelect(id || p.sku)}>
      <div ref={ref} onMouseMove={onMove} onMouseLeave={reset} style={{
        position: 'relative', display: 'flex', flexDirection: 'column', height: '100%',
        transformStyle: 'preserve-3d', willChange: 'transform', transition: 'transform .25s ease',
        background: `linear-gradient(165deg, ${r.cor}26 0%, #202020 55%, #1a1a1a 100%)`,
        ...itBorda(r.cor, selected),
        boxShadow: selected ? `0 12px 36px ${r.cor}3d` : '0 8px 24px rgba(0,0,0,.35)',
      }}>
        <div style={{
          position: 'absolute', inset: 0, pointerEvents: 'none', zIndex: 5,
          background: `radial-gradient(circle at var(--gx,50%) var(--gy,50%), ${r.cor}24 0%, transparent 48%)`,
        }} />
        <div style={{
          position: 'absolute', top: 10, right: 10, zIndex: 6, transform: 'translateZ(34px)',
          background: r.cor + '1c', border: `1px solid ${r.cor}55`, color: r.cor,
          fontFamily: 'Share Tech Mono', fontSize: 9.5, padding: '3px 8px', letterSpacing: '0.12em',
        }}>{r.label}</div>

        <div style={{
          // 218 = a MESMA area 3D da vitrine da fazenda, que ele deu de referencia
          // (medido: fazenda 243x218, emotes tinham 243x156 e cortavam a cabeca).
          position: 'relative', flex: 1, minHeight: 218, transform: 'translateZ(44px)',
          background: `radial-gradient(ellipse at 50% 80%, ${r.cor}2e 0%, transparent 66%)`,
        }}>
          <ItPalco3D produto={p} fator={IT_OLHAR_CARD} controles={false}
            orbita={md.orbita_card || '223deg 77deg 96%'} pinturas={itPinturas(md)} />
        </div>

        <div style={{ padding: '8px 12px 12px', display: 'flex', flexDirection: 'column', gap: 5, flexShrink: 0, transform: 'translateZ(18px)' }}>
          <div style={{
            fontFamily: 'Rajdhani', fontWeight: 700, fontSize: 13.5, textTransform: 'uppercase',
            lineHeight: 1.12, color: selected ? '#fff' : 'rgba(255,255,255,.85)',
          }}>{titulo || p.title}</div>
          {sub && (
            <div style={{
              fontFamily: 'Share Tech Mono', fontSize: 10, letterSpacing: '.1em',
              color: 'rgba(255,255,255,.5)', textTransform: 'uppercase',
            }}>{sub}</div>
          )}
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
            <span style={{ fontFamily: 'Share Tech Mono', fontSize: 13, color: '#a8ff00' }}>
              {itFmt(p.price_credits)} <span style={{ fontSize: 10, color: 'rgba(255,255,255,.55)' }}>ZB</span>
            </span>
            {selected && <span style={{ color: r.cor, fontFamily: 'Share Tech Mono', fontSize: 12 }}>▸ NO PALCO</span>}
          </div>
        </div>
      </div>
    </div>
  );
}

// --- a vitrine ----------------------------------------------------------------
function ItemShowcase({ produtos, entrega, session, wallet, busy, onBuy, onNavigate }) {
  const { useState } = React;
  const entradas = itAgrupar(produtos);
  const [selId, setSelId] = useState(entradas.length ? entradas[0].id : null);
  const [escolhas, setEscolhas] = useState({});     // id do grupo -> {cor, categoria}
  React.useEffect(() => { ensureItensCss(); }, []);
  if (!entradas.length) return null;

  // A variante em foco de uma entrada: num grupo é a combinação escolhida; sem
  // grupo é o único produto. Escolha parcial cai na 1ª que casa — nunca "nada".
  function focoDe(e) {
    const esc = escolhas[e.id] || {};
    return e.variantes.find(v => {
      const m = v.metadata || {};
      return (!esc.cor || m.cor === esc.cor) && (!esc.categoria || m.categoria === esc.categoria);
    }) || e.variantes[0];
  }
  function itSub(e) {
    const m = focoDe(e).metadata || {};
    return e.grupo && m.cor_nome ? (m.cor_nome + ' · ' + (m.categoria_nome || '')) : null;
  }

  const ent = entradas.find(x => x.id === selId) || entradas[0];
  const p = focoDe(ent);
  const md = p.metadata || {};
  const r = itRar(p.rarity);
  const fatos = itFatos(md);
  const canAfford = session && wallet && (wallet.balance || 0) >= p.price_credits;
  const isBusy = busy === p.sku;

  // A escolha atual sai sempre da variante em foco, não de um estado paralelo:
  // assim o seletor nunca mostra marcado algo diferente do que está no palco.
  // 🪤 A base vem de `prev`, NUNCA do `md` do fechamento. Duas trocas no mesmo
  // lote do React (trocar cor e marca antes de um re-render) liam o `md` velho e
  // a segunda desfazia a primeira — a caixa voltava pra cor anterior sozinha.
  function escolher(eixo, valor) {
    setEscolhas(prev => {
      const atual = prev[ent.id] || { cor: md.cor, categoria: md.categoria };
      return Object.assign({}, prev, { [ent.id]: Object.assign({}, atual, { [eixo]: valor }) });
    });
  }

  const cores = ent.grupo ? itEixo(ent.variantes, 'cor', 'cor_nome', 'cor_hex') : [];
  const marcas = ent.grupo ? itEixo(ent.variantes, 'categoria', 'categoria_nome', 'simbolo') : [];

  return (
    <div className="gz-it-wrap">
      <div className="gz-it-list">
        {entradas.map(e => {
          const f = focoDe(e);
          return <ItemCard key={e.id} id={e.id} p={f} titulo={e.titulo} sub={itSub(e)}
            selected={e.id === ent.id} onSelect={setSelId} />;
        })}
      </div>

      <div key={ent.id} className="gz-it-fade" style={{
        position: 'relative', overflow: 'hidden', display: 'flex', flexDirection: 'column',
        background: `linear-gradient(160deg, ${r.cor}20 0%, #1e1e1e 45%, #191919 100%)`,
        ...itBorda(r.cor, true),
        clipPath: 'polygon(0 0, calc(100% - 16px) 0, 100% 16px, 100% 100%, 16px 100%, 0 calc(100% - 16px))',
      }}>
        <div style={{
          position: 'absolute', top: 14, right: 16, zIndex: 3,
          background: r.cor + '1c', border: `1px solid ${r.cor}55`, color: r.cor,
          fontFamily: 'Share Tech Mono', fontSize: 10, padding: '4px 11px', letterSpacing: '0.14em',
        }}>{r.label}</div>

        <div style={{
          position: 'relative', height: 400,
          background: `radial-gradient(ellipse at 50% 82%, ${r.cor}34 0%, transparent 62%)`,
        }}>
          <ItPalco3D produto={p} fator={IT_OLHAR_PALCO} controles={true}
            orbita={md.orbita_palco || '225deg 74deg 94%'} pinturas={itPinturas(md)} />
          {md.model && (
            <div style={{
              position: 'absolute', left: 16, bottom: 10, fontFamily: 'Share Tech Mono',
              fontSize: 9.5, color: 'rgba(255,255,255,.5)', letterSpacing: '.14em', pointerEvents: 'none',
            }}>3D · ARRASTE PRA GIRAR</div>
          )}
        </div>

        <div style={{ padding: '16px 20px 20px', display: 'flex', flexDirection: 'column', gap: 14, flex: 1 }}>
          <div style={{ fontFamily: 'Rajdhani', fontWeight: 700, fontSize: 'clamp(20px,2.4vw,27px)', textTransform: 'uppercase', lineHeight: 1.05 }}>
            {p.title}
          </div>

          <p style={{ fontSize: 13, color: 'rgba(255,255,255,.68)', lineHeight: 1.6, margin: 0 }}>
            {p.description}
          </p>

          {/* seletores: só aparecem quando há mais de uma opção no eixo.
              A cor da bolinha é a AMOSTRA medida na peça renderizada (vem no
              metadata), não a tinta — senão o botão promete um tom e o 3D
              entrega outro. */}
          {cores.length > 1 && (
            <div style={{ display: 'flex', flexDirection: 'column', gap: 7 }}>
              <span style={{ fontFamily: 'Share Tech Mono', fontSize: 9.5, color: 'rgba(255,255,255,.5)', letterSpacing: '.12em' }}>
                COR — {md.cor_nome}
              </span>
              <div className="gz-it-chips">
                {cores.map(c => {
                  const on = c.k === md.cor;
                  return (
                    <button className="gzb" key={c.k} type="button" title={c.nome} aria-label={'Cor ' + c.nome}
                      aria-pressed={on} onClick={() => escolher('cor', c.k)} className="gz-it-chip gzb"
                      style={{
                        width: 30, height: 30, background: c.extra,
                        borderStyle: 'solid', borderWidth: on ? 2 : 1,
                        borderColor: on ? '#fff' : 'rgba(255,255,255,.28)',
                        boxShadow: on ? `0 0 9px ${c.extra}` : 'none',
                      }} />
                  );
                })}
              </div>
            </div>
          )}

          {marcas.length > 1 && (
            <div style={{ display: 'flex', flexDirection: 'column', gap: 7 }}>
              <span style={{ fontFamily: 'Share Tech Mono', fontSize: 9.5, color: 'rgba(255,255,255,.5)', letterSpacing: '.12em' }}>
                MARCA DA FRENTE — {md.categoria_nome}
              </span>
              <div className="gz-it-chips">
                {marcas.map(c => {
                  const on = c.k === md.categoria;
                  return (
                    <button className="gzb" key={c.k} type="button" title={c.nome} aria-label={'Marca ' + c.nome}
                      aria-pressed={on} onClick={() => escolher('categoria', c.k)} className="gz-it-chip gzb"
                      style={{
                        width: 34, height: 34, padding: 4, background: on ? r.cor + '26' : 'rgba(255,255,255,.05)',
                        borderStyle: 'solid', borderWidth: 1,
                        borderColor: on ? r.cor : 'rgba(255,255,255,.18)',
                      }}>
                      <img src={c.extra} alt="" width="24" height="24"
                        style={{ display: 'block', opacity: on ? 1 : 0.55 }} />
                    </button>
                  );
                })}
              </div>
            </div>
          )}

          {fatos.length > 0 && (
            <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
              {fatos.map(([k, v]) => (
                <div key={k} style={{ display: 'flex', alignItems: 'baseline', gap: 12 }}>
                  <span style={{
                    fontFamily: 'Share Tech Mono', fontSize: 9.5, color: 'rgba(255,255,255,.5)',
                    letterSpacing: '.12em', width: 96, flexShrink: 0,
                  }}>{k}</span>
                  <span style={{ fontSize: 13, color: 'rgba(255,255,255,.82)', lineHeight: 1.4 }}>{v}</span>
                </div>
              ))}
            </div>
          )}

          <div style={{ display: 'flex', alignItems: 'center', gap: 14, marginTop: 'auto', flexWrap: 'wrap' }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              {window.ZbIcon ? <window.ZbIcon size={24} /> : null}
              <span style={{ fontFamily: 'Share Tech Mono', fontSize: 28, color: '#a8ff00', lineHeight: 1 }}>{itFmt(p.price_credits)}</span>
              <span style={{ fontSize: 12, color: 'rgba(255,255,255,.5)' }}>ZB</span>
            </div>
            {window.GzSeloValidade ? <window.GzSeloValidade categoria={p.category} /> : null}
            <button className="gzb" onClick={() => session ? onBuy(p) : (onNavigate && onNavigate('auth'))} disabled={isBusy} style={{
              flex: '1 1 180px', maxWidth: 320, padding: '14px 22px',
              background: !session ? 'transparent' : (canAfford ? r.cor : 'rgba(255,255,255,.06)'),
              color: !session ? '#a8ff00' : (canAfford ? '#111' : 'rgba(255,255,255,.4)'),
              border: !session ? '1px solid rgba(168,255,0,.4)' : 'none',
              fontFamily: 'Rajdhani', fontWeight: 700, fontSize: 15, letterSpacing: '0.12em',
              cursor: isBusy ? 'wait' : 'pointer', textTransform: 'uppercase', transition: 'all .2s',
              clipPath: 'polygon(0 0, calc(100% - 9px) 0, 100% 9px, 100% 100%, 9px 100%, 0 calc(100% - 9px))',
            }}>
              {!session ? 'Entrar pra comprar' : isBusy ? 'Comprando...' : 'Comprar'}
            </button>
          </div>

          <div style={{ fontFamily: 'Share Tech Mono', fontSize: 10.5, color: 'rgba(255,255,255,.5)', letterSpacing: '.04em', lineHeight: 1.6 }}>
            {entrega}
          </div>

          {/* Crédito de licença. Os símbolos são CC BY 3.0 (game-icons.net): usar
              pode, inclusive comercialmente, mas o crédito é OBRIGATÓRIO — e a
              página que mostra os símbolos é onde ele tem que aparecer. */}
          {md.creditos && (
            <div style={{ fontFamily: 'Share Tech Mono', fontSize: 9.5, color: 'rgba(255,255,255,.3)', letterSpacing: '.04em' }}>
              {md.creditos}
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { ItemShowcase });
