/* eslint-disable */
/* Nova Materia Ceramics — Screens (assemble components into pages) */

const HOME_FEATURED_COLLECTION_IDS = [
  'cotto-milano',
  'dual-travertine',
  'pietra-di-orosei',
  'gemmastone',
  'tele-di-marmo-lumia',
  'trevi',
];

const HomeScreen = ({ onNav, onOpenProduct }) => {
  const featuredFromResearch = HOME_FEATURED_COLLECTION_IDS
    .map(id => window.NM_PRODUCTS.find(p => p.id === id))
    .filter(Boolean);
  const featuredFallback = window.NM_PRODUCTS
    .filter(p => p.tag && !HOME_FEATURED_COLLECTION_IDS.includes(p.id))
    .slice(0, Math.max(0, 6 - featuredFromResearch.length));
  const featured = featuredFromResearch.concat(featuredFallback).slice(0, 6);
  return (
    <>
      <Hero onNav={onNav} />
      <BrandBar />
      <ServizioStrip />
      <Section eyebrow="Catálogo · colecciones principales">
        <div className="nm-section-head">
          <h2 className="nm-section-h2">
            Colecciones <em>destacadas</em>.
          </h2>
          <a className="nm-link" onClick={() => onNav('catalog')}>Ver todo el catálogo →</a>
        </div>
        <ProductGrid products={featured} onOpen={onOpenProduct} />
      </Section>
      <ItaliaLockup />
      <ProBlock onNav={onNav} />
      <section className="nm-section nm-section-dark nm-section-padded">
        <div className="nm-container">
          <div className="nm-positioning">
            <span className="nm-eyebrow" style={{ color: 'var(--cotto-300)' }}>Quiénes somos</span>
            <p className="nm-positioning-quote">
              El catálogo completo de <em>Emilgroup</em> y <em>Keope</em>, directo desde Sassuolo <em>a tu proyecto</em> en Barcelona.
            </p>
            <div className="nm-positioning-grid">
              <div className="nm-positioning-stat">
                <span className="nm-positioning-num">4</span>
                <span className="nm-positioning-label">Marcas italianas</span>
                <span className="nm-positioning-sub">Emil · Ergon · Provenza · Keope</span>
              </div>
              <div className="nm-positioning-stat">
                <span className="nm-positioning-num">+200</span>
                <span className="nm-positioning-label">Colecciones</span>
                <span className="nm-positioning-sub">Mármol · Piedra · Cemento · Madera</span>
              </div>
              <div className="nm-positioning-stat">
                <span className="nm-positioning-num">48h</span>
                <span className="nm-positioning-label">Visita comercial</span>
                <span className="nm-positioning-sub">Barcelona y provincia</span>
              </div>
            </div>
          </div>
        </div>
      </section>
      <Section eyebrow="Empieza" narrow>
        <h2 className="nm-cta-h2">
          ¿Listo para tu próximo <em>proyecto</em>?
        </h2>
        <p className="nm-cta-p">
          Activa tu cuenta profesional y recibe muestras, fichas técnicas
          y condiciones para tu estudio o tienda.
        </p>
        <div className="nm-cta-actions">
          <button className="nm-btn nm-btn-primary nm-btn-lg" onClick={() => onNav('pros')}>
            Activar cuenta profesional <span className="nm-arrow">→</span>
          </button>
          <button className="nm-btn nm-btn-ghost nm-btn-lg" onClick={() => onNav('contact')}>
            Contactar con comercial
          </button>
        </div>
      </Section>
    </>
  );
};

const LoginScreen = ({ onNav }) => (
  <Section eyebrow="Zona profesional" narrow>
    <div className="nm-login">
      <h2 className="nm-section-h2">Acceso <em>cliente</em>.</h2>
      <p className="nm-form-intro">
        Solo para tiendas y estudios con cuenta activa en Nova Materia Ceramics.
        ¿No tienes acceso? <a className="nm-link" onClick={() => onNav('contact')}>Solicita invitación</a>.
      </p>
      <form className="nm-form nm-form-narrow" onSubmit={(e) => e.preventDefault()}>
        <div className="nm-field nm-field-full">
          <label>Email profesional</label>
          <input className="nm-input" type="email" placeholder="contacto@estudio.es" />
        </div>
        <div className="nm-field nm-field-full">
          <label>Contraseña</label>
          <input className="nm-input" type="password" placeholder="••••••••" />
        </div>
        <div className="nm-field-full">
          <button className="nm-btn nm-btn-primary nm-btn-lg" type="submit">
            Entrar <span className="nm-arrow">→</span>
          </button>
          <p className="nm-form-note">¿Olvidaste la contraseña? Escríbenos a novamateriaceramics@gmail.com</p>
        </div>
      </form>
    </div>
  </Section>
);

const ClientScreen = ({ onNav, onOpenProduct, activeClient, setActiveClient }) => {
  const createClientSession = (email) => {
    const cleanEmail = email.trim().toLowerCase();
    const nameFromEmail = cleanEmail.split('@')[0]
      .replace(/[._-]+/g, ' ')
      .replace(/\b\w/g, ch => ch.toUpperCase()) || 'Cliente';
    return {
      id: `client-${Date.now()}`,
      email: cleanEmail,
      company: nameFromEmail,
      contact: nameFromEmail,
      type: 'Cliente profesional',
      zone: 'Barcelona y provincia',
      orders: [],
    };
  };
  const [login, setLogin] = useState({ email: '', code: '' });
  const [loginError, setLoginError] = useState('');
  const [authLoading, setAuthLoading] = useState(false);
  const [supabaseState, setSupabaseState] = useState({ loading: true, ready: false, error: '', client: null, adminEmails: [] });
  const [adminAction, setAdminAction] = useState({ loading: false, message: '', error: '' });
  const [newClientForm, setNewClientForm] = useState({ email: '', password: '', company: '', contact: '', type: 'Cliente profesional', zone: 'Barcelona y provincia' });
  const [newOrderForm, setNewOrderForm] = useState({ client_id: '', order_ref: '', project: '', brand: '', material: '', format: '', finish: '', sqm: '', status: 'Consulta' });
  const [query, setQuery] = useState('');
  const [visualSearch, setVisualSearch] = useState(() => {
    try {
      return JSON.parse(window.sessionStorage.getItem('nmVisualSearch') || 'null') || { image: '', tone: null, matches: [] };
    } catch (e) {
      return { image: '', tone: null, matches: [] };
    }
  });
  const [selectedVisualItem, setSelectedVisualItem] = useState(null);
  const products = window.NM_PRODUCTS || [];
  const featuredIds = ['gemmastone', 'unique-travertine', 'tele-di-marmo-onyx', 'i-wood', 'abacus', 'dual-travertine'];
  const featured = featuredIds
    .map(id => products.find(p => p.id === id))
    .filter(Boolean);
  const normalizedQuery = query.trim().toLowerCase();
  const results = products
    .filter(p => {
      if (!normalizedQuery) return featured.some(f => f.id === p.id);
      const haystack = [
        p.brand,
        p.name,
        p.collection,
        p.type,
        ...(p.specs || []),
        ...(p.formats || []),
        ...(p.finishes || []),
        ...(p.colors || []),
      ].join(' ').toLowerCase();
      return haystack.includes(normalizedQuery);
    })
    .slice(0, 8);
  const quickSearches = ['GemmaStone', 'Travertine', 'R11', '120×278', 'Madera', 'Mosaico'];
  const clientTools = activeClient ? [
    ['01', 'Pedidos', `${activeClient.orders.length} pedidos y consultas registrados.`],
    ['02', 'Material', `${activeClient.orders.reduce((sum, o) => sum + o.sqm, 0)} m2 totales en seguimiento.`],
    ['03', 'Soporte', 'Ficha, plazo y condiciones siempre centralizados.'],
  ] : [
    ['01', 'Acceso privado', 'Cada cliente entra con email y contraseña asignada por Nova Materia Ceramics.'],
    ['02', 'Pedidos y m2', 'Historial de materiales, formatos, acabados, m2 y estado.'],
    ['03', 'Repetir pedido', 'Localiza una serie anterior y pide ficha, muestra o nuevo presupuesto.'],
  ];
  const savedRequests = activeClient ? [
    ['Cliente', `${activeClient.company} · ${activeClient.type}`],
    ['Zona', activeClient.zone],
    ['Última actualización', activeClient.orders[0]?.date || 'Pendiente'],
  ] : [];
  const countBy = (items, key) => items.reduce((acc, item) => {
    const value = item[key] || 'Sin dato';
    acc[value] = (acc[value] || 0) + 1;
    return acc;
  }, {});
  const topEntry = (counts) => Object.entries(counts).sort((a, b) => b[1] - a[1])[0] || ['-', 0];
  const orders = activeClient ? activeClient.orders : [];
  const totalSqm = orders.reduce((sum, order) => sum + order.sqm, 0);
  const activeOrders = orders.filter(order => order.status !== 'Entregado').length;
  const topMaterial = topEntry(countBy(orders, 'material'));
  const topBrand = topEntry(countBy(orders, 'brand'));
  const topFormat = topEntry(countBy(orders, 'format'));
  const averageSqm = orders.length ? Math.round(totalSqm / orders.length) : 0;
  const materialBreakdown = Object.entries(countBy(orders, 'material'))
    .map(([name, count]) => ({
      name,
      count,
      sqm: orders.filter(order => order.material === name).reduce((sum, order) => sum + order.sqm, 0),
    }))
    .sort((a, b) => b.sqm - a.sqm);
  const statusBreakdown = Object.entries(countBy(orders, 'status'))
    .map(([name, count]) => ({ name, count }));
  const normalizeVisualText = (value) => String(value || '')
    .toLowerCase()
    .normalize('NFD')
    .replace(/[\u0300-\u036f]/g, '');
  const visualToneRules = [
    { keys: ['extra white', 'white', 'bianco', 'blanco', 'calce', 'sale', 'cotton'], rgb: [232, 228, 216], family: 'claro' },
    { keys: ['ivory', 'avorio', 'cream', 'crema', 'almond', 'mandorla', 'bone'], rgb: [218, 205, 184], family: 'calido claro' },
    { keys: ['silver', 'plata', 'grigio chiaro', 'gris claro', 'light grey'], rgb: [176, 174, 166], family: 'gris claro' },
    { keys: ['grey', 'gray', 'gris', 'grigio', 'cenere', 'ash', 'cemento', 'concrete'], rgb: [132, 132, 126], family: 'cemento' },
    { keys: ['dark grey', 'antracite', 'anthracite', 'carbone', 'nero', 'black', 'basalto', 'labradorite'], rgb: [54, 55, 54], family: 'oscuro' },
    { keys: ['beige', 'greige', 'sabbia', 'sand', 'arena', 'taupe', 'dune'], rgb: [184, 164, 133], family: 'beige' },
    { keys: ['travertine', 'travertino', 'vein cut', 'cross cut'], rgb: [194, 177, 145], family: 'travertino' },
    { keys: ['stone', 'piedra', 'pietra', 'bourg', 'limestone', 'orosei'], rgb: [154, 148, 132], family: 'piedra' },
    { keys: ['marmo', 'marble', 'onyx', 'statuario', 'calacatta', 'crystal'], rgb: [210, 205, 194], family: 'marmol' },
    { keys: ['cotto', 'terracotta', 'mattone', 'rosso', 'rosato', 'amaranto', 'clay'], rgb: [168, 91, 60], family: 'cotto' },
    { keys: ['wood', 'madera', 'rovere', 'oak', 'noce', 'walnut', 'dorato', 'imbrunito', 'tortora'], rgb: [148, 111, 76], family: 'madera' },
    { keys: ['petrolio', 'green', 'verde', 'sage', 'salvia'], rgb: [78, 118, 104], family: 'verde' },
    { keys: ['blue', 'blu', 'avio', 'azure', 'azzurro'], rgb: [82, 108, 134], family: 'azul' },
  ];
  const familyAliases = {
    marmol: ['marmol', 'piedra', 'travertino'],
    travertino: ['travertino', 'piedra', 'marmol'],
    piedra: ['piedra', 'travertino', 'cemento'],
    cemento: ['cemento', 'piedra', 'resina'],
    madera: ['madera'],
    cotto: ['cotto', 'terracotta'],
    oscuro: ['oscuro', 'cemento', 'piedra'],
    claro: ['claro', 'marmol', 'piedra'],
    beige: ['beige', 'travertino', 'piedra'],
  };
  const rgbToLab = ([r, g, b]) => {
    const toLinear = v => {
      v /= 255;
      return v > 0.04045 ? Math.pow((v + 0.055) / 1.055, 2.4) : v / 12.92;
    };
    let rr = toLinear(r), gg = toLinear(g), bb = toLinear(b);
    let x = (rr * 0.4124 + gg * 0.3576 + bb * 0.1805) / 0.95047;
    let y = (rr * 0.2126 + gg * 0.7152 + bb * 0.0722) / 1.00000;
    let z = (rr * 0.0193 + gg * 0.1192 + bb * 0.9505) / 1.08883;
    const f = t => t > 0.008856 ? Math.cbrt(t) : (7.787 * t) + (16 / 116);
    const fx = f(x), fy = f(y), fz = f(z);
    return [(116 * fy) - 16, 500 * (fx - fy), 200 * (fy - fz)];
  };
  const labDistance = (a, b) => {
    const la = rgbToLab(a), lb = rgbToLab(b);
    return Math.sqrt(
      Math.pow(la[0] - lb[0], 2) +
      Math.pow(la[1] - lb[1], 2) +
      Math.pow(la[2] - lb[2], 2)
    );
  };
  const saturationOf = ([r, g, b]) => {
    const max = Math.max(r, g, b), min = Math.min(r, g, b);
    return max === 0 ? 0 : (max - min) / max;
  };
  const saveVisualSearch = (next) => {
    setVisualSearch(next);
    try {
      window.sessionStorage.setItem('nmVisualSearch', JSON.stringify(next));
    } catch (e) {}
  };

  React.useEffect(() => {
    let mounted = true;
    const initSupabase = async () => {
      try {
        const res = await fetch('/api/supabase-config', { cache: 'no-store' });
        const cfg = await res.json();
        if (!cfg.url || !cfg.anonKey || !window.supabase) {
          if (mounted) setSupabaseState({ loading: false, ready: false, error: 'Supabase todavía no está configurado en Vercel.', client: null, adminEmails: cfg.adminEmails || [] });
          return;
        }
        const client = window.supabase.createClient(cfg.url, cfg.anonKey, {
          auth: { persistSession: false, autoRefreshToken: false, detectSessionInUrl: false }
        });
        if (mounted) setSupabaseState({ loading: false, ready: true, error: '', client, adminEmails: cfg.adminEmails || [] });
      } catch (err) {
        if (mounted) setSupabaseState({ loading: false, ready: false, error: 'No se pudo cargar Supabase.', client: null, adminEmails: [] });
      }
    };
    initSupabase();
    return () => { mounted = false; };
  }, []);

  const loadClientPortal = async (client, user, adminEmails) => {
    const email = (user.email || '').toLowerCase();
    const isAdmin = adminEmails.includes(email);
    if (isAdmin) {
      const { data: clients, error: clientsError } = await client
        .from('nm_client_profiles')
        .select('id,email,company,contact,type,zone,created_at')
        .order('company', { ascending: true });
      if (clientsError) throw clientsError;
      const { data: allOrders, error: ordersError } = await client
        .from('nm_client_orders')
        .select('*')
        .order('created_at', { ascending: false });
      if (ordersError) throw ordersError;
      setActiveClient({
        id: 'admin',
        isAdmin: true,
        email,
        company: 'Panel admin',
        contact: 'Admin',
        type: 'Administrador',
        zone: 'Todos los clientes',
        clients: clients || [],
        allOrders: allOrders || [],
        orders: allOrders || [],
        accessToken: (await client.auth.getSession()).data.session?.access_token || '',
      });
      return;
    }

    const { data: profile, error: profileError } = await client
      .from('nm_client_profiles')
      .select('*')
      .eq('user_id', user.id)
      .maybeSingle();
    if (profileError) throw profileError;
    if (!profile) throw new Error('Este usuario todavía no tiene perfil de cliente asignado.');
    const { data: orders, error: ordersError } = await client
      .from('nm_client_orders')
      .select('*')
      .eq('client_id', profile.id)
      .order('created_at', { ascending: false });
    if (ordersError) throw ordersError;
    setActiveClient({
      id: profile.id,
      email: profile.email,
      company: profile.company || profile.email,
      contact: profile.contact || profile.company || profile.email,
      type: profile.type || 'Cliente profesional',
      zone: profile.zone || 'Barcelona y provincia',
      accessToken: (await client.auth.getSession()).data.session?.access_token || '',
      orders: (orders || []).map(o => ({
        id: o.order_ref || o.id,
        date: o.created_at ? new Date(o.created_at).toLocaleDateString('es-ES') : '',
        project: o.project || 'Consulta',
        brand: o.brand || '-',
        material: o.material || '-',
        format: o.format || '-',
        finish: o.finish || '-',
        sqm: Number(o.sqm || 0),
        status: o.status || 'Consulta',
      })),
    });
  };

  const productText = (product, extra = '') => normalizeVisualText([
    product.brand,
    product.name,
    product.collection,
    product.type,
    ...(product.specs || []),
    ...(product.colors || []),
    ...(product.finishes || []),
    ...Object.keys(product.colorImages || {}),
    extra,
  ].join(' '));
  const buildVisualCandidates = () => products.flatMap(product => {
    const colorEntries = Object.entries(product.colorImages || {});
    if (colorEntries.length) {
      return colorEntries.map(([color, detail]) => ({
        id: `${product.id}-${color}`,
        product,
        brand: product.brand,
        collection: product.name,
        subcollection: product.collection,
        color,
        name: `${product.name}${product.collection ? ` · ${product.collection}` : ''}`,
        img: (detail && detail.img) || product.img,
        formats: (detail && detail.formats) || product.formats || [],
        finishes: (detail && detail.finishes) || product.finishes || [],
        thickness: (detail && detail.thickness) || [],
        searchText: productText(product, color),
      }));
    }
    const colors = product.colors && product.colors.length ? product.colors : [''];
    return colors.map(color => ({
      id: `${product.id}-${color || 'base'}`,
      product,
      brand: product.brand,
      collection: product.name,
      subcollection: product.collection,
      color: color || product.collection || 'Base',
      name: `${product.name}${product.collection ? ` · ${product.collection}` : ''}`,
      img: product.img,
      formats: product.formats || [],
      finishes: product.finishes || [],
      thickness: [],
      searchText: productText(product, color),
    }));
  });
  const detectProductFamily = (candidate) => {
    const text = candidate.searchText || productText(candidate.product || candidate);
    if (/wood|madera|rovere|noce|i-wood|playwood|mimesis|essence/.test(text)) return 'madera';
    if (/cotto|terracotta|mattone|clay|forme/.test(text)) return 'cotto';
    if (/travertine|travertino|vein cut|cross cut/.test(text)) return 'travertino';
    if (/marmo|marble|onyx|statuario|calacatta|crystal|tele di marmo/.test(text)) return 'marmol';
    if (/cemento|concrete|resina|resin|re-play|portland|pigmento|abacus/.test(text)) return 'cemento';
    if (/stone|piedra|pietra|bourg|orosei|limestone|gemmastone|cornerstone|ever-stone|mapierre/.test(text)) return 'piedra';
    return 'piedra';
  };
  const toneFromName = (name) => {
    const text = normalizeVisualText(name);
    return visualToneRules.find(rule => rule.keys.some(key => text.includes(key))) || null;
  };
  const getProductProfile = (candidate) => {
    const product = candidate.product || candidate;
    const text = candidate.searchText || productText(product);
    const family = detectProductFamily(candidate);
    const labels = [
      product.name,
      product.collection,
      candidate.color,
      ...(product.colors || []),
      ...Object.keys(product.colorImages || {}),
    ];
    const tones = labels
      .map(toneFromName)
      .filter(Boolean)
      .map(rule => rule.rgb);
    visualToneRules.forEach(rule => {
      if (rule.keys.some(key => text.includes(key))) tones.push(rule.rgb);
    });
    if (!tones.length) {
      const fallback = visualToneRules.find(rule => rule.family === family) || visualToneRules.find(rule => rule.family === 'piedra');
      tones.push(fallback.rgb);
    }
    const uniqueTones = tones.filter((tone, index) => tones.findIndex(other => other.join(',') === tone.join(',')) === index).slice(0, 7);
    return { family, tones: uniqueTones };
  };
  const inferUploadedFamily = (features) => {
    const [r, g, b] = features.avg;
    const warm = r - b;
    if (features.saturation > 0.2 && warm > 42 && features.brightness < 178) return 'cotto';
    if (warm > 30 && features.brightness < 170 && features.edge > 18) return 'madera';
    if (features.brightness > 176 && features.contrast > 42) return 'marmol';
    if (warm > 18 && features.brightness > 138 && features.contrast > 26) return 'travertino';
    if (features.saturation < 0.13 && features.contrast < 32) return 'cemento';
    if (features.brightness < 86) return 'oscuro';
    if (features.brightness > 190) return 'claro';
    return 'piedra';
  };
  const familyScore = (uploaded, productFamily) => {
    if (uploaded === productFamily) return 100;
    if ((familyAliases[uploaded] || []).includes(productFamily)) return 74;
    if ((familyAliases[productFamily] || []).includes(uploaded)) return 68;
    return 34;
  };
  const textureTarget = {
    marmol: { contrast: 52, edge: 28 },
    travertino: { contrast: 34, edge: 20 },
    piedra: { contrast: 31, edge: 24 },
    cemento: { contrast: 18, edge: 12 },
    madera: { contrast: 38, edge: 33 },
    cotto: { contrast: 24, edge: 16 },
    oscuro: { contrast: 28, edge: 18 },
    claro: { contrast: 24, edge: 14 },
  };
  const textureScore = (features, family) => {
    const target = textureTarget[family] || textureTarget.piedra;
    const diff = Math.abs(features.contrast - target.contrast) + Math.abs(features.edge - target.edge);
    return Math.max(0, 100 - diff * 1.4);
  };
  const extractImageFeatures = (ctx, size) => {
    const data = ctx.getImageData(0, 0, size, size).data;
    const bins = new Map();
    const brightnessValues = [];
    let r = 0, g = 0, b = 0, count = 0, edge = 0, edgeCount = 0;
    for (let y = 0; y < size; y++) {
      for (let x = 0; x < size; x++) {
        const i = (y * size + x) * 4;
        const alpha = data[i + 3];
        if (alpha < 180) continue;
        const pr = data[i], pg = data[i + 1], pb = data[i + 2];
        const brightness = (pr + pg + pb) / 3;
        if (brightness < 14 || brightness > 248) continue;
        r += pr; g += pg; b += pb; count += 1;
        brightnessValues.push(brightness);
        const key = [Math.round(pr / 22) * 22, Math.round(pg / 22) * 22, Math.round(pb / 22) * 22].join(',');
        const current = bins.get(key) || { rgb: [0, 0, 0], count: 0 };
        current.rgb[0] += pr; current.rgb[1] += pg; current.rgb[2] += pb; current.count += 1;
        bins.set(key, current);
        if (x > 0) {
          const left = i - 4;
          edge += Math.abs(pr - data[left]) + Math.abs(pg - data[left + 1]) + Math.abs(pb - data[left + 2]);
          edgeCount += 1;
        }
        if (y > 0) {
          const up = i - size * 4;
          edge += Math.abs(pr - data[up]) + Math.abs(pg - data[up + 1]) + Math.abs(pb - data[up + 2]);
          edgeCount += 1;
        }
      }
    }
    const avg = count ? [Math.round(r / count), Math.round(g / count), Math.round(b / count)] : [166, 156, 142];
    const brightness = (avg[0] + avg[1] + avg[2]) / 3;
    const contrast = brightnessValues.length
      ? Math.sqrt(brightnessValues.reduce((sum, value) => sum + Math.pow(value - brightness, 2), 0) / brightnessValues.length)
      : 0;
    const palette = Array.from(bins.values())
      .sort((a, b) => b.count - a.count)
      .slice(0, 6)
      .map(bin => ({
        rgb: bin.rgb.map(v => Math.round(v / bin.count)),
        weight: bin.count / Math.max(count, 1),
      }));
    const features = {
      avg,
      palette: palette.length ? palette : [{ rgb: avg, weight: 1 }],
      brightness,
      saturation: saturationOf(avg),
      contrast,
      edge: edgeCount ? edge / edgeCount : 0,
    };
    features.family = inferUploadedFamily(features);
    return features;
  };
  const scoreProductMatch = (features, candidate) => {
    const profile = getProductProfile(candidate);
    const paletteDistance = features.palette.reduce((sum, color) => {
      const best = Math.min(...profile.tones.map(tone => labDistance(color.rgb, tone)));
      return sum + best * color.weight;
    }, 0);
    const colorScore = Math.max(0, 100 - paletteDistance * 2.35);
    const famScore = familyScore(features.family, profile.family);
    const texScore = textureScore(features, profile.family);
    const exactToneBonus = profile.tones.some(tone => labDistance(features.avg, tone) < 18) ? 6 : 0;
    const score = Math.max(0, Math.min(99, Math.round(colorScore * 0.58 + famScore * 0.28 + texScore * 0.14 + exactToneBonus)));
    return { item: candidate, score, tone: profile.tones[0], family: profile.family, reason: `${profile.family} · tono ${Math.round(colorScore)} · textura ${Math.round(texScore)}` };
  };
  const handleVisualUpload = (event) => {
    const file = event.target.files && event.target.files[0];
    if (!file) return;
    const reader = new FileReader();
    reader.onload = () => {
      const img = new Image();
      img.onload = () => {
        const canvas = document.createElement('canvas');
        const size = 128;
        canvas.width = size;
        canvas.height = size;
        const ctx = canvas.getContext('2d', { willReadFrequently: true });
        ctx.drawImage(img, 0, 0, size, size);
        const features = extractImageFeatures(ctx, size);
        const matches = buildVisualCandidates()
          .map(candidate => scoreProductMatch(features, candidate))
          .sort((a, b) => b.score - a.score)
          .slice(0, 8);
        const next = { image: reader.result, tone: features.avg, features, matches };
        saveVisualSearch(next);
        setSelectedVisualItem(matches[0] ? matches[0].item : null);
      };
      img.src = reader.result;
    };
    reader.readAsDataURL(file);
  };
  const refreshAdminPortal = async () => {
    if (!activeClient?.isAdmin || !supabaseState.client) return;
    const session = await supabaseState.client.auth.getSession();
    const user = session.data.session?.user;
    if (user) await loadClientPortal(supabaseState.client, user, supabaseState.adminEmails);
  };

  const handleAdminCreateClient = async (e) => {
    e.preventDefault();
    if (!activeClient?.accessToken) return;
    setAdminAction({ loading: true, message: '', error: '' });
    try {
      const res = await fetch('/api/admin-create-client', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${activeClient.accessToken}` },
        body: JSON.stringify(newClientForm)
      });
      const body = await res.json();
      if (!body.ok) throw new Error(body.error || 'No se pudo crear cliente.');
      setNewClientForm({ email: '', password: '', company: '', contact: '', type: 'Cliente profesional', zone: 'Barcelona y provincia' });
      setAdminAction({ loading: false, message: 'Cliente creado correctamente.', error: '' });
      await refreshAdminPortal();
    } catch (err) {
      setAdminAction({ loading: false, message: '', error: err.message });
    }
  };

  const handleAdminCreateOrder = async (e) => {
    e.preventDefault();
    if (!activeClient?.accessToken) return;
    setAdminAction({ loading: true, message: '', error: '' });
    try {
      const res = await fetch('/api/admin-create-order', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${activeClient.accessToken}` },
        body: JSON.stringify(newOrderForm)
      });
      const body = await res.json();
      if (!body.ok) throw new Error(body.error || 'No se pudo crear pedido/consulta.');
      setNewOrderForm({ client_id: '', order_ref: '', project: '', brand: '', material: '', format: '', finish: '', sqm: '', status: 'Consulta' });
      setAdminAction({ loading: false, message: 'Pedido/consulta añadido correctamente.', error: '' });
      await refreshAdminPortal();
    } catch (err) {
      setAdminAction({ loading: false, message: '', error: err.message });
    }
  };

  const adminPost = async (endpoint, payload) => {
    if (!activeClient?.accessToken) throw new Error('No hay sesión admin activa.');
    const res = await fetch(endpoint, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${activeClient.accessToken}` },
      body: JSON.stringify(payload)
    });
    const body = await res.json();
    if (!body.ok) throw new Error(body.error || 'Acción no completada.');
    return body;
  };

  const handleAdminEditClient = async (client) => {
    const company = window.prompt('Empresa / estudio', client.company || '');
    if (company === null) return;
    const contact = window.prompt('Contacto', client.contact || '');
    if (contact === null) return;
    const type = window.prompt('Tipo de cliente', client.type || 'Cliente profesional');
    if (type === null) return;
    const zone = window.prompt('Zona', client.zone || 'Barcelona y provincia');
    if (zone === null) return;
    const password = window.prompt('Nueva contraseña (opcional, deja vacío para no cambiarla)', '');
    setAdminAction({ loading: true, message: '', error: '' });
    try {
      await adminPost('/api/admin-update-client', { id: client.id, company, contact, type, zone, ...(password ? { password } : {}) });
      setAdminAction({ loading: false, message: 'Cliente actualizado.', error: '' });
      await refreshAdminPortal();
    } catch (err) {
      setAdminAction({ loading: false, message: '', error: err.message });
    }
  };

  const handleAdminDeleteClient = async (client) => {
    if (!window.confirm(`¿Eliminar cliente ${client.company || client.email}? Se borrará también su usuario y pedidos.`)) return;
    setAdminAction({ loading: true, message: '', error: '' });
    try {
      await adminPost('/api/admin-delete-client', { id: client.id });
      setAdminAction({ loading: false, message: 'Cliente eliminado.', error: '' });
      await refreshAdminPortal();
    } catch (err) {
      setAdminAction({ loading: false, message: '', error: err.message });
    }
  };

  const handleAdminEditOrder = async (order) => {
    const order_ref = window.prompt('Referencia', order.order_ref || '');
    if (order_ref === null) return;
    const project = window.prompt('Proyecto', order.project || '');
    if (project === null) return;
    const brand = window.prompt('Marca', order.brand || '');
    if (brand === null) return;
    const material = window.prompt('Material', order.material || '');
    if (material === null) return;
    const format = window.prompt('Formato', order.format || '');
    if (format === null) return;
    const finish = window.prompt('Acabado', order.finish || '');
    if (finish === null) return;
    const sqm = window.prompt('m²', String(order.sqm || 0));
    if (sqm === null) return;
    const status = window.prompt('Estado', order.status || 'Consulta');
    if (status === null) return;
    setAdminAction({ loading: true, message: '', error: '' });
    try {
      await adminPost('/api/admin-update-order', { id: order.id, order_ref, project, brand, material, format, finish, sqm, status });
      setAdminAction({ loading: false, message: 'Pedido/consulta actualizado.', error: '' });
      await refreshAdminPortal();
    } catch (err) {
      setAdminAction({ loading: false, message: '', error: err.message });
    }
  };

  const handleAdminDeleteOrder = async (order) => {
    if (!window.confirm(`¿Eliminar pedido/consulta ${order.order_ref || order.project || ''}?`)) return;
    setAdminAction({ loading: true, message: '', error: '' });
    try {
      await adminPost('/api/admin-delete-order', { id: order.id });
      setAdminAction({ loading: false, message: 'Pedido/consulta eliminado.', error: '' });
      await refreshAdminPortal();
    } catch (err) {
      setAdminAction({ loading: false, message: '', error: err.message });
    }
  };

  const handleClientLogin = async (e) => {
    e.preventDefault();
    const email = login.email.trim().toLowerCase();
    const password = login.code.trim();
    if (!email || !password) {
      setLoginError('Introduce email y contraseña de cliente.');
      return;
    }
    if (!supabaseState.ready || !supabaseState.client) {
      setLoginError(supabaseState.error || 'Supabase todavía no está configurado.');
      return;
    }
    setAuthLoading(true);
    setLoginError('');
    try {
      const { data, error } = await supabaseState.client.auth.signInWithPassword({ email, password });
      if (error) throw error;
      await loadClientPortal(supabaseState.client, data.user, supabaseState.adminEmails);
      setLogin({ email: '', code: '' });
    } catch (err) {
      setLoginError(err.message === 'Invalid login credentials' ? 'Email o contraseña incorrectos.' : err.message);
    } finally {
      setAuthLoading(false);
    }
  };

  if (!activeClient) {
    return (
      <>
        <section className="nm-client-hero is-login">
          <div className="nm-container nm-client-hero-grid">
            <div className="nm-client-copy">
              <span className="nm-eyebrow">Portal cliente · Acceso privado</span>
              <h1 className="nm-client-h1">
                Entra a tu zona <em>profesional</em>.
              </h1>
              <p className="nm-client-lead">
                Consulta tus pedidos, materiales, m2, muestras, fichas técnicas y estados de suministro
                desde un único panel.
              </p>
            </div>
            <aside className="nm-client-login-card">
              <span className="nm-client-panel-label">Acceso cliente registrado</span>
              <p className="nm-client-login-note">
                Introduce tu email profesional y contraseña asignada por Nova Materia Ceramics.
              </p>
              <form className="nm-client-login-form" onSubmit={handleClientLogin}>
                <label>
                  <span>Email profesional</span>
                  <input
                    type="email"
                    value={login.email}
                    onChange={(e) => setLogin({ ...login, email: e.target.value })}
                    placeholder="cliente@empresa.es"
                    required
                  />
                </label>
                <label>
                  <span>Contraseña</span>
                  <input
                    type="password"
                    value={login.code}
                    onChange={(e) => setLogin({ ...login, code: e.target.value })}
                    placeholder="Contraseña"
                    required
                  />
                </label>
                {supabaseState.loading && <p className="nm-client-login-note">Preparando acceso seguro…</p>}
                {loginError && <p className="nm-client-login-error">{loginError}</p>}
                <button className="nm-btn nm-btn-primary nm-btn-lg" type="submit" disabled={authLoading || supabaseState.loading}>
                  {authLoading ? 'Entrando…' : 'Entrar al portal'} <span className="nm-arrow">→</span>
                </button>
              </form>
              <button className="nm-link nm-client-login-help" onClick={() => onNav('contact')}>
                Pedir acceso de cliente →
              </button>
            </aside>
          </div>
        </section>

        <section className="nm-client-tools">
          <div className="nm-container nm-client-tools-grid">
            {clientTools.map(([num, title, desc]) => (
              <article className="nm-client-tool" key={num}>
                <span>{num}</span>
                <h3>{title}</h3>
                <p>{desc}</p>
              </article>
            ))}
          </div>
        </section>
      </>
    );
  }

  if (activeClient && activeClient.isAdmin) {
    const adminClients = activeClient.clients || [];
    const adminOrders = activeClient.allOrders || [];
    const totalAdminSqm = adminOrders.reduce((sum, order) => sum + Number(order.sqm || 0), 0);
    const activeAdminOrders = adminOrders.filter(order => (order.status || '').toLowerCase() !== 'entregado').length;
    const ordersByClient = adminClients.map(client => {
      const clientOrders = adminOrders.filter(order => order.client_id === client.id);
      return {
        ...client,
        orders: clientOrders,
        sqm: clientOrders.reduce((sum, order) => sum + Number(order.sqm || 0), 0),
        active: clientOrders.filter(order => (order.status || '').toLowerCase() !== 'entregado').length,
      };
    });
    return (
      <>
        <section className="nm-client-hero nm-admin-hero">
          <div className="nm-container nm-client-hero-grid">
            <div className="nm-client-copy">
              <span className="nm-eyebrow">Panel admin · Nova Materia Ceramics</span>
              <h1 className="nm-client-h1">
                Resumen de <em>clientes</em>.
              </h1>
              <p className="nm-client-lead">
                Vista global de clientes profesionales, pedidos, consultas, m2 acumulados y estado comercial.
              </p>
              <div className="nm-client-actions">
                <button className="nm-btn nm-btn-primary nm-btn-lg" onClick={() => onNav('catalog')}>
                  Ir al catálogo <span className="nm-arrow">→</span>
                </button>
                <button className="nm-btn nm-btn-ghost nm-btn-lg" onClick={async () => { await supabaseState.client?.auth.signOut(); setActiveClient(null); }}>
                  Cerrar sesión
                </button>
              </div>
            </div>
            <aside className="nm-client-panel">
              <span className="nm-client-panel-label">Admin activo</span>
              <div className="nm-client-code">{activeClient.email}</div>
              <p>Vista interna · Todos los clientes</p>
              <div className="nm-client-panel-list">
                <span>{adminClients.length} clientes</span>
                <span>{adminOrders.length} pedidos / consultas</span>
                <span>{totalAdminSqm} m2 totales</span>
              </div>
            </aside>
          </div>
        </section>

        <section className="nm-client-main nm-admin-main">
          <div className="nm-container">
            <div className="nm-client-stats nm-admin-stats">
              <article className="nm-client-stat is-large">
                <span>Clientes</span>
                <strong>{adminClients.length}</strong>
                <p>Clientes profesionales registrados.</p>
              </article>
              <article className="nm-client-stat">
                <span>m2 totales</span>
                <strong>{totalAdminSqm}</strong>
                <p>Sumados entre pedidos y consultas.</p>
              </article>
              <article className="nm-client-stat">
                <span>Pedidos / consultas</span>
                <strong>{adminOrders.length}</strong>
                <p>Histórico total registrado.</p>
              </article>
              <article className="nm-client-stat">
                <span>Activos</span>
                <strong>{activeAdminOrders}</strong>
                <p>Pedidos o consultas no entregados.</p>
              </article>
            </div>

            <div className="nm-admin-forms">
              <form className="nm-admin-form-card" onSubmit={handleAdminCreateClient}>
                <span className="nm-eyebrow">Crear cliente</span>
                <h2>Nuevo acceso.</h2>
                <div className="nm-admin-form-grid">
                  <label><span>Email</span><input type="email" value={newClientForm.email} onChange={(e) => setNewClientForm({ ...newClientForm, email: e.target.value })} placeholder="cliente@empresa.com" required /></label>
                  <label><span>Contraseña</span><input type="text" value={newClientForm.password} onChange={(e) => setNewClientForm({ ...newClientForm, password: e.target.value })} placeholder="mín. 6 caracteres" required /></label>
                  <label><span>Empresa</span><input value={newClientForm.company} onChange={(e) => setNewClientForm({ ...newClientForm, company: e.target.value })} placeholder="Nombre empresa/estudio" required /></label>
                  <label><span>Contacto</span><input value={newClientForm.contact} onChange={(e) => setNewClientForm({ ...newClientForm, contact: e.target.value })} placeholder="Nombre contacto" /></label>
                  <label><span>Tipo</span><select value={newClientForm.type} onChange={(e) => setNewClientForm({ ...newClientForm, type: e.target.value })}>
                    <option value="Cliente profesional">Cliente profesional</option>
                    <option value="Arquitecto">Arquitecto</option>
                    <option value="Interiorista">Interiorista</option>
                    <option value="Reformista">Reformista</option>
                    <option value="Constructora">Constructora</option>
                    <option value="Promotora">Promotora</option>
                    <option value="Particular alto valor">Particular alto valor</option>
                    <option value="Otro">Otro</option>
                  </select></label>
                  <label><span>Zona</span><select value={newClientForm.zone} onChange={(e) => setNewClientForm({ ...newClientForm, zone: e.target.value })}>
                    <option value="Barcelona y provincia">Barcelona y provincia</option>
                    <option value="Barcelona ciudad">Barcelona ciudad</option>
                    <option value="Vallès Occidental">Vallès Occidental</option>
                    <option value="Vallès Oriental">Vallès Oriental</option>
                    <option value="Maresme">Maresme</option>
                    <option value="Baix Llobregat">Baix Llobregat</option>
                    <option value="Garraf / Sitges">Garraf / Sitges</option>
                    <option value="Girona / Costa Brava">Girona / Costa Brava</option>
                    <option value="Tarragona">Tarragona</option>
                    <option value="Cataluña">Cataluña</option>
                    <option value="Otra zona">Otra zona</option>
                  </select></label>
                </div>
                <button className="nm-btn nm-btn-primary" type="submit" disabled={adminAction.loading}>Crear cliente <span className="nm-arrow">→</span></button>
              </form>

              <form className="nm-admin-form-card" onSubmit={handleAdminCreateOrder}>
                <span className="nm-eyebrow">Añadir pedido/consulta</span>
                <h2>Movimiento de cliente.</h2>
                <div className="nm-admin-form-grid">
                  <label className="is-wide"><span>Cliente</span><select value={newOrderForm.client_id} onChange={(e) => setNewOrderForm({ ...newOrderForm, client_id: e.target.value })} required><option value="">Seleccionar cliente</option>{adminClients.map(c => <option key={c.id} value={c.id}>{c.company} · {c.email}</option>)}</select></label>
                  <label><span>Ref.</span><input value={newOrderForm.order_ref} onChange={(e) => setNewOrderForm({ ...newOrderForm, order_ref: e.target.value })} placeholder="NM-1001" /></label>
                  <label><span>Proyecto</span><input value={newOrderForm.project} onChange={(e) => setNewOrderForm({ ...newOrderForm, project: e.target.value })} placeholder="Baño vivienda" /></label>
                  <label><span>Marca</span><input value={newOrderForm.brand} onChange={(e) => setNewOrderForm({ ...newOrderForm, brand: e.target.value })} placeholder="Keope" /></label>
                  <label><span>Material</span><input value={newOrderForm.material} onChange={(e) => setNewOrderForm({ ...newOrderForm, material: e.target.value })} placeholder="CottoMilano" /></label>
                  <label><span>Formato</span><input value={newOrderForm.format} onChange={(e) => setNewOrderForm({ ...newOrderForm, format: e.target.value })} placeholder="60×120 cm" /></label>
                  <label><span>Acabado</span><input value={newOrderForm.finish} onChange={(e) => setNewOrderForm({ ...newOrderForm, finish: e.target.value })} placeholder="ULTRAmatt" /></label>
                  <label><span>m²</span><input type="number" min="0" step="0.1" value={newOrderForm.sqm} onChange={(e) => setNewOrderForm({ ...newOrderForm, sqm: e.target.value })} placeholder="42" /></label>
                  <label><span>Estado</span><input value={newOrderForm.status} onChange={(e) => setNewOrderForm({ ...newOrderForm, status: e.target.value })} placeholder="Consulta / Muestras enviadas" /></label>
                </div>
                <button className="nm-btn nm-btn-primary" type="submit" disabled={adminAction.loading}>Añadir pedido/consulta <span className="nm-arrow">→</span></button>
              </form>
            </div>
            {adminAction.message && <p className="nm-admin-action-ok">{adminAction.message}</p>}
            {adminAction.error && <p className="nm-client-login-error">{adminAction.error}</p>}

            <div className="nm-admin-table-card">
              <div className="nm-client-section-head">
                <span className="nm-eyebrow">Clientes</span>
                <h2>Detalle por cliente.</h2>
              </div>
              <div className="nm-admin-client-list">
                {ordersByClient.length ? ordersByClient.map(client => (
                  <article className="nm-admin-client-card" key={client.id}>
                    <div>
                      <h3>{client.company}</h3>
                      <p>{client.contact || client.email} · {client.type || 'Cliente profesional'} · {client.zone || 'Zona pendiente'}</p>
                      <span>{client.email}</span>
                      <div className="nm-admin-row-actions">
                        <button type="button" onClick={() => handleAdminEditClient(client)}>Editar cliente</button>
                        <button type="button" className="is-danger" onClick={() => handleAdminDeleteClient(client)}>Borrar cliente</button>
                      </div>
                    </div>
                    <div className="nm-admin-client-metrics">
                      <strong>{client.sqm} m2</strong>
                      <span>{client.orders.length} pedidos/consultas</span>
                      <span>{client.active} activos</span>
                    </div>
                    {client.orders.length > 0 && (
                      <div className="nm-admin-order-list">
                        {client.orders.slice(0, 4).map(order => (
                          <div className="nm-admin-order-row" key={order.id}>
                            <span>{order.order_ref || 'Consulta'}</span>
                            <span>{order.project || '-'}</span>
                            <span>{order.material || order.brand || '-'}</span>
                            <strong>{Number(order.sqm || 0)} m2</strong>
                            <em>{order.status || 'Consulta'}</em>
                            <div className="nm-admin-order-actions">
                              <button type="button" onClick={() => handleAdminEditOrder(order)}>Editar</button>
                              <button type="button" className="is-danger" onClick={() => handleAdminDeleteOrder(order)}>Borrar</button>
                            </div>
                          </div>
                        ))}
                      </div>
                    )}
                  </article>
                )) : (
                  <p className="nm-client-empty">Todavía no hay clientes creados en Supabase.</p>
                )}
              </div>
            </div>
          </div>
        </section>
      </>
    );
  }

  return (
    <>
      <section className="nm-client-hero">
        <div className="nm-container nm-client-hero-grid">
          <div className="nm-client-copy">
            <span className="nm-eyebrow">Portal cliente · Sesión activa</span>
            <h1 className="nm-client-h1">
              Tus pedidos, materiales y <em>m2</em>.
            </h1>
            <p className="nm-client-lead">
              Historial profesional con las colecciones trabajadas, formatos, acabados,
              metros cuadrados y estado de cada pedido o consulta.
            </p>
            <div className="nm-client-actions">
              <button className="nm-btn nm-btn-primary nm-btn-lg" onClick={() => onNav('catalog')}>
                Ir al catálogo <span className="nm-arrow">→</span>
              </button>
              <button className="nm-btn nm-btn-ghost nm-btn-lg" onClick={async () => { await supabaseState.client?.auth.signOut(); setActiveClient(null); }}>
                Cerrar sesión
              </button>
            </div>
          </div>
          <aside className="nm-client-panel">
            <span className="nm-client-panel-label">Cliente activo</span>
            <div className="nm-client-code">{activeClient.company}</div>
            <p>{activeClient.contact} · {activeClient.type} · {activeClient.zone}</p>
            <div className="nm-client-panel-list">
              <span>{activeClient.orders.length} pedidos / consultas</span>
              <span>{activeClient.orders.reduce((sum, o) => sum + o.sqm, 0)} m2 en historial</span>
              <span>Soporte comercial 24 h</span>
            </div>
          </aside>
        </div>
      </section>

      <section className="nm-client-tools">
        <div className="nm-container nm-client-tools-grid">
          {clientTools.map(([num, title, desc]) => (
            <article className="nm-client-tool" key={num}>
              <span>{num}</span>
              <h3>{title}</h3>
              <p>{desc}</p>
            </article>
          ))}
        </div>
      </section>

      <section className="nm-client-main">
        <div className="nm-container nm-client-layout">
          <div className="nm-client-search-card">
            <div className="nm-client-stats">
              <article className="nm-client-stat is-large">
                <span>m2 totales</span>
                <strong>{totalSqm}</strong>
                <p>Sumados entre pedidos y consultas registradas.</p>
              </article>
              <article className="nm-client-stat">
                <span>Material más usado</span>
                <strong>{topMaterial[0]}</strong>
                <p>{topMaterial[1]} pedido{topMaterial[1] !== 1 ? 's' : ''} con este material.</p>
              </article>
              <article className="nm-client-stat">
                <span>Marca principal</span>
                <strong>{topBrand[0]}</strong>
                <p>{topBrand[1]} selección{topBrand[1] !== 1 ? 'es' : ''} en historial.</p>
              </article>
              <article className="nm-client-stat">
                <span>Pedidos activos</span>
                <strong>{activeOrders}</strong>
                <p>{averageSqm} m2 de media por pedido.</p>
              </article>
            </div>

            <div className="nm-client-insights">
              <div className="nm-client-insight-card">
                <div className="nm-client-insight-head">
                  <span className="nm-eyebrow">Uso por material</span>
                  <strong>Ranking de m2</strong>
                </div>
                <div className="nm-client-bars">
                  {materialBreakdown.map(item => (
                    <div className="nm-client-bar" key={item.name}>
                      <div>
                        <span>{item.name}</span>
                        <em>{item.sqm} m2</em>
                      </div>
                      <i style={{ width: `${Math.max(12, Math.round((item.sqm / Math.max(totalSqm, 1)) * 100))}%` }} />
                    </div>
                  ))}
                </div>
              </div>
              <div className="nm-client-insight-card">
                <div className="nm-client-insight-head">
                  <span className="nm-eyebrow">Resumen útil</span>
                  <strong>Decisiones rápidas</strong>
                </div>
                <ul className="nm-client-insight-list">
                  <li><span>Formato más repetido</span><strong>{topFormat[0]}</strong></li>
                  <li><span>Material recomendado para repetir</span><strong>{topMaterial[0]}</strong></li>
                  <li><span>Pedidos pendientes</span><strong>{activeOrders}</strong></li>
                </ul>
                <div className="nm-client-status-pills">
                  {statusBreakdown.map(item => (
                    <span key={item.name}>{item.name} · {item.count}</span>
                  ))}
                </div>
              </div>
            </div>

            <div className="nm-client-visual-card">
              <div className="nm-client-search-head">
                <div>
                  <span className="nm-eyebrow">Buscador visual</span>
                  <h2>Sube una foto del material.</h2>
                </div>
                {visualSearch.tone && (
                  <div className="nm-client-tone">
                    <span style={{ backgroundColor: `rgb(${visualSearch.tone.join(',')})` }} />
                    <em>{visualSearch.features ? `${visualSearch.features.family} · tono detectado` : 'Tono detectado'}</em>
                  </div>
                )}
              </div>
              <div className="nm-client-visual-grid">
                <label className="nm-client-upload">
                  <input type="file" accept="image/*" onChange={handleVisualUpload} />
                  {visualSearch.image ? (
                    <img src={visualSearch.image} alt="Material subido por el cliente" loading="lazy" decoding="async" />
                  ) : (
                    <span>
                      Arrastra o selecciona una foto<br />
                      <em>piedra, madera, mármol, cemento, cotto...</em>
                    </span>
                  )}
                </label>
                <div className="nm-client-visual-results">
                  {visualSearch.matches.length > 0 ? (
                    visualSearch.matches.map(({ item, score, reason }) => (
                      <article
                        className={`nm-client-visual-match${selectedVisualItem && selectedVisualItem.id === item.id ? ' is-selected' : ''}`}
                        key={item.id}
                      >
                        <button
                          className="nm-client-visual-img"
                          style={{ backgroundImage: `url('${item.img}')` }}
                          onClick={() => setSelectedVisualItem(item)}
                          aria-label={`Ver ${item.color}`}
                        />
                        <div>
                          <span>{score}% parecido</span>
                          <h3>{item.color}</h3>
                          <p>{item.brand} · {item.name}</p>
                          <small>{reason}</small>
                          <button onClick={() => setSelectedVisualItem(item)}>Ver producto</button>
                        </div>
                      </article>
                    ))
                  ) : (
                    <div className="nm-client-visual-empty">
                      <strong>Resultado inmediato</strong>
                      <p>Cuando subas la foto, te mostraremos los productos y colores más parecidos del catálogo.</p>
                    </div>
                  )}
                </div>
              </div>
              {selectedVisualItem && (
                <aside className="nm-client-visual-detail">
                  <div
                    className="nm-client-visual-detail-media"
                    style={{ backgroundImage: `url('${selectedVisualItem.img}')` }}
                    aria-hidden="true"
                  />
                  <div className="nm-client-visual-detail-body">
                    <span className="nm-eyebrow">Producto seleccionado</span>
                    <h3>{selectedVisualItem.color}</h3>
                    <p>{selectedVisualItem.brand} · {selectedVisualItem.name}</p>
                    <dl>
                      <div><dt>Marca</dt><dd>{selectedVisualItem.brand}</dd></div>
                      <div><dt>Colección</dt><dd>{selectedVisualItem.name}</dd></div>
                      <div><dt>Producto</dt><dd>{selectedVisualItem.color}</dd></div>
                      {selectedVisualItem.formats && selectedVisualItem.formats.length > 0 && (
                        <div><dt>Formatos</dt><dd>{selectedVisualItem.formats.join(' · ')}</dd></div>
                      )}
                      {selectedVisualItem.finishes && selectedVisualItem.finishes.length > 0 && (
                        <div><dt>Acabados</dt><dd>{selectedVisualItem.finishes.join(' · ')}</dd></div>
                      )}
                      {selectedVisualItem.thickness && selectedVisualItem.thickness.length > 0 && (
                        <div><dt>Espesor</dt><dd>{selectedVisualItem.thickness.join(' · ')}</dd></div>
                      )}
                    </dl>
                    <div className="nm-client-visual-detail-actions">
                      <button className="nm-btn nm-btn-primary" onClick={() => onNav('sample')}>
                        Pedir muestra <span className="nm-arrow">→</span>
                      </button>
                      <button className="nm-btn nm-btn-ghost" onClick={() => onNav('contact')}>
                        Consultar producto
                      </button>
                    </div>
                  </div>
                </aside>
              )}
              <p className="nm-client-visual-note">
                Comparación avanzada por paleta, familia visual y textura. Para clavar partida final, valida siempre con muestra física.
              </p>
            </div>

            <div className="nm-client-search-head">
              <div>
                <span className="nm-eyebrow">Historial cliente</span>
                <h2>Pedidos realizados.</h2>
              </div>
            </div>
            <div className="nm-client-order-table">
              <div className="nm-client-order-row is-head">
                <span>Pedido</span>
                <span>Proyecto</span>
                <span>Material</span>
                <span>m2</span>
              </div>
              {activeClient.orders.map(order => (
                <article className="nm-client-order-row" key={order.id}>
                  <span><strong>{order.id}</strong><em>{order.date}</em></span>
                  <span>{order.project}</span>
                  <span><strong>{order.material}</strong><em>{order.brand} · {order.format} · {order.finish}</em></span>
                  <span>{order.sqm} m2</span>
                </article>
              ))}
            </div>

            <div className="nm-client-search-head is-secondary">
              <div>
                <span className="nm-eyebrow">Repetir o buscar material</span>
                <h2>Producto, formato o acabado.</h2>
              </div>
              <button className="nm-link" onClick={() => onNav('catalog')}>
                Ver catálogo completo →
              </button>
            </div>
            <label className="nm-client-search">
              <span>Buscar en catálogo</span>
              <input
                value={query}
                onChange={(e) => setQuery(e.target.value)}
                placeholder="Ej. GemmaStone, R11, 120×278, travertino..."
              />
            </label>
            <div className="nm-client-chips" aria-label="Búsquedas rápidas">
              {quickSearches.map(item => (
                <button
                  type="button"
                  key={item}
                  className={query === item ? 'is-active' : ''}
                  onClick={() => setQuery(item)}
                >
                  {item}
                </button>
              ))}
            </div>
            <div className="nm-client-results">
              {results.map(p => (
                <article className="nm-client-result" key={p.id}>
                  <button
                    className="nm-client-result-img"
                    style={{ backgroundImage: `url('${p.img}')` }}
                    onClick={() => onOpenProduct(p)}
                    aria-label={`Abrir ${p.name}`}
                  />
                  <div className="nm-client-result-body">
                    <span>{p.brand}</span>
                    <h3>{p.name}{p.collection ? <em> · {p.collection}</em> : null}</h3>
                    <p>{[p.type, (p.formats || [])[0], (p.finishes || [])[0]].filter(Boolean).join(' · ')}</p>
                    <div className="nm-client-result-actions">
                      <button onClick={() => onOpenProduct(p)}>Abrir ficha</button>
                      <button onClick={() => onNav('contact')}>Repetir pedido</button>
                    </div>
                  </div>
                </article>
              ))}
            </div>
          </div>

          <aside className="nm-client-side">
            <div className="nm-client-side-card">
              <span className="nm-eyebrow">Tu operativa</span>
              {savedRequests.map(([title, desc]) => (
                <div className="nm-client-status" key={title}>
                  <strong>{title}</strong>
                  <p>{desc}</p>
                </div>
              ))}
            </div>
            <div className="nm-client-side-card is-dark">
              <span>Pedido o consulta urgente</span>
              <strong>+34 691 519 814</strong>
              <p>Envíanos el número de pedido, colección, formato, acabado y m2 aproximados.</p>
              <a
                className="nm-btn nm-btn-primary"
                href="https://wa.me/34691519814?text=Hola%2C%20necesito%20ayuda%20con%20una%20consulta%20urgente.%20Os%20comparto%20la%20informaci%C3%B3n%20para%20que%20pod%C3%A1is%20revisarla."
                target="_blank"
                rel="noopener noreferrer"
              >
                Contactar ahora <span className="nm-arrow">→</span>
              </a>
            </div>
          </aside>
        </div>
      </section>
    </>
  );
};

const mixProductsByBrand = (products) => {
  const brandOrder = ['Keope', 'Emilceramica', 'Provenza', 'Ergon'];
  const buckets = brandOrder.map(brand => products.filter(p => p.brand === brand));
  const knownBrands = new Set(brandOrder);

  products.forEach(p => {
    if (!knownBrands.has(p.brand)) {
      knownBrands.add(p.brand);
      buckets.push(products.filter(item => item.brand === p.brand));
    }
  });

  const mixed = [];
  const max = Math.max(...buckets.map(group => group.length));
  for (let i = 0; i < max; i++) {
    buckets.forEach(group => {
      if (group[i]) mixed.push(group[i]);
    });
  }
  return mixed;
};

const CatalogScreen = ({ onNav, onOpenProduct, preset = null }) => {
  const [active, setActive] = useState({});
  const [searchTerm, setSearchTerm] = useState('');
  React.useEffect(() => {
    if (!preset) return;
    if (preset.group && preset.item) {
      setActive({ [preset.group + '|' + preset.item]: true });
      setSearchTerm('');
    } else if (preset.query) {
      setActive({});
      setSearchTerm(preset.query);
    }
  }, [preset]);
  const toggle = (group, item) => {
    const key = group + '|' + item;
    setActive(a => ({ ...a, [key]: !a[key] }));
  };
  const filtered = useMemo(() => {
    const activeKeys = Object.entries(active).filter(([_, v]) => v).map(([k]) => k);
    const query = searchTerm.trim().toLowerCase();
    const matchesSearch = (p) => {
      if (!query) return true;
      return [
        p.name,
        p.collection,
        p.brand,
        p.type,
        ...(p.formats || []),
        ...(p.finishes || []),
        ...(p.colors || []),
        ...Object.keys(p.colorImages || {})
      ].filter(Boolean).join(' ').toLowerCase().includes(query);
    };
    if (!activeKeys.length) {
      return mixProductsByBrand(window.NM_PRODUCTS).filter(matchesSearch);
    }
    // Group active filters by category
    const groups = {};
    activeKeys.forEach(k => {
      const [group, val] = k.split('|');
      if (!groups[group]) groups[group] = [];
      groups[group].push(val);
    });
    // Product must match at least one value in EACH active group (OR within group, AND across groups)
    return window.NM_PRODUCTS.filter(p => {
      return matchesSearch(p) && Object.entries(groups).every(([group, vals]) => {
        if (group === 'Marca') return vals.some(v => p.brand === v);
        if (group === 'Tipo') return vals.some(v => p.type && p.type.includes(v));
        if (group === 'Efecto') return vals.some(v => {
          const desc = (p.description || '').toLowerCase() + ' ' + (p.specs || []).join(' ').toLowerCase();
          return desc.includes(v.toLowerCase()) || desc.includes(v.toLowerCase().replace('á','a').replace('é','e'));
        });
        if (group === 'Formato') return vals.some(v => p.formats && p.formats.some(f => f.includes(v)));
        if (group === 'Acabado') return vals.some(v => p.finishes && p.finishes.some(f => f.toLowerCase().includes(v.toLowerCase())));
        if (group === 'Espesor') return vals.some(v => p.thickness && p.thickness.some(t => t.includes(v)));
        if (group === 'Color') return vals.some(v => p.colors && p.colors.some(c => c.toLowerCase().includes(v.toLowerCase())));
        return true;
      });
    });
  }, [active, searchTerm]);

  const activeCount = Object.values(active).filter(Boolean).length;
  const hasSearch = searchTerm.trim().length > 0;
  const catalogHeroImages = useMemo(
    () => mixProductsByBrand(window.NM_PRODUCTS).filter(p => p.img).slice(0, 8),
    []
  );

  return (
    <>
      <section className="nm-catalog-intro">
        <div className="nm-catalog-carousel" aria-hidden="true">
          {catalogHeroImages.map((p, i) => (
            <div
              key={p.id}
              className="nm-catalog-slide"
              style={{
                backgroundImage: `url('${p.img}')`,
                '--slide-index': i
              }}
            />
          ))}
        </div>
        <div className="nm-container">
          <div className="nm-catalog-intro-grid">
            <div className="nm-catalog-intro-left">
              <h1 className="nm-catalog-h1">
                Catálogo
              </h1>
            </div>
            <div className="nm-catalog-intro-right">
              <p className="nm-catalog-sub">
                Porcelánico italiano de Emilgroup y Keope. Filtra por marca, formato, acabado y color.
              </p>
              <div className="nm-catalog-intro-stats">
                <span><strong>{window.NM_PRODUCTS.length}</strong> colecciones</span>
                <span><strong>4</strong> marcas</span>
                <span><strong>+200</strong> formatos</span>
              </div>
            </div>
          </div>
        </div>
      </section>
      <section className="nm-section nm-section-padded">
        <div className="nm-container">
          <div className="nm-catalog-toolbar">
            <span className="nm-catalog-count">{filtered.length} colecciones</span>
            <div className="nm-catalog-tools">
              <label className="nm-catalog-search">
                <span>Buscar colección</span>
                <input
                  type="search"
                  value={searchTerm}
                  onChange={(e) => setSearchTerm(e.target.value)}
                  placeholder="Nombre de colección..."
                />
              </label>
            </div>
            {(activeCount > 0 || hasSearch) && (
              <button className="nm-catalog-clear" onClick={() => { setActive({}); setSearchTerm(''); }}>
                ✕ Limpiar {activeCount > 0 ? `(${activeCount})` : ''}
              </button>
            )}
          </div>
          <div className="nm-catalog-layout">
            <FilterRail filters={window.NM_FILTERS} active={active} onToggle={toggle} />
            <div className="nm-catalog-main">
              {filtered.length === 0 ? (
                <p className="nm-empty">Sin resultados para esos filtros. <a onClick={() => setActive({})}>Limpiar filtros</a></p>
              ) : (
                <ProductGrid products={filtered} onOpen={onOpenProduct} />
              )}
            </div>
          </div>
        </div>
      </section>
    </>
  );
};

const getCollectionAmbienceSlides = (product) => {
  const curatedSlides = [
    ...((window.NM_AMBIENCE_GALLERIES && window.NM_AMBIENCE_GALLERIES[product.id]) || []),
    ...(product.ambienceImages || []),
    ...(product.galleryImages || []),
  ].filter(Boolean);
  const hasCuratedGallery = Object.prototype.hasOwnProperty.call(product, 'ambienceImages') ||
    Object.prototype.hasOwnProperty.call(product, 'galleryImages') ||
    Boolean(window.NM_AMBIENCE_GALLERIES && window.NM_AMBIENCE_GALLERIES[product.id]);
  const rawSlides = curatedSlides.length || hasCuratedGallery
    ? curatedSlides
    : [product.img ? { src: product.img, title: 'Ambiente principal' } : null].filter(Boolean);

  const seen = new Set();
  return rawSlides
    .map((item, index) => typeof item === 'string'
      ? { src: item, title: index === 0 ? 'Ambiente principal' : `Ambiente ${index + 1}` }
      : { src: item.src || item.img, title: item.title || item.name || (index === 0 ? 'Ambiente principal' : `Ambiente ${index + 1}`) })
    .filter(item => item.src && !seen.has(item.src) && seen.add(item.src));
};

const ProductScreen = ({ product, onNav, addSample, sampleCart = [] }) => {
  if (!product) return null;
  const p = product;
  const [selectedColor, setSelectedColor] = React.useState(null);
  const [showSelectHint, setShowSelectHint] = React.useState(false);
  const [lightboxImage, setLightboxImage] = React.useState(null);
  const [ambienceIndex, setAmbienceIndex] = React.useState(0);
  const [ambienceExpanded, setAmbienceExpanded] = React.useState(false);
  const ambienceSlides = getCollectionAmbienceSlides(p);
  const activeAmbienceSlide = ambienceSlides[ambienceIndex] || ambienceSlides[0];
  const moveAmbience = (direction) => {
    if (ambienceSlides.length <= 1) return;
    setAmbienceIndex(i => (i + direction + ambienceSlides.length) % ambienceSlides.length);
  };

  React.useEffect(() => {
    setAmbienceIndex(0);
    setAmbienceExpanded(false);
  }, [p.id]);

  React.useEffect(() => {
    if (ambienceSlides.length <= 1 || ambienceExpanded) return undefined;
    const timer = setInterval(() => {
      setAmbienceIndex(i => (i + 1) % ambienceSlides.length);
    }, 4200);
    return () => clearInterval(timer);
  }, [ambienceSlides.length, ambienceExpanded]);

  // Smart related: find collections with similar style/effect, not just same brand
  const related = (() => {
    const all = window.NM_PRODUCTS.filter(r => r.id !== p.id);
    // Extract effect keywords from current product specs + description
    const effectWords = ['mármol','marble','marmo','piedra','stone','cemento','cement','concrete','madera','wood','legno','terracota','cotto','resina','resin','travertino','travertine','pizarra','slate','cuarcita','quartz','caliza','limestone','ónice','onyx','metal'];
    const pText = ((p.specs || []).join(' ') + ' ' + (p.description || '') + ' ' + (p.type || '')).toLowerCase();
    const pEffects = effectWords.filter(w => pText.includes(w));

    // Score each product by similarity
    const scored = all.map(r => {
      const rText = ((r.specs || []).join(' ') + ' ' + (r.description || '') + ' ' + (r.type || '')).toLowerCase();
      let score = 0;
      // Same effects = high score
      pEffects.forEach(w => { if (rText.includes(w)) score += 3; });
      // Same type (pavimento/revestimiento)
      if (r.type === p.type) score += 1;
      // Same brand = small bonus
      if (r.brand === p.brand) score += 1;
      // Similar finishes
      if (p.finishes && r.finishes) {
        p.finishes.forEach(f => { if (r.finishes.includes(f)) score += 1; });
      }
      return { product: r, score };
    });

    // Sort by score desc, take top 3
    return scored.sort((a, b) => b.score - a.score).slice(0, 3).map(s => s.product);
  })();

  const renderAmbienceCarousel = () => activeAmbienceSlide && (
    <div className="nm-pd-ambience">
      <div className="nm-pd-ambience-media">
        <img src={activeAmbienceSlide.src} alt={`${p.name} ${activeAmbienceSlide.title}`} className="nm-pd-ambience-img" loading="lazy" decoding="async" />
        <div className="nm-pd-ambience-shade" />
        <div className="nm-pd-ambience-top">
          <span className="nm-pd-ambience-label">Ambientes {ambienceSlides.length > 1 ? `${ambienceIndex + 1}/${ambienceSlides.length}` : ''}</span>
          <button className="nm-pd-ambience-expand" type="button" onClick={() => setAmbienceExpanded(true)}>
            Ver grande
          </button>
        </div>
        {ambienceSlides.length > 1 && (
          <>
            <button className="nm-pd-ambience-arrow is-prev" type="button" onClick={() => moveAmbience(-1)} aria-label="Ambiente anterior">‹</button>
            <button className="nm-pd-ambience-arrow is-next" type="button" onClick={() => moveAmbience(1)} aria-label="Ambiente siguiente">›</button>
            <div className="nm-pd-ambience-dots">
              {ambienceSlides.map((slide, index) => (
                <button
                  key={slide.src}
                  type="button"
                  className={index === ambienceIndex ? 'is-active' : ''}
                  title={slide.title}
                  onClick={() => setAmbienceIndex(index)}
                  aria-label={`Ver ambiente ${index + 1}`}
                />
              ))}
            </div>
          </>
        )}
        <div className="nm-pd-ambience-caption">
          <strong>{p.name}</strong>
          <span>{activeAmbienceSlide.title}</span>
        </div>
      </div>
    </div>
  );


  return (
    <>
      {/* ── Hero ambient ── */}
      <section className="nm-pd-hero">
        <div className="nm-pd-hero-bg" style={{ backgroundImage: `url('${p.img}')` }}>
          <div className="nm-pd-hero-overlay" />
        </div>
        <div className="nm-container nm-pd-hero-content">
          <button className="nm-pd-back" onClick={() => onNav('catalog')}>
            ← Volver al catálogo
          </button>
          <div className="nm-pd-hero-text">
            <span className="nm-eyebrow" style={{ color: 'var(--cotto-300)' }}>{p.brand}</span>
            <h1 className="nm-pd-h1">
              {p.name}{p.collection ? <em> {p.collection}</em> : ''}
            </h1>
            <p className="nm-pd-lead">{p.description}</p>
          </div>
        </div>
      </section>

      {/* ── Info + Color selector ── */}
      <section className="nm-pd-body">
        <div className="nm-container">
          <div className="nm-pd-grid">

            {/* Left: all tile samples gallery */}
            <div className="nm-pd-left">
              <h3 className="nm-pd-section-title">Muestras de la colección</h3>

              {/* Detail panel when a swatch is clicked — ABOVE the gallery */}
              {selectedColor && p.colorImages && p.colorImages[selectedColor] && (() => {
                // Support both old format (string URL) and new format (object with img + specs)
                const entry = p.colorImages[selectedColor];
                const imgUrl = typeof entry === 'string' ? entry : entry.img;
                const colorFormats = typeof entry === 'object' && entry.formats ? entry.formats : null;
                const colorThickness = typeof entry === 'object' && entry.thickness ? entry.thickness : null;
                const colorFinishes = typeof entry === 'object' && entry.finishes ? entry.finishes : null;
                const hasColorSpecs = colorFormats || colorThickness || colorFinishes;
                const colorFD = typeof entry === 'object' && entry.formatDetails ? entry.formatDetails : null;

                // Build format details: prefer per-color formatDetails, then collection-level
                const fdSource = colorFD || (p.formatDetails || null);

                return (
                <div className="nm-pd-detail-panel">
                  <div className="nm-pd-detail-header">
                    <div>
                      <span className="nm-pd-detail-brand">{p.brand}</span>
                      <h3 className="nm-pd-detail-name">{p.name}{p.collection ? ` ${p.collection}` : ''} — {selectedColor}</h3>
                    </div>
                    <button className="nm-pd-detail-close" onClick={() => setSelectedColor(null)}>✕</button>
                  </div>
                  <div className="nm-pd-detail-body">
                    <div className="nm-pd-detail-img-wrap">
                      <button
                        className="nm-pd-detail-img-button is-zoomable"
                        type="button"
                        onClick={() => setLightboxImage({ src: imgUrl, title: selectedColor })}
                        aria-label={`Ampliar imagen de ${selectedColor}`}
                      >
                        <img src={imgUrl} alt={selectedColor} className="nm-pd-detail-img" loading="lazy" decoding="async" />
                      </button>
                    </div>
                    <div className="nm-pd-detail-specs">
                      <h4 className="nm-pd-detail-specs-title">Ficha técnica</h4>

                      {/* Basic info */}
                      <dl className="nm-pd-detail-dl">
                        <div><dt>Color / Modelo</dt><dd>{selectedColor}</dd></div>
                        {p.type && <div><dt>Tipo</dt><dd>{p.type}</dd></div>}
                        {p.use && <div><dt>Uso</dt><dd>{p.use}</dd></div>}
                        {p.specs && p.specs.length > 0 && (
                          <div><dt>Características</dt><dd>{p.specs.join(' · ')}</dd></div>
                        )}
                      </dl>

                      {/* Format details — grouped by Finish → Thickness → Formats */}
                      <h4 className="nm-pd-detail-specs-title" style={{ marginTop: '24px' }}>Disponibilidad</h4>
                      {(() => {
                        // Get data sources
                        const cFinishes = colorFinishes || p.finishes || [];
                        const cThickness = colorThickness || p.thickness || [];
                        const cFormats = colorFormats || p.formats || [];
                        const fd = fdSource && fdSource.length > 0 ? fdSource : null;

                        if (fd) {
                          // Use formatDetails: group by finish → thickness → formats
                          const byFinish = {};
                          fd.forEach(item => {
                            const fins = Array.isArray(item.finishes) ? item.finishes : [item.finishes];
                            fins.forEach(fin => {
                              if (!byFinish[fin]) byFinish[fin] = {};
                              if (!byFinish[fin][item.thickness]) byFinish[fin][item.thickness] = [];
                              byFinish[fin][item.thickness].push(item.format);
                            });
                          });
                          return (
                            <div className="nm-pd-avail">
                              {Object.entries(byFinish).map(([finish, thicknesses]) => (
                                <div key={finish} className="nm-pd-avail-finish">
                                  <span className="nm-pd-avail-finish-name">{finish}</span>
                                  {Object.entries(thicknesses).map(([thick, fmts]) => (
                                    <div key={thick} className="nm-pd-avail-thick">
                                      <span className="nm-pd-avail-thick-label">{thick}</span>
                                      <span className="nm-pd-avail-formats">{fmts.join(' · ')}</span>
                                    </div>
                                  ))}
                                </div>
                              ))}
                            </div>
                          );
                        } else if (cFinishes.length > 0) {
                          // Per-color flat arrays: show finish → thickness → formats
                          return (
                            <div className="nm-pd-avail">
                              {cFinishes.map(fin => (
                                <div key={fin} className="nm-pd-avail-finish">
                                  <span className="nm-pd-avail-finish-name">{fin}</span>
                                  {cThickness.map(thick => (
                                    <div key={thick} className="nm-pd-avail-thick">
                                      <span className="nm-pd-avail-thick-label">{thick}</span>
                                      <span className="nm-pd-avail-formats">{cFormats.join(' · ')}</span>
                                    </div>
                                  ))}
                                </div>
                              ))}
                            </div>
                          );
                        } else {
                          return (
                            <dl className="nm-pd-detail-dl">
                              {cFormats.length > 0 && <div><dt>Formatos</dt><dd>{cFormats.join(' · ')}</dd></div>}
                              {cThickness.length > 0 && <div><dt>Espesores</dt><dd>{cThickness.join(' · ')}</dd></div>}
                            </dl>
                          );
                        }
                      })()}

                      <div className="nm-pd-detail-cta">
                        {(() => {
                          const alreadyInCart = sampleCart.some(s => s.brand === p.brand && s.collection === (p.name + (p.collection ? ' ' + p.collection : '')) && s.color === selectedColor);
                          return alreadyInCart ? (
                            <span className="nm-sample-added">✓ Muestra añadida</span>
                          ) : (
                            <button className="nm-btn nm-btn-primary nm-btn-sm" onClick={() => addSample({
                              brand: p.brand,
                              collection: p.name + (p.collection ? ' ' + p.collection : ''),
                              color: selectedColor,
                              img: imgUrl
                            })}>
                              Añadir muestra <span className="nm-arrow">→</span>
                            </button>
                          );
                        })()}
                      </div>
                    </div>
                  </div>
                </div>
                );
              })()}

              {lightboxImage && (
                <div className="nm-image-lightbox" onClick={() => setLightboxImage(null)}>
                  <button className="nm-image-lightbox-close" type="button" onClick={(e) => { e.stopPropagation(); setLightboxImage(null); }} aria-label="Cerrar imagen">
                    ✕
                  </button>
                  <div className="nm-image-lightbox-frame" onClick={(e) => e.stopPropagation()}>
                    <img src={lightboxImage.src} alt={lightboxImage.title} className="nm-image-lightbox-img" loading="lazy" decoding="async" />
                    <span className="nm-image-lightbox-caption">{p.name} — {lightboxImage.title}</span>
                  </div>
                </div>
              )}

              {/* Gallery grid */}
              {p.colorImages && Object.keys(p.colorImages).length > 0 ? (
                <div className="nm-pd-gallery">
                  {Object.entries(p.colorImages).map(([name, entry]) => {
                    const swatchUrl = typeof entry === 'string' ? entry : entry.img;
                    return (
                      <div key={name} className={`nm-pd-swatch-card ${selectedColor === name ? 'active' : ''}`} onClick={() => setSelectedColor(name)}>
                        <div className="nm-pd-swatch-img-wrap">
                          <img src={swatchUrl} alt={`${p.name} — ${name}`} className="nm-pd-swatch-img" loading="lazy" decoding="async" />
                        </div>
                        <span className="nm-pd-swatch-name">{name}</span>
                      </div>
                    );
                  })}
                </div>
              ) : (
                <p style={{ color: 'var(--fg-muted)', fontStyle: 'italic' }}>Imágenes en preparación</p>
              )}
            </div>

            {/* Right: specs table */}
            <div className="nm-pd-right">
              {renderAmbienceCarousel()}

              <h3 className="nm-pd-section-title">Especificaciones técnicas</h3>
              <dl className="nm-spec">
                <div><dt>Tipo</dt><dd>{p.type}</dd></div>
                {p.formats && p.formats.length > 0 && (
                  <div><dt>Formatos</dt><dd>{p.formats.join(' · ')}</dd></div>
                )}
                {p.finishes && p.finishes.length > 0 && (
                  <div><dt>Acabados</dt><dd>{p.finishes.join(' · ')}</dd></div>
                )}
                {p.thickness && p.thickness.length > 0 && (
                  <div><dt>Espesores</dt><dd>{p.thickness.join(' · ')}</dd></div>
                )}
                {p.use && (
                  <div><dt>Uso</dt><dd>{p.use}</dd></div>
                )}
                {p.specs && p.specs.length > 0 && (
                  <div><dt>Características</dt><dd>{p.specs.join(' · ')}</dd></div>
                )}
              </dl>

              {/* Formats visual grid */}
              {p.formats && p.formats.length > 0 && (
                <>
                  <h3 className="nm-pd-section-title" style={{ marginTop: '18px' }}>Formatos disponibles</h3>
                  <div className="nm-pd-formats">
                    {p.formats.map(f => (
                      <div key={f} className="nm-pd-format-chip">
                        {f}
                      </div>
                    ))}
                  </div>
                </>
              )}

              {/* CTA */}
              <div className="nm-pd-cta">
                <button className="nm-btn nm-btn-primary" onClick={() => {
                  if (!selectedColor) {
                    setShowSelectHint(true);
                    setTimeout(() => setShowSelectHint(false), 3000);
                  } else {
                    addSample({
                      brand: p.brand,
                      collection: p.name + (p.collection ? ' ' + p.collection : ''),
                      color: selectedColor,
                      img: (() => { const e = p.colorImages[selectedColor]; return typeof e === 'string' ? e : e.img; })()
                    });
                    onNav('sample');
                  }
                }}>
                  Pedir muestra <span className="nm-arrow">→</span>
                </button>
                <button className="nm-btn nm-btn-ghost" onClick={() => onNav('contact')}>
                  Consultar esta colección
                </button>
                {showSelectHint && (
                  <p className="nm-pd-select-hint">Selecciona un color de la galería para pedir tu muestra.</p>
                )}
                <p className="nm-product-availability" style={{ margin: '12px 0 0', fontSize: '12px', color: 'var(--ink-500)' }}>
                  <strong>Muestras gratuitas.</strong> Entrega estimada en 5–6 días laborables.
                </p>
              </div>

            </div>
          </div>
        </div>
      </section>

      {ambienceExpanded && activeAmbienceSlide && (
        <div className="nm-ambience-lightbox" onClick={() => setAmbienceExpanded(false)}>
          <button className="nm-image-lightbox-close nm-ambience-lightbox-close" type="button" onClick={(e) => { e.stopPropagation(); setAmbienceExpanded(false); }} aria-label="Cerrar carrusel">
            ✕
          </button>
          <div className="nm-ambience-lightbox-stage" onClick={(e) => e.stopPropagation()}>
            <img src={activeAmbienceSlide.src} alt={`${p.name} ${activeAmbienceSlide.title}`} className="nm-ambience-lightbox-img" loading="lazy" decoding="async" />
            {ambienceSlides.length > 1 && (
              <>
                <button className="nm-ambience-lightbox-arrow is-prev" type="button" onClick={() => moveAmbience(-1)} aria-label="Ambiente anterior">‹</button>
                <button className="nm-ambience-lightbox-arrow is-next" type="button" onClick={() => moveAmbience(1)} aria-label="Ambiente siguiente">›</button>
              </>
            )}
            <div className="nm-ambience-lightbox-caption">
              <strong>{p.name}</strong>
              <span>{activeAmbienceSlide.title}{ambienceSlides.length > 1 ? ` · ${ambienceIndex + 1}/${ambienceSlides.length}` : ''}</span>
            </div>
          </div>
        </div>
      )}

      {/* ── Related ── */}
      {related.length > 0 && (
        <Section eyebrow="Colecciones similares que te pueden interesar" className="nm-pd-related">
          <ProductGrid products={related} onOpen={(r) => onNav('product', r)} />
        </Section>
      )}
    </>
  );
};

const SampleScreen = ({ onNav, sampleCart = [], removeSample }) => {
  const steps = [
    ['01', 'Elige colección', 'Añade muestras desde la ficha o indícanos la serie que necesitas.'],
    ['02', 'Validamos disponibilidad', 'Revisamos formato, acabado, plazo y uso previsto antes de enviarlas.'],
    ['03', 'Envío a tu estudio', 'Preparamos la solicitud y te contactamos en 24 h laborables.'],
  ];
  const heroTiles = ['cotto-milano', 'gemmastone', 'tele-di-marmo-lumia', 'unique-travertine', 'matera-stone']
    .map(id => window.NM_PRODUCTS.find(p => p.id === id))
    .filter(Boolean);

  return (
    <>
      <section className="nm-samples-hero">
        <div className="nm-container nm-samples-hero-inner">
          <div className="nm-samples-title-wrap">
            <div className="nm-samples-title-scene" aria-hidden="true">
              <span className="nm-samples-title-rule" />
              {heroTiles.map((p, index) => (
                <span
                  key={p.id}
                  className={`nm-samples-title-tile tile-${index + 1}`}
                  style={{
                    backgroundImage: `url('${p.img}')`,
                    '--tile-index': index
                  }}
                />
              ))}
              <span className="nm-samples-title-pill is-one">muestra</span>
              <span className="nm-samples-title-pill is-two">ficha</span>
              <span className="nm-samples-title-pill is-three">plazo</span>
            </div>
            <div className="nm-samples-title-content">
              <span className="nm-eyebrow">Muestras profesionales · Cerámica italiana</span>
              <h1 className="nm-samples-h1">
                Pide muestras para <em>decidir con material real</em>.
              </h1>
            </div>
          </div>
          <div className="nm-samples-lead-block">
            <p className="nm-samples-lead">
              Para tiendas, estudios, reformistas y obra. Te ayudamos a seleccionar
              la pieza correcta y confirmar ficha, plazo y disponibilidad antes de presentar.
            </p>
            <div className="nm-samples-lead-tags" aria-label="Ventajas del servicio de muestras">
              <span>Selección real</span>
              <span>Confirmación técnica</span>
              <span>Respuesta 24 h</span>
            </div>
          </div>
        </div>
      </section>

      <section className="nm-samples-flow">
        <div className="nm-container nm-samples-flow-grid">
          {steps.map(([num, title, desc]) => (
            <article key={num} className="nm-samples-flow-item">
              <span>{num}</span>
              <h3>{title}</h3>
              <p>{desc}</p>
            </article>
          ))}
        </div>
      </section>

      <section className="nm-samples-main">
        <div className="nm-container nm-samples-grid">
          <aside className="nm-samples-summary">
            <span className="nm-eyebrow">Tu selección</span>
            <h2 className="nm-samples-summary-h2">
              {sampleCart.length > 0 ? `${sampleCart.length} muestra${sampleCart.length > 1 ? 's' : ''} seleccionada${sampleCart.length > 1 ? 's' : ''}.` : 'Empieza desde una colección.'}
            </h2>
            {sampleCart.length > 0 ? (
              <div className="nm-sample-cart">
                <h3 className="nm-sample-cart-title">Muestras seleccionadas</h3>
                <div className="nm-sample-cart-list">
                  {sampleCart.map((s, i) => (
                    <div key={i} className="nm-sample-cart-item">
                      <div className="nm-sample-cart-img-wrap">
                        <img src={s.img} alt={s.color} className="nm-sample-cart-img" loading="lazy" decoding="async" />
                      </div>
                      <div className="nm-sample-cart-info">
                        <span className="nm-sample-cart-brand">{s.brand}</span>
                        <span className="nm-sample-cart-collection">{s.collection}</span>
                        <span className="nm-sample-cart-color">{s.color}</span>
                      </div>
                      <button className="nm-sample-cart-remove" onClick={() => removeSample(i)} aria-label="Eliminar">✕</button>
                    </div>
                  ))}
                </div>
              </div>
            ) : (
              <div className="nm-samples-empty">
                <p>Si todavía no has elegido muestra, puedes enviarnos la solicitud igualmente o revisar el catálogo.</p>
                <button className="nm-btn nm-btn-ghost" onClick={() => onNav('catalog')}>
                  Ver catálogo <span className="nm-arrow">→</span>
                </button>
              </div>
            )}
            <div className="nm-samples-note">
              <strong>Qué revisamos antes de confirmar</strong>
              <span>Uso del material · formato · acabado · plazo · disponibilidad</span>
            </div>
          </aside>

          <div className="nm-samples-form-card">
            <span className="nm-eyebrow">Solicitud profesional</span>
            <h2 className="nm-samples-form-h2">Cuéntanos dónde van las muestras.</h2>
            <p className="nm-samples-form-p">
              Te llamamos en 24 h laborables para confirmar la selección y preparar el envío.
            </p>
            <SampleForm source="Pedir muestras" />
          </div>
        </div>
      </section>
    </>
  );
};

const ContactScreen = ({ onNav }) => {
  const contactRows = [
    ['Teléfono profesional', '+34 691 519 814', 'tel:+34691519814'],
    ['Email', 'novamateriaceramics@gmail.com', 'mailto:novamateriaceramics@gmail.com'],
    ['Zona de trabajo', 'Barcelona y provincia', null],
  ];
  const serviceRows = [
    ['01', 'Respuesta', 'Te contestamos en 24 h laborables.'],
    ['02', 'Muestras', 'Preparamos muestras según colección, formato y proyecto.'],
    ['03', 'Soporte', 'Revisamos ficha técnica, plazo y disponibilidad antes del pedido.'],
  ];
  const contactMaterials = ['cotto-milano', 'gemmastone', 'unique-travertine']
    .map(id => window.NM_PRODUCTS.find(p => p.id === id))
    .filter(Boolean);

  return (
    <>
      <section className="nm-contact-hero">
        <div className="nm-container nm-contact-hero-inner">
          <div className="nm-contact-hero-copy">
            <span className="nm-eyebrow">Contacto profesional · Nova Materia Ceramics</span>
            <h1 className="nm-contact-h1">
              Hablemos de tu <em>próximo proyecto</em>.
            </h1>
            <p className="nm-contact-lead">
              Si necesitas muestras, plazo de partida, fichas técnicas o una selección
              concreta para presentar a cliente, escríbenos y lo preparamos contigo.
            </p>
          </div>
          <div className="nm-contact-hero-panel">
            <span className="nm-contact-panel-label">Atención B2B</span>
            <strong>24 h laborables</strong>
            <p>Distribución profesional de cerámica italiana para tiendas, estudios, reformas y obra.</p>
            <div className="nm-contact-material-strip" aria-hidden="true">
              {contactMaterials.map((p, index) => (
                <span
                  key={p.id}
                  className={`nm-contact-material tile-${index + 1}`}
                  style={{ backgroundImage: `url('${p.img}')` }}
                >
                  <em>{p.brand}</em>
                </span>
              ))}
            </div>
            <div className="nm-contact-panel-stack" aria-hidden="true">
              <span><em>01</em> Muestras</span>
              <span><em>02</em> Ficha técnica</span>
              <span><em>03</em> Plazo confirmado</span>
            </div>
          </div>
        </div>
      </section>

      <section className="nm-contact-main">
        <div className="nm-container nm-contact-grid">
          <aside className="nm-contact-info">
            <span className="nm-eyebrow">Contacto directo</span>
            <div className="nm-contact-rows">
              {contactRows.map(([label, value, href]) => (
                <div className="nm-contact-row" key={label}>
                  <span>{label}</span>
                  {href ? <a href={href}>{value}</a> : <strong>{value}</strong>}
                </div>
              ))}
            </div>
            <div className="nm-contact-service">
              {serviceRows.map(([num, title, desc]) => (
                <div className="nm-contact-service-row" key={num}>
                  <span>{num}</span>
                  <div>
                    <strong>{title}</strong>
                    <p>{desc}</p>
                  </div>
                </div>
              ))}
            </div>
          </aside>
          <div className="nm-contact-form-card">
            <span className="nm-eyebrow">Solicitud</span>
            <h2 className="nm-contact-form-h2">Cuéntanos qué necesitas.</h2>
            <SampleForm source="Contacto profesional" />
          </div>
        </div>
      </section>
    </>
  );
};

const BrandsScreen = ({ onNav, onOpenProduct }) => {
  const findProduct = (id) => window.NM_PRODUCTS.find(p => p.id === id);
  const getProductImage = (product, slideIndex = 0) => (
    (product && product.ambienceImages && product.ambienceImages[slideIndex] && product.ambienceImages[slideIndex].src)
    || (product && product.img)
    || ''
  );
  const getBrandImage = (brand) => getProductImage(findProduct(brand.heroProductId), brand.heroSlide || 0);
  const signatureProductIds = {
    'Forme': 'forme',
    'MaPierre': 'mapierre',
    'Mimesis': 'mimesis',
    'Ever-Stone': 'ever-stone',
    'Tele di Marmo Onyx': 'tele-di-marmo-onyx',
    'Abacus': 'abacus',
    'Cornerstone': 'cornerstone',
    'Cornerstone Evolution': 'cornerstone-evolution',
    'Elegance Pro': 'elegance-pro',
    'I-Wood': 'i-wood',
    'Matera Stone': 'matera-stone',
    'Pigmento': 'pigmento',
    'Portland Stone': 'portland-stone',
    'Re-Play Concrete': 're-play-concrete',
    'Unique Bourg': 'unique-bourg',
    'W-Circles': 'w-circles',
    'Unique Intensity': 'unique-intensity',
    'Unique Travertine': 'unique-travertine',
    'CottoMilano': 'cotto-milano',
    'Trevi': 'trevi',
    'Brystone': 'brystone',
    'Omnia': 'omnia',
    'Elements Lux': 'elements-lux',
    'Discovery': 'discovery',
    'Versilia': 'versilia',
  };
  const getSignatureProduct = (name) => findProduct(signatureProductIds[name]);

  const brands = [
    {
      id: 'emil', name: 'Emil', group: 'Emilgroup', year: '1961',
      city: 'Fiorano Modenese · MO', specialty: 'Mármoles · Piedras editoriales',
      lead: 'La voz editorial del grupo. Mármoles estatuarios y piedras nobles en formatos de revestimiento hasta 120 × 278 cm. Una alternativa cerámica elegante para proyectos que buscan presencia, continuidad y facilidad de mantenimiento.',
      signatures: ['Forme', 'MaPierre', 'Mimesis', 'Ever-Stone', 'Tele di Marmo Onyx'],
      heroProductId: 'forme',
      heroSlide: 0,
      productIds: ['forme', 'ever-stone'],
    },
    {
      id: 'ergon', name: 'Ergon', group: 'Emilgroup', year: '1991',
      city: 'Sassuolo · MO', specialty: 'Arquitectura · Materia · Proyecto',
      lead: 'Superficies cerámicas pensadas para proyectos exigentes, desde vivienda hasta espacios comerciales. Piedras, cementos y maderas con una lectura natural, buena resistencia de uso y acabados preparados para interior y exterior.',
      signatures: ['Abacus', 'Cornerstone', 'Cornerstone Evolution', 'Elegance Pro', 'I-Wood', 'Matera Stone', 'Pigmento', 'Portland Stone'],
      heroProductId: 'matera-stone',
      heroSlide: 0,
      productIds: ['matera-stone', 'cornerstone-evolution'],
    },
    {
      id: 'provenza', name: 'Provenza', group: 'Emilgroup', year: '1975',
      city: 'Sassuolo · MO', specialty: 'Diseño · Grandes formatos · Color',
      lead: 'La voz contemporánea del grupo. Color, formato grande y series para interiorismo y proyectos editoriales donde la baldosa juega un papel narrativo, no de fondo.',
      signatures: ['Re-Play Concrete', 'Unique Bourg', 'W-Circles', 'Unique Intensity', 'Unique Travertine'],
      heroProductId: 'unique-travertine',
      heroSlide: 0,
      productIds: ['unique-travertine', 'w-circles'],
    },
    {
      id: 'keope', name: 'Keope', group: 'Gruppo Concorde', year: '1995',
      city: 'Casalgrande · RE', specialty: 'Piedra · Mármol · Interior y exterior',
      lead: 'Porcelánico italiano para arquitectura, interiorismo y exterior. Sus colecciones combinan estética muy cuidada con formatos grandes, soluciones de 20 mm y acabados antideslizantes para dar continuidad al proyecto dentro y fuera.',
      signatures: ['CottoMilano', 'Trevi', 'Brystone', 'Omnia', 'Elements Lux', 'Discovery', 'Versilia'],
      heroProductId: 'cotto-milano',
      heroSlide: 0,
      productIds: ['cotto-milano', 'elements-lux'],
    },
  ].map(brand => ({
    ...brand,
    img: getBrandImage(brand),
  }));

  const scrollToBrand = (id) => {
    if (window.location.hash) {
      window.history.replaceState(null, '', window.location.pathname + window.location.search);
    }
    const el = document.getElementById(id);
    if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
  };

  return (
    <>
      {/* Masthead — 4-panel image strip */}
      <section className="nm-marcas-mast">
        <div className="nm-marcas-mast-strip">
          {brands.map(b => (
            <div key={b.id} className="nm-marcas-mast-panel" style={{ backgroundImage: `url('${b.img}')` }}>
              <span className="nm-marcas-mast-tag">{b.name}</span>
              <span className="nm-marcas-mast-year">{b.year}</span>
            </div>
          ))}
        </div>
        <div className="nm-container nm-marcas-mast-caption">
          <span className="nm-eyebrow">Marcas que distribuimos · 4 sellos italianos</span>
          <h1 className="nm-marcas-mast-h1">
            Cuatro casas. <em>Un solo</em><br/>distretto ceramico.
          </h1>
          <p className="nm-marcas-mast-lead">
            Trabajamos directamente con los principales sellos del distrito ceramico
            de Sassuolo, Fiorano y Casalgrande. Sin intermediarios, con condiciones
            negociadas para profesionales en Barcelona y provincia.
          </p>
        </div>
      </section>

      {/* Directory — typographic table */}
      <section className="nm-marcas-directory">
        <div className="nm-container">
          <div className="nm-marcas-directory-row nm-marcas-directory-head">
            <span>Marca</span>
            <span>Grupo</span>
            <span>Fundada</span>
            <span>Sede</span>
            <span>Especialidad</span>
          </div>
          {brands.map(b => (
            <a key={b.id} href="" className="nm-marcas-directory-row" onClick={(e) => { e.preventDefault(); scrollToBrand(b.id); }}>
              <span className="nm-marcas-directory-name">{b.name}</span>
              <span>{b.group}</span>
              <span className="nm-marcas-directory-year">{b.year}</span>
              <span>{b.city}</span>
              <span>{b.specialty} <span className="nm-marcas-directory-arrow">→</span></span>
            </a>
          ))}
        </div>
      </section>

      {/* Per-brand spreads — alternating */}
      {brands.map((b, i) => {
        const products = b.productIds
          .map(id => window.NM_PRODUCTS.find(p => p.id === id))
          .filter(Boolean);
        return (
          <section key={b.id} id={b.id}
                   className={'nm-marcas-spread' + (i % 2 === 1 ? ' is-flipped' : '')}>
            <div className="nm-container nm-marcas-spread-inner">
              <div className="nm-marcas-spread-meta">
                <span className="nm-marcas-spread-num">
                  {String(i + 1).padStart(2, '0')} · {b.group}
                </span>
                <h2 className="nm-marcas-spread-name">
                  <em>{b.name}.</em>
                </h2>
                <dl className="nm-marcas-spread-data">
                  <div><dt>Fundada</dt><dd>{b.year}</dd></div>
                  <div><dt>Sede</dt><dd>{b.city}</dd></div>
                  <div><dt>Especialidad</dt><dd>{b.specialty}</dd></div>
                </dl>
                <p className="nm-marcas-spread-lead">{b.lead}</p>
                <div className="nm-marcas-spread-sigs">
                  <span className="nm-marcas-spread-sublabel">Colecciones de referencia</span>
                  <ul className="nm-marcas-spread-list">
                    {b.signatures.map(s => {
                      const signatureProduct = getSignatureProduct(s);
                      return (
                        <li key={s}>
                          {signatureProduct ? (
                            <button type="button" onClick={() => onOpenProduct(signatureProduct)}>
                              {s} <span>→</span>
                            </button>
                          ) : (
                            <span>{s}</span>
                          )}
                        </li>
                      );
                    })}
                  </ul>
                </div>
              </div>
              <div className="nm-marcas-spread-imgs">
                <div className="nm-marcas-spread-bigimg"
                     style={{ backgroundImage: `url('${b.img}')` }}>
                  <span className="nm-marcas-spread-bigimg-cap">
                    {b.name} · {b.specialty.split(' · ')[0]}
                  </span>
                </div>
                <div className="nm-marcas-spread-smimgs">
                  {products.length > 0 ? (
                    products.map(p => (
                      <button key={p.id} className="nm-marcas-spread-prodcard"
                              onClick={() => onOpenProduct(p)}>
                        <div className="nm-marcas-spread-prodimg"
                             style={{ backgroundImage: `url('${getProductImage(p)}')` }} />
                        <span className="nm-marcas-spread-prodbrand">{p.brand}</span>
                        <span className="nm-marcas-spread-prodname">
                          {p.name} <em>{p.collection}</em>
                        </span>
                        <span className="nm-marcas-spread-prodspec">
                          {p.specs.join(' · ')}
                        </span>
                      </button>
                    ))
                  ) : (
                    <div className="nm-marcas-spread-soon">
                      <span className="nm-eyebrow">Catálogo en construcción</span>
                      <p>Pide muestras directas a tu comercial.</p>
                    </div>
                  )}
                </div>
              </div>
            </div>
          </section>
        );
      })}

      {/* Matrix — guidance */}
      <section className="nm-marcas-matrix">
        <div className="nm-container">
          <div className="nm-marcas-matrix-head">
            <span className="nm-eyebrow">Guía rápida · Si tu proyecto necesita…</span>
            <h2 className="nm-marcas-matrix-h2">
              ¿Por dónde <em>empiezas?</em>
            </h2>
          </div>
          <div className="nm-marcas-matrix-grid">
            {[
              ['Mármol estatuario para revestimiento', 'Emil'],
              ['Cotto o piedra para residencial', 'Ergon'],
              ['Gran formato editorial · color', 'Provenza'],
              ['Exterior técnico antideslizante', 'Keope · Ergon'],
              ['Cemento contemporáneo', 'Provenza · Keope'],
              ['Acabado tradicional toscano', 'Ergon'],
            ].map(([q, a]) => (
              <div key={q} className="nm-marcas-matrix-row">
                <span className="nm-marcas-matrix-q">{q}</span>
                <span className="nm-marcas-matrix-arrow">→</span>
                <strong className="nm-marcas-matrix-a">{a}</strong>
              </div>
            ))}
          </div>
        </div>
      </section>

      {/* Closing CTA on cotto */}
      <section className="nm-marcas-cta">
        <div className="nm-container nm-marcas-cta-inner">
          <span className="nm-marcas-cta-eyebrow">Nova Materia Ceramics · Distribuidor B2B</span>
          <p className="nm-marcas-cta-quote">
            Una selección italiana <em>bien editada</em> para cada proyecto,
            con muestras y soporte <em>desde el primer contacto.</em>
          </p>
          <div className="nm-marcas-cta-actions">
            <button className="nm-btn nm-btn-primary nm-btn-lg" onClick={() => onNav('catalog')}>
              Ver catálogo completo <span className="nm-arrow">→</span>
            </button>
            <button className="nm-btn nm-btn-ghost nm-btn-lg" onClick={() => onNav('contact')}>
              Hablar con comercial
            </button>
          </div>
        </div>
      </section>
    </>
  );
};

const ProsScreen = ({ onNav, onOpenProduct }) => {
  const profiles = [
    {
      id: 'tienda', tag: '01', t: 'Tienda de materiales', sub: 'Mostrador y showroom propio',
      lead: 'Vendes a particulares y profesionales desde tu mostrador. Necesitas catálogo amplio, muestras físicas para tu expositor y márgenes de mayorista.',
      gets: ['Acceso a marcas Emilgroup + Keope', 'Margen de mayorista sobre PVP', 'Catálogos PDF y físicos para mostrador', 'Muestras para tu expositor', 'Visita comercial trimestral'],
      sample: 'cotto-milano',
    },
    {
      id: 'reformista', tag: '02', t: 'Reformista', sub: 'Reformas integrales y obra menor',
      lead: 'Cierras presupuestos en casa de cliente. Necesitas muestras concretas y plazo confirmado antes de pedir partida. Sin sorpresas en obra.',
      gets: ['Muestras gratis para tus presupuestos', 'Asesoramiento técnico antes de la obra', 'Plazo y partida confirmados en 24–48 h', 'Soporte técnico durante la instalación'],
      sample: 'gemmastone',
    },
    {
      id: 'interiorista', tag: '03', t: 'Interiorista', sub: 'Estudio de interiorismo residencial · comercial',
      lead: 'Trabajas con moodboards y propuestas visuales. Necesitas material editorial e imágenes en alta para presentar a cliente.',
      gets: ['Imágenes oficiales desde la web de la marca', 'Acceso a series editoriales y novedades', 'Muestras para presentación a cliente', 'Fichas técnicas (sin marca de agua)', 'Recomendación específica por proyecto'],
      sample: 'tele-di-marmo-revolution',
    },
    {
      id: 'arquitecto', tag: '04', t: 'Arquitecto', sub: 'Proyectos residenciales y comerciales',
      lead: 'Especificas material en proyecto. Necesitas certificados, fichas técnicas y soporte en obra, también en fase de dirección facultativa.',
      gets: ['Fichas técnicas completas y certificados', 'Asesoramiento para especificación del material', 'Visita técnica a obra', 'Muestra mínima 30 × 30 para presentación'],
      sample: 'cornerstone-evolution',
    },
    {
      id: 'distribuidor', tag: '05', t: 'Distribuidor', sub: 'Distribución secundaria',
      lead: 'Distribuyes a otros profesionales en zonas donde no tenemos cobertura directa. Acuerdo comercial y soporte logístico desde Barcelona.',
      gets: ['Condiciones de mayorista', 'Acuerdo comercial por zona', 'Soporte logístico desde Barcelona', 'Material de marketing co-branded'],
      sample: 'dual-travertine',
    },
  ];
  const [active, setActive] = useState('reformista');
  const [processIndex, setProcessIndex] = useState(0);
  const [testimonialIndex, setTestimonialIndex] = useState(0);
  const current = profiles.find(p => p.id === active) || profiles[0];
  const sampleProduct = window.NM_PRODUCTS.find(p => p.id === current.sample);
  const heroProducts = ['cotto-milano', 'gemmastone', 'unique-travertine']
    .map(id => window.NM_PRODUCTS.find(p => p.id === id))
    .filter(Boolean);
  const proofPoints = [
    {
      n: '01',
      t: 'Muestras útiles',
      d: 'Seleccionamos piezas reales para que cierres decisiones con el cliente, no solo con renders.',
    },
    {
      n: '02',
      t: 'Plazo antes de partida',
      d: 'Confirmamos disponibilidad y timing antes de que comprometas una obra o un presupuesto.',
    },
    {
      n: '03',
      t: 'Ficha técnica lista',
      d: 'Formatos, acabados, antideslizante y certificados preparados para especificar bien.',
    },
    {
      n: '04',
      t: 'Soporte de proyecto',
      d: 'Te ayudamos a elegir colección, acabado y formato según uso, tránsito y estética.',
    },
  ];

  const steps = [
    { n: '01', t: 'Alta profesional', d: 'Identificamos tu perfil, zona de trabajo y tipo de proyecto para darte condiciones adecuadas.', m: '24 h' },
    { n: '02', t: 'Selección técnica', d: 'Definimos colección, formato, acabado y uso previsto para evitar cambios de material a mitad de obra.', m: 'Asesoría' },
    { n: '03', t: 'Muestras físicas', d: 'Preparamos las piezas necesarias para presentar al cliente, validar tono y cerrar la decisión.', m: '48 a 72 h' },
    { n: '04', t: 'Disponibilidad y ficha', d: 'Revisamos stock, plazo, espesor, antideslizante y documentación técnica antes de presupuestar.', m: 'Validación' },
    { n: '05', t: 'Pedido confirmado', d: 'Tramitamos la partida con condiciones profesionales y confirmación de material antes de suministro.', m: 'Partida' },
    { n: '06', t: 'Entrega y seguimiento', d: 'Coordinamos la entrega y mantenemos soporte técnico si aparece cualquier duda durante la ejecución.', m: 'Obra' },
  ];
  const currentProcess = steps[processIndex] || steps[0];
  const goProcess = (direction) => {
    setProcessIndex(i => Math.min(steps.length - 1, Math.max(0, i + direction)));
  };
  React.useEffect(() => {
    const section = document.querySelector('.nm-prof-process');
    if (!section) return undefined;
    let frame = null;
    const update = () => {
      frame = null;
      const rect = section.getBoundingClientRect();
      const maxScroll = Math.max(1, section.offsetHeight - window.innerHeight);
      const isMobile = window.innerWidth <= 700;
      const headerOffset = isMobile ? 0 : 64;
      const scrollInSection = -rect.top + headerOffset;
      if (isMobile) {
        section.classList.toggle('is-process-pinned', scrollInSection >= 0 && scrollInSection < maxScroll);
        section.classList.toggle('is-process-done', scrollInSection >= maxScroll);
      } else {
        section.classList.remove('is-process-pinned', 'is-process-done');
      }
      const progress = Math.min(0.999, Math.max(0, scrollInSection / maxScroll));
      setProcessIndex(Math.min(steps.length - 1, Math.floor(progress * steps.length)));
    };
    const requestUpdate = () => {
      if (frame) return;
      frame = window.requestAnimationFrame(update);
    };
    window.addEventListener('scroll', requestUpdate, { passive: true });
    window.addEventListener('resize', requestUpdate);
    requestUpdate();
    return () => {
      if (frame) window.cancelAnimationFrame(frame);
      window.removeEventListener('scroll', requestUpdate);
      window.removeEventListener('resize', requestUpdate);
    };
  }, []);

  const matrix = [
    ['Catálogo profesional', '✓', '✓', '✓', '✓', '✓'],
    ['Muestras', '✓', '✓', '✓', '✓', '✓'],
    ['Fichas técnicas y certificados', '✓', '✓', '✓', '✓', '✓'],
    ['Visita comercial', 'Trimestral', 'A demanda', 'Por proyecto', 'A demanda', 'Mensual'],
    ['Soporte en obra', 'Según proyecto', '✓', 'Según proyecto', '✓', 'Según zona'],
    ['Margen profesional', 'Profesional', 'Profesional', 'Profesional', 'Profesional', 'Profesional'],
  ];
  const testimonials = [
    {
      eyebrow: 'Cliente · Reformista · Sant Cugat',
      quote: 'Pido muestras un martes, las tengo el jueves. Plazo confirmado el viernes. Es lo que necesito para cerrar presupuestos sin que el cliente se enfríe.',
      initials: 'JM',
      name: 'Jordi M.',
      role: 'Reformista · colaborador profesional',
    },
    {
      eyebrow: 'Cliente · Interiorista · Barcelona',
      quote: 'Nos ayuda mucho tener fichas, imágenes oficiales y muestras físicas antes de presentar. La propuesta llega al cliente con otra seguridad.',
      initials: 'LC',
      name: 'Laura C.',
      role: 'Interiorista · estudio residencial',
    },
    {
      eyebrow: 'Cliente · Tienda de materiales · Maresme',
      quote: 'El catálogo italiano nos permite enseñar algo diferente en tienda. Cuando pedimos apoyo para una serie concreta, la respuesta es rápida.',
      initials: 'PR',
      name: 'Pau R.',
      role: 'Tienda de materiales · exposición',
    },
    {
      eyebrow: 'Cliente · Arquitectura · Barcelona',
      quote: 'Para especificar necesitamos datos claros: acabado, formato, antideslizante y disponibilidad. Tenerlo ordenado ahorra correcciones.',
      initials: 'AS',
      name: 'Anna S.',
      role: 'Arquitecta · proyectos residenciales',
    },
    {
      eyebrow: 'Cliente · Distribución · Girona',
      quote: 'La diferencia está en confirmar partida y plazo antes de comprometer una entrega. Eso nos evita llamadas difíciles después.',
      initials: 'MV',
      name: 'Marc V.',
      role: 'Distribuidor · cliente profesional',
    },
  ];
  const currentTestimonial = testimonials[testimonialIndex] || testimonials[0];
  React.useEffect(() => {
    const timer = window.setInterval(() => {
      setTestimonialIndex(i => (i + 1) % testimonials.length);
    }, 5200);
    return () => window.clearInterval(timer);
  }, []);

  return (
    <>
      {/* Question masthead */}
      <section className="nm-prof-mast">
        <div className="nm-container nm-prof-mast-inner">
          <div className="nm-prof-mast-copy">
            <span className="nm-eyebrow">Para profesionales · B2B · Barcelona y provincia</span>
            <h1 className="nm-prof-mast-h1">
              Material italiano para <em>cerrar proyectos</em>.
            </h1>
            <p className="nm-prof-mast-lead">
              Trabajamos solo con profesionales del sector reforma e interiorismo.
              Cada perfil recibe condiciones, muestras y soporte específicos.
              Selecciona el tuyo abajo.
            </p>
            <div className="nm-prof-mast-jump">
              {profiles.map(p => (
                <button key={p.id}
                        className={'nm-prof-mast-chip' + (active === p.id ? ' is-active' : '')}
                        onClick={() => setActive(p.id)}>
                  <span className="nm-prof-mast-chip-num">{p.tag}</span>
                  <span>{p.t}</span>
                </button>
              ))}
            </div>
          </div>
          <div className="nm-prof-mast-visual" aria-hidden="true">
            {heroProducts[0] && (
              <div className="nm-prof-mast-heroimg" style={{ backgroundImage: `url('${heroProducts[0].img}')` }} />
            )}
            <div className="nm-prof-mast-brief">
              <span>Cuenta profesional</span>
              <strong>muestras · ficha · plazo</strong>
            </div>
            <div className="nm-prof-mast-stack">
              {heroProducts.slice(1).map(p => (
                <div key={p.id} className="nm-prof-mast-tile">
                  <div className="nm-prof-mast-tileimg" style={{ backgroundImage: `url('${p.img}')` }} />
                  <span>{p.brand}</span>
                  <strong>{p.name}</strong>
                </div>
              ))}
            </div>
          </div>
        </div>
      </section>

      <section className="nm-prof-proof">
        <div className="nm-container nm-prof-proof-inner">
          <div className="nm-prof-proof-head">
            <span className="nm-eyebrow">Lo importante · Antes de pedir partida</span>
            <h2 className="nm-prof-proof-h2">
              Menos catálogo infinito. <em>Más decisión.</em>
            </h2>
            <p>
              Te damos la información que de verdad desbloquea una venta o una obra:
              muestra correcta, ficha clara, plazo confirmado y soporte cuando hay dudas técnicas.
            </p>
          </div>
          <div className="nm-prof-proof-grid">
            {proofPoints.map(point => (
              <article key={point.n} className="nm-prof-proof-item">
                <span>{point.n}</span>
                <h3>{point.t}</h3>
                <p>{point.d}</p>
              </article>
            ))}
          </div>
        </div>
      </section>

      {/* Profile picker */}
      <section className="nm-prof-picker">
        <div className="nm-container nm-prof-picker-inner">
          <aside className="nm-prof-picker-tabs">
            {profiles.map(p => (
              <button key={p.id}
                      className={'nm-prof-picker-tab' + (active === p.id ? ' is-active' : '')}
                      onClick={() => setActive(p.id)}>
                <span className="nm-prof-picker-tabnum">{p.tag}</span>
                <div className="nm-prof-picker-tabtext">
                  <span className="nm-prof-picker-tabt">{p.t}</span>
                  <span className="nm-prof-picker-tabsub">{p.sub}</span>
                </div>
                <span className="nm-prof-picker-tabarrow">→</span>
              </button>
            ))}
          </aside>
          <div className="nm-prof-picker-panel">
            <span className="nm-eyebrow">Perfil {current.tag} · {current.t}</span>
            <h2 className="nm-prof-picker-h2">{current.lead}</h2>
            <div className="nm-prof-picker-grid">
              <div className="nm-prof-picker-col">
                <span className="nm-prof-picker-sublabel">Lo que recibes</span>
                <ul className="nm-prof-picker-list">
                  {current.gets.map(g => <li key={g}>{g}</li>)}
                </ul>
                <button className="nm-btn nm-btn-primary nm-btn-lg" onClick={() => onNav('contact')}>
                  Activar cuenta como {current.t.toLowerCase()} <span className="nm-arrow">→</span>
                </button>
              </div>
              {sampleProduct && (
                <div className="nm-prof-picker-col">
                  <span className="nm-prof-picker-sublabel">Tu primera muestra sugerida</span>
                  <button className="nm-prof-picker-prod"
                          onClick={() => onOpenProduct && onOpenProduct(sampleProduct)}>
                    <div className="nm-prof-picker-prodimg"
                         style={{ backgroundImage: `url('${sampleProduct.img}')` }} />
                    <div className="nm-prof-picker-prodmeta">
                      <span className="nm-prof-picker-prodbrand">{sampleProduct.brand}</span>
                      <span className="nm-prof-picker-prodname">
                        {sampleProduct.name} <em>{sampleProduct.collection}</em>
                      </span>
                      <span className="nm-prof-picker-prodspec">
                        {sampleProduct.specs.join(' · ')}
                      </span>
                      <span className="nm-prof-picker-prodview">Ver ficha completa →</span>
                    </div>
                  </button>
                </div>
              )}
            </div>
          </div>
        </div>
      </section>

      {/* Process timeline */}
      <section className="nm-prof-process">
        <div className="nm-prof-process-sticky">
          <div className="nm-container">
            <div className="nm-prof-process-head">
              <div>
                <h2 className="nm-prof-process-h2">
                  Un circuito claro para <em>presupuestar sin improvisar.</em>
                </h2>
                <p className="nm-prof-process-lead">
                  Cada paso deja una decisión cerrada: muestra, ficha, disponibilidad,
                  plazo y condiciones antes de mover una partida.
                </p>
              </div>
            </div>
            <div className="nm-prof-process-console">
              <div className="nm-prof-process-stage">
                <div key={currentProcess.n} className="nm-prof-process-copy">
                  <div className="nm-prof-process-stage-top">
                    <span className="nm-prof-process-num">{currentProcess.n}</span>
                    <span className="nm-prof-process-meta">{currentProcess.m}</span>
                  </div>
                  <h3 className="nm-prof-process-t">{currentProcess.t}</h3>
                  <p className="nm-prof-process-d">{currentProcess.d}</p>
                </div>
                <div className="nm-prof-process-meter" aria-hidden="true">
                  <span style={{ width: `${((processIndex + 1) / steps.length) * 100}%` }} />
                </div>
                <div className="nm-prof-process-actions">
                  <button type="button" onClick={() => goProcess(-1)} disabled={processIndex === 0}>
                    Anterior
                  </button>
                  <button type="button" onClick={() => goProcess(1)} disabled={processIndex === steps.length - 1}>
                    Siguiente
                  </button>
                </div>
              </div>
              <ol className="nm-prof-process-track">
                {steps.map((s, index) => (
                  <li key={s.n}>
                    <button
                      type="button"
                      className={'nm-prof-process-step' + (index === processIndex ? ' is-active' : '')}
                      onClick={() => setProcessIndex(index)}
                    >
                      <span className="nm-prof-process-stepnum">{s.n}</span>
                      <span className="nm-prof-process-stept">{s.t}</span>
                    </button>
                  </li>
                ))}
              </ol>
            </div>
          </div>
        </div>
        <div className="nm-prof-process-scroll" aria-hidden="true">
          {steps.map((s, index) => (
            <div key={s.n} className="nm-prof-process-scrollstep" />
          ))}
          </div>
      </section>

      {/* Comparison matrix */}
      <section className="nm-prof-matrix">
        <div className="nm-container">
          <div className="nm-prof-matrix-head">
            <span className="nm-eyebrow">Servicios · Por perfil profesional</span>
            <h2 className="nm-prof-matrix-h2">
              Lo que recibes <em>según tu actividad.</em>
            </h2>
          </div>
          <div className="nm-prof-matrix-tablewrap">
            <table className="nm-prof-matrix-table">
              <thead>
                <tr>
                  <th>Servicio</th>
                  {profiles.map(p => (
                    <th key={p.id}
                        className={active === p.id ? 'is-active' : ''}>
                      <span className="nm-prof-matrix-thnum">{p.tag}</span>
                      {p.t}
                    </th>
                  ))}
                </tr>
              </thead>
              <tbody>
                {matrix.map(row => (
                  <tr key={row[0]}>
                    {row.map((cell, j) => {
                      const colProfile = profiles[j - 1];
                      const isActiveCol = colProfile && colProfile.id === active;
                      const isCheck = cell === '✓';
                      return (
                        <td key={j}
                            className={[
                              j === 0 ? 'is-svc' : '',
                              isActiveCol ? 'is-active' : '',
                              isCheck ? 'is-check' : '',
                            ].filter(Boolean).join(' ')}>
                          {cell}
                        </td>
                      );
                    })}
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </div>
      </section>

      {/* Testimonial */}
      <section className="nm-prof-testimonial">
        <div className="nm-container nm-prof-testimonial-inner">
          <div className="nm-prof-testimonial-head">
            <span className="nm-eyebrow" style={{ color: 'var(--cotto-300)' }}>
              {currentTestimonial.eyebrow}
            </span>
            <span className="nm-prof-testimonial-count">
              {String(testimonialIndex + 1).padStart(2, '0')} / {String(testimonials.length).padStart(2, '0')}
            </span>
          </div>
          <p className="nm-prof-testimonial-q">
            “{currentTestimonial.quote}”
          </p>
          <div className="nm-prof-testimonial-meta">
            <div className="nm-prof-testimonial-avatar">{currentTestimonial.initials}</div>
            <div className="nm-prof-testimonial-sig">
              <strong>{currentTestimonial.name}</strong>
              <span>{currentTestimonial.role}</span>
            </div>
            <div className="nm-prof-testimonial-controls">
              <button
                type="button"
                onClick={() => setTestimonialIndex(i => (i - 1 + testimonials.length) % testimonials.length)}
                aria-label="Reseña anterior"
              >
                Anterior
              </button>
              <button
                type="button"
                onClick={() => setTestimonialIndex(i => (i + 1) % testimonials.length)}
                aria-label="Reseña siguiente"
              >
                Siguiente
              </button>
            </div>
          </div>
          <div className="nm-prof-testimonial-dots" aria-hidden="true">
            {testimonials.map((item, index) => (
              <button
                key={item.initials}
                type="button"
                className={index === testimonialIndex ? 'is-active' : ''}
                onClick={() => setTestimonialIndex(index)}
              />
            ))}
          </div>
        </div>
      </section>

      {/* CTA dual */}
      <section className="nm-prof-finalcta">
        <div className="nm-container nm-prof-finalcta-inner">
          <div className="nm-prof-finalcta-text">
            <span className="nm-eyebrow">Activa cuenta</span>
            <h2 className="nm-prof-finalcta-h2">
              Empieza a trabajar con <em>Nova Materia Ceramics</em>.
            </h2>
            <p className="nm-prof-finalcta-p">
              Cuéntanos qué tipo de profesional eres y qué proyectos llevas.
              Te llamamos en 24 h laborables. También puedes llamarnos directamente.
            </p>
            <button className="nm-btn nm-btn-primary nm-btn-lg" onClick={() => onNav('contact')}>
              Contactar y activar cuenta <span className="nm-arrow">→</span>
            </button>
          </div>
          <a className="nm-prof-finalcta-phone" href="tel:+34691519814">
            <span className="nm-prof-finalcta-phone-eyebrow">Línea profesional · L–V 9–18 h</span>
            <span className="nm-prof-finalcta-phone-num">+34 691 519 814</span>
            <span className="nm-prof-finalcta-phone-meta">novamateriaceramics@gmail.com</span>
          </a>
        </div>
      </section>
    </>
  );
};

Object.assign(window, { HomeScreen, CatalogScreen, ProductScreen, SampleScreen, ContactScreen, LoginScreen, ClientScreen, BrandsScreen, ProsScreen });
