function parseEuro(raw) { if (!raw) return 0; const clean = raw.replace(/[^\d,]/g, "").replace(",", "."); const val = parseFloat(clean); return Number.isFinite(val) ? val : 0; } async function getTotalReparacion(page) { // Selector “deep” que atraviesa Shadow DOM const deepSel = 'css=multiasistencia-valoraciones >>> td[data-label^="TOTAL REPARACION"]'; // 1) Intenta en todos los frames (por si la web lo mete en alguno) for (const frame of page.frames()) { try { const loc = frame.locator(deepSel).first(); await loc.waitFor({ state: "attached", timeout: 8000 }); const raw = await loc.innerText(); const val = parseEuro(raw); if (val > 0) return val; } catch {} } // 2) Fallback: búsqueda profunda recorriendo shadowRoots abiertos (por si cambia el HTML) const raw2 = await page.evaluate(() => { const seen = new Set(); function findIn(root) { if (!root || seen.has(root)) return null; seen.add(root); // busca el td por data-label const td = root.querySelector?.('td[data-label^="TOTAL REPARACION"]'); if (td) return td.innerText; // recorre hijos y sus shadowRoots const els = root.querySelectorAll ? Array.from(root.querySelectorAll("*")) : []; for (const el of els) { if (el.shadowRoot) { const hit = findIn(el.shadowRoot); if (hit) return hit; } } return null; } return findIn(document); }); return parseEuro(raw2); }