{"id":6,"date":"2025-10-16T12:01:15","date_gmt":"2025-10-16T12:01:15","guid":{"rendered":"https:\/\/calculadora.demotest.es\/?page_id=6"},"modified":"2025-11-04T10:30:28","modified_gmt":"2025-11-04T10:30:28","slug":"calculadora","status":"publish","type":"page","link":"https:\/\/calculadora.demotest.es\/","title":{"rendered":"Calculadora"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"6\" class=\"elementor elementor-6\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-90cb8dd e-flex e-con-boxed e-con e-parent\" data-id=\"90cb8dd\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-2ae8657 elementor-widget elementor-widget-image\" data-id=\"2ae8657\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img fetchpriority=\"high\" decoding=\"async\" width=\"1088\" height=\"686\" src=\"https:\/\/calculadora.demotest.es\/wp-content\/uploads\/2025\/10\/logo-entero-17h20zh9-2023-06-28.png\" class=\"attachment-full size-full wp-image-201\" alt=\"\" srcset=\"https:\/\/calculadora.demotest.es\/wp-content\/uploads\/2025\/10\/logo-entero-17h20zh9-2023-06-28.png 1088w, https:\/\/calculadora.demotest.es\/wp-content\/uploads\/2025\/10\/logo-entero-17h20zh9-2023-06-28-300x189.png 300w, https:\/\/calculadora.demotest.es\/wp-content\/uploads\/2025\/10\/logo-entero-17h20zh9-2023-06-28-1024x646.png 1024w, https:\/\/calculadora.demotest.es\/wp-content\/uploads\/2025\/10\/logo-entero-17h20zh9-2023-06-28-768x484.png 768w\" sizes=\"(max-width: 1088px) 100vw, 1088px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-1942d40 e-flex e-con-boxed e-con e-parent\" data-id=\"1942d40\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-64b8812 e-n-tabs-mobile elementor-widget elementor-widget-n-tabs\" data-id=\"64b8812\" data-element_type=\"widget\" data-settings=\"{&quot;horizontal_scroll&quot;:&quot;disable&quot;}\" data-widget_type=\"nested-tabs.default\">\n\t\t\t\t\t\t\t<div class=\"e-n-tabs\" data-widget-number=\"105613330\" aria-label=\"Pesta\u00f1as. Abre elementos con Intro o Espacio, ci\u00e9rralos con Escape y navega con las fechas.\">\n\t\t\t<div class=\"e-n-tabs-heading\" role=\"tablist\">\n\t\t\t\t\t<button id=\"e-n-tab-title-1056133301\" class=\"e-n-tab-title\" aria-selected=\"true\" data-tab-index=\"1\" role=\"tab\" tabindex=\"0\" aria-controls=\"e-n-tab-content-1056133301\" style=\"--n-tabs-title-order: 1;\">\n\t\t\t\t\t<span class=\"e-n-tab-icon\">\n\t\t\t<svg aria-hidden=\"true\" class=\"e-font-icon-svg e-far-file\" viewBox=\"0 0 384 512\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M369.9 97.9L286 14C277 5 264.8-.1 252.1-.1H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V131.9c0-12.7-5.1-25-14.1-34zM332.1 128H256V51.9l76.1 76.1zM48 464V48h160v104c0 13.3 10.7 24 24 24h104v288H48z\"><\/path><\/svg>\t\t\t<svg aria-hidden=\"true\" class=\"e-font-icon-svg e-far-file\" viewBox=\"0 0 384 512\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M369.9 97.9L286 14C277 5 264.8-.1 252.1-.1H48C21.5 0 0 21.5 0 48v416c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V131.9c0-12.7-5.1-25-14.1-34zM332.1 128H256V51.9l76.1 76.1zM48 464V48h160v104c0 13.3 10.7 24 24 24h104v288H48z\"><\/path><\/svg>\t\t<\/span>\n\t\t\t\t\t<span class=\"e-n-tab-title-text\">\n\t\t\t\tCalculadora individual\t\t\t<\/span>\n\t\t<\/button>\n\t\t\t\t<button id=\"e-n-tab-title-1056133302\" class=\"e-n-tab-title\" aria-selected=\"false\" data-tab-index=\"2\" role=\"tab\" tabindex=\"-1\" aria-controls=\"e-n-tab-content-1056133302\" style=\"--n-tabs-title-order: 2;\">\n\t\t\t\t\t<span class=\"e-n-tab-icon\">\n\t\t\t<svg aria-hidden=\"true\" class=\"e-font-icon-svg e-far-file-alt\" viewBox=\"0 0 384 512\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M288 248v28c0 6.6-5.4 12-12 12H108c-6.6 0-12-5.4-12-12v-28c0-6.6 5.4-12 12-12h168c6.6 0 12 5.4 12 12zm-12 72H108c-6.6 0-12 5.4-12 12v28c0 6.6 5.4 12 12 12h168c6.6 0 12-5.4 12-12v-28c0-6.6-5.4-12-12-12zm108-188.1V464c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V48C0 21.5 21.5 0 48 0h204.1C264.8 0 277 5.1 286 14.1L369.9 98c9 8.9 14.1 21.2 14.1 33.9zm-128-80V128h76.1L256 51.9zM336 464V176H232c-13.3 0-24-10.7-24-24V48H48v416h288z\"><\/path><\/svg>\t\t\t<svg aria-hidden=\"true\" class=\"e-font-icon-svg e-far-file-alt\" viewBox=\"0 0 384 512\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M288 248v28c0 6.6-5.4 12-12 12H108c-6.6 0-12-5.4-12-12v-28c0-6.6 5.4-12 12-12h168c6.6 0 12 5.4 12 12zm-12 72H108c-6.6 0-12 5.4-12 12v28c0 6.6 5.4 12 12 12h168c6.6 0 12-5.4 12-12v-28c0-6.6-5.4-12-12-12zm108-188.1V464c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V48C0 21.5 21.5 0 48 0h204.1C264.8 0 277 5.1 286 14.1L369.9 98c9 8.9 14.1 21.2 14.1 33.9zm-128-80V128h76.1L256 51.9zM336 464V176H232c-13.3 0-24-10.7-24-24V48H48v416h288z\"><\/path><\/svg>\t\t<\/span>\n\t\t\t\t\t<span class=\"e-n-tab-title-text\">\n\t\t\t\tCalculadora masiva\t\t\t<\/span>\n\t\t<\/button>\n\t\t\t\t\t<\/div>\n\t\t\t<div class=\"e-n-tabs-content\">\n\t\t\t\t<div id=\"e-n-tab-content-1056133301\" role=\"tabpanel\" aria-labelledby=\"e-n-tab-title-1056133301\" data-tab-index=\"1\" style=\"--n-tabs-title-order: 1;\" class=\"e-active elementor-element elementor-element-5280d0c e-con-full e-flex e-con e-child\" data-id=\"5280d0c\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-47edc37 elementor-widget elementor-widget-html\" data-id=\"47edc37\" data-element_type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<!-- ===== Calculadora de tallas \u2014 Individual (embebible, aislada) ===== -->\n<section id=\"ml-individual\" aria-label=\"Calculadora de tallaje\">\n  <style>\n    \/* Scope: solo dentro de #ml-individual *\/\n    #ml-individual{--black:#000;--white:#fff;--gray:#555;--light:#f2f2f2;font-family:Arial,Helvetica,sans-serif;color:var(--black)}\n    #ml-individual .wrap{max-width:1080px;margin:12px auto;padding:24px}\n    #ml-individual .card{background:#fff;border:1px solid var(--black);border-radius:10px;box-shadow:0 2px 6px rgba(0,0,0,.08)}\n    #ml-individual header{padding:18px 22px;border-bottom:1px solid var(--black);display:flex;justify-content:space-between;align-items:center;gap:16px}\n    #ml-individual header h1{font-size:30px;margin:0}\n    #ml-individual header small{color:var(--gray)}\n    #ml-individual .unit-toggle{display:flex;gap:6px;align-items:center}\n    #ml-individual .toggle{display:inline-flex;border:1px solid var(--black);border-radius:999px;overflow:hidden}\n    #ml-individual .toggle button{padding:6px 10px;border:0;background:#ffd400;color:#000;cursor:pointer}\n    #ml-individual .toggle button.active{background:#000;color:#ffd400}\n\n    #ml-individual .grid{display:grid;gap:22px;padding:24px;grid-template-columns:repeat(12,1fr)}\n    #ml-individual .col-7{grid-column:span 7}\n    #ml-individual .col-6{grid-column:span 6}\n    #ml-individual .col-5{grid-column:span 5}\n    #ml-individual .col-4{grid-column:span 4}\n    #ml-individual .col-12{grid-column:span 12}\n\n    #ml-individual label{display:block;margin:0 0 8px 2px;font-size:14px;font-weight:700}\n    #ml-individual select,#ml-individual input{width:100%;padding:14px 16px;border-radius:8px;border:1px solid var(--black);background:#fff;color:#000;font-size:16px;font-weight:bold;text-align:center}\n    #ml-individual input{appearance:textfield;-webkit-appearance:textfield;-moz-appearance:textfield}\n    #ml-individual select{appearance:auto;-webkit-appearance:auto;-moz-appearance:auto;cursor:pointer;text-align-last:center}\n    #ml-individual .hint{font-size:10px;color:var(--gray)}\n    #ml-individual .actions{display:flex;gap:14px;flex-wrap:wrap;align-items:center}\n    #ml-individual .btn{border:1px solid var(--black);background:#fff;color:#000;padding:12px 18px;border-radius:8px;cursor:pointer;font-size:16px;font-weight:bold;transition:all .15s ease-in-out}\n    #ml-individual .btn.primary{background:#000;color:#fff}\n    #ml-individual .btn:disabled{opacity:.5;cursor:not-allowed}\n\n    \/* Hover universal amarillo *\/\n    #ml-individual .btn:hover,#ml-individual .btn.primary:hover{background:#ffd400;color:#000;border-color:#000}\n    #ml-individual .btn:active,#ml-individual .btn.primary:active{filter:brightness(.95)}\n    #ml-individual .btn:focus-visible{outline:2px solid #000;outline-offset:2px}\n\n    #ml-individual .result{padding:24px;border-top:1px solid var(--black)}\n    #ml-individual .result h2{margin:0 0 10px 0;font-size:20px}\n    #ml-individual .table{width:100%;border-collapse:collapse;border:1px solid var(--black)}\n    #ml-individual .table th,#ml-individual .table td{padding:12px;border:1px solid var(--black);text-align:center;font-weight:bold;font-size:16px}\n    #ml-individual .pill{display:inline-block;padding:2px 8px;border-radius:6px;background:#000;color:#fff;font-size:12px}\n    #ml-individual .notice{background:var(--light);padding:12px;border:1px dashed var(--black);border-radius:8px;color:#000}\n    #ml-individual footer{padding:18px;color:var(--gray);font-size:12px}\n\n    #ml-individual .visual{grid-column:span 5;display:flex;justify-content:flex-start;align-items:flex-start;padding:8px;min-height:260px;overflow:hidden;position:relative}\n    #ml-individual .visual-inner{display:flex;flex-direction:column;gap:12px;align-items:flex-start;width:100%}\n    #ml-individual .preview-img{width:clamp(200px,36vw,380px);max-height:360px;object-fit:contain;display:block;border:1px solid var(--black);border-radius:8px;background:#fff}\n    #ml-individual .preview-title{font-size:14px;color:var(--gray);margin-left:2px}\n\n    @media (max-width:960px){\n      #ml-individual .col-7,#ml-individual .col-6,#ml-individual .col-5{grid-column:span 12}\n      #ml-individual .grid{gap:18px;padding:18px}\n      #ml-individual .visual{min-height:220px}\n    }\n  <\/style>\n\n  <div class=\"wrap\">\n    <div class=\"card\">\n      <header>\n        <div>\n          <h1>Calculadora de tallas<\/h1>\n          <small>EN 13402 \/ UNE-ISO 8559 \u00b7 Prototipo UE<\/small>\n        <\/div>\n        <div class=\"unit-toggle\">\n          <span class=\"hint\">Unidades<\/span>\n          <div class=\"toggle\">\n            <button data-ml1=\"btn-cm\" class=\"active\" type=\"button\">cm<\/button>\n            <button data-ml1=\"btn-in\" type=\"button\">in<\/button>\n          <\/div>\n        <\/div>\n      <\/header>\n\n      <form class=\"grid\" data-ml1=\"form\">\n        <!-- IZQUIERDA: PREVIEW IMAGEN -->\n        <div class=\"visual col-5\">\n          <div class=\"visual-inner\">\n            <img decoding=\"async\" class=\"preview-img\" data-ml1=\"preview\" referrerpolicy=\"no-referrer\"\n                 src=\"https:\/\/calculadora.demotest.es\/img\/products\/camiseta.jpg\" alt=\"Prenda seleccionada\" \/>\n            <div class=\"preview-title\" data-ml1=\"previewTitle\">Camiseta \/ Top<\/div>\n          <\/div>\n        <\/div>\n\n        <!-- DERECHA: FORMULARIO -->\n        <div class=\"col-7 form-pane\">\n          <div class=\"grid\">\n            <div class=\"col-6\">\n              <label>\u00bfPara qui\u00e9n es la prenda?<\/label>\n              <select data-ml1=\"persona\">\n                <option value=\"\">Selecciona\u2026<\/option>\n                <option value=\"mujer\">Mujer<\/option>\n                <option value=\"hombre\" selected>Hombre<\/option>\n                <option value=\"nina\">Ni\u00f1a<\/option>\n                <option value=\"nino\">Ni\u00f1o<\/option>\n              <\/select>\n            <\/div>\n\n            <div class=\"col-6\">\n              <label>Prenda<\/label>\n              <select data-ml1=\"garment\">\n                <optgroup label=\"Tops \/ Cuerpo\">\n                  <option value=\"top\" data-image=\"https:\/\/calculadora.demotest.es\/img\/products\/camiseta.jpg\" selected>Camiseta \/ Top<\/option>\n                  <option value=\"top\" data-image=\"https:\/\/calculadora.demotest.es\/img\/products\/camisa.jpg\">Camisa<\/option>\n                  <option value=\"top\" data-image=\"https:\/\/calculadora.demotest.es\/img\/products\/polo.jpg\">Polo<\/option>\n                  <option value=\"top\" data-image=\"https:\/\/calculadora.demotest.es\/img\/products\/sudadera.jpg\">Sudadera<\/option>\n                  <option value=\"top\" data-image=\"https:\/\/calculadora.demotest.es\/img\/products\/jersey.jpg\">Jersey<\/option>\n                  <option value=\"top\" data-image=\"https:\/\/calculadora.demotest.es\/img\/products\/cardigan.jpg\">Cardigan<\/option>\n                  <option value=\"top\" data-image=\"https:\/\/calculadora.demotest.es\/img\/products\/vestido.jpg\">Vestido (busto)<\/option>\n                <\/optgroup>\n                <optgroup label=\"Chaquetas \/ Abrigos\">\n                  <option value=\"jacket\" data-image=\"https:\/\/calculadora.demotest.es\/img\/products\/chaqueta.jpg\">Chaqueta<\/option>\n                  <option value=\"jacket\" data-image=\"https:\/\/calculadora.demotest.es\/img\/products\/abrigo.jpg\">Abrigo<\/option>\n                  <option value=\"jacket\" data-image=\"https:\/\/calculadora.demotest.es\/img\/products\/americana.jpg\">Americana \/ Traje<\/option>\n                <\/optgroup>\n                <optgroup label=\"Parte inferior\">\n                  <option value=\"bottom\" data-image=\"https:\/\/calculadora.demotest.es\/img\/products\/pantalon.jpg\">Pantal\u00f3n<\/option>\n                  <option value=\"bottom\" data-image=\"https:\/\/calculadora.demotest.es\/img\/products\/vaquero.jpg\">Vaquero<\/option>\n                  <option value=\"bottom\" data-image=\"https:\/\/calculadora.demotest.es\/img\/products\/shorts.jpg\">Shorts<\/option>\n                  <option value=\"bottom\" data-image=\"https:\/\/calculadora.demotest.es\/img\/products\/falda.jpg\">Falda<\/option>\n                  <option value=\"bottom\" data-image=\"https:\/\/calculadora.demotest.es\/img\/products\/leggins.jpg\">Leggings<\/option>\n                <\/optgroup>\n                <optgroup label=\"Resto\">\n                  <option value=\"top\" data-image=\"https:\/\/calculadora.demotest.es\/img\/products\/camiseta.jpg\">Pijama (pecho\/busto)<\/option>\n                  <option value=\"bottom\" data-image=\"https:\/\/calculadora.demotest.es\/img\/products\/camiseta.jpg\">Ropa interior (cintura)<\/option>\n                <\/optgroup>\n              <\/select>\n            <\/div>\n\n            <!-- Medidas principales -->\n            <div class=\"col-4\" data-ml1=\"grp-busto\">\n              <label>Busto \/ Pecho <span class=\"hint unit\" data-ml1=\"u-busto\">(cm)<\/span><\/label>\n              <input type=\"text\" inputmode=\"decimal\" placeholder=\"92,0\" data-ml1=\"busto\" \/>\n            <\/div>\n            <div class=\"col-4\" data-ml1=\"grp-cintura\">\n              <label>Cintura <span class=\"hint unit\" data-ml1=\"u-cintura\">(cm)<\/span><\/label>\n              <input type=\"text\" inputmode=\"decimal\" placeholder=\"74,0\" data-ml1=\"cintura\" \/>\n            <\/div>\n            <div class=\"col-4\" data-ml1=\"grp-cadera\">\n              <label>Cadera <span class=\"hint unit\" data-ml1=\"u-cadera\">(cm)<\/span><\/label>\n              <input type=\"text\" inputmode=\"decimal\" placeholder=\"98,0\" data-ml1=\"cadera\" \/>\n            <\/div>\n\n            <!-- Altura + Pa\u00eds -->\n            <div class=\"col-4\" data-ml1=\"grp-altura\">\n              <label>Altura <span class=\"hint unit\" data-ml1=\"u-altura\">(cm)<\/span><\/label>\n              <input type=\"text\" inputmode=\"decimal\" placeholder=\"170,0\" data-ml1=\"altura\" \/>\n            <\/div>\n            <div class=\"col-4\">\n              <label>Pa\u00eds (UE)<\/label>\n              <select data-ml1=\"countryEU\">\n                <optgroup label=\"UE\/EEE\">\n                  <option value=\"ES\" selected>Espa\u00f1a<\/option><option value=\"PT\">Portugal<\/option><option value=\"FR\">Francia<\/option><option value=\"IT\">Italia<\/option><option value=\"DE\">Alemania<\/option>\n                  <option value=\"NL\">Pa\u00edses Bajos<\/option><option value=\"BE\">B\u00e9lgica<\/option><option value=\"LU\">Luxemburgo<\/option><option value=\"AT\">Austria<\/option><option value=\"IE\">Irlanda<\/option>\n                  <option value=\"DK\">Dinamarca<\/option><option value=\"SE\">Suecia<\/option><option value=\"FI\">Finlandia<\/option><option value=\"PL\">Polonia<\/option><option value=\"CZ\">Chequia<\/option>\n                  <option value=\"SK\">Eslovaquia<\/option><option value=\"HU\">Hungr\u00eda<\/option><option value=\"RO\">Ruman\u00eda<\/option><option value=\"BG\">Bulgaria<\/option><option value=\"GR\">Grecia<\/option>\n                  <option value=\"HR\">Croacia<\/option><option value=\"SI\">Eslovenia<\/option><option value=\"EE\">Estonia<\/option><option value=\"LV\">Letonia<\/option><option value=\"LT\">Lituania<\/option>\n                  <option value=\"MT\">Malta<\/option><option value=\"CY\">Chipre<\/option>\n                <\/optgroup>\n                <optgroup label=\"Otros europeos\">\n                  <option value=\"UK\">Reino Unido<\/option><option value=\"CH\">Suiza<\/option><option value=\"NO\">Noruega<\/option><option value=\"IS\">Islandia<\/option><option value=\"AD\">Andorra<\/option>\n                <\/optgroup>\n              <\/select>\n              <div class=\"hint\">Selecciona tu pa\u00eds para ajustar la referencia de tallas.<\/div>\n            <\/div>\n\n            <!-- Acciones -->\n            <div class=\"col-12 actions\">\n              <button class=\"btn primary\" type=\"submit\" data-ml1=\"btnCalc\">Calcular<\/button>\n              <button class=\"btn\" type=\"button\" data-ml1=\"btnReset\">Reset<\/button>\n            <\/div>\n          <\/div>\n        <\/div>\n      <\/form>\n\n      <!-- RESULTADOS -->\n      <div class=\"result\">\n        <h2>Resultado<\/h2>\n        <div class=\"notice\" data-ml1=\"notice\">Selecciona grupo e introduce medidas.<\/div>\n        <table class=\"table\" data-ml1=\"table\" style=\"display:none\">\n          <thead><tr><th>Sistema<\/th><th>Talla<\/th><th>Rango<\/th><\/tr><\/thead>\n          <tbody data-ml1=\"tbody\"><\/tbody>\n        <\/table>\n      <\/div>\n\n      <footer>\n        <p class=\"hint\">Prototipo MorningLabs \u00b7 EN 13402 \u00b7 EU-aware<\/p>\n      <\/footer>\n    <\/div>\n  <\/div>\n\n  <script>\n  (function(){\n    const root = document.getElementById('ml-individual');\n    const $  = sel => root.querySelector(sel);\n\n    \/* ===== Config ===== *\/\n    const PLACEHOLDER =\n      'data:image\/svg+xml;utf8,<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"640\" height=\"420\"><rect width=\"100%\" height=\"100%\" fill=\"white\" stroke=\"black\"\/><text x=\"50%\" y=\"50%\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-size=\"18\">No se pudo cargar la imagen<\/text><\/svg>';\n    const SHEET_ID = 'TU_NUEVO_SHEET_ID_AQUI'; \/\/ opcional; si falta, usa tablas base\n\n    \/* ===== Helpers ===== *\/\n    const isInches = ()=> $('[data-ml1=\"btn-in\"]').classList.contains('active');\n    const toCm     = v => isInches()? v*2.54 : v;\n    const between  = (x,[a,b]) => x>=a&&x<=b;\n    const range = (s)=>{ if(!s) return null; const m=String(s).replace(\/\\s\/g,'').replace(\/\u2013\/g,'-').match(\/^(\\d+(?:[.,]\\d+)?)\\-(\\d+(?:[.,]\\d+)?)\/); if(!m) return null; const n=x=>Number(String(x).replace(',','.')); return [n(m[1]),n(m[2])]; };\n    const strip=s=>String(s||'').normalize('NFD').replace(\/[\\u0300-\\u036f]\/g,'').toLowerCase().replace(\/\\s+\/g,'');\n\n    function numInput(el){ const s=(el.value||'').replace(',','.'); const n=parseFloat(s); return Number.isFinite(n)?n:NaN; }\n    function parseCm(el){ const v=numInput(el); return Number.isFinite(v)? toCm(v) : NaN; }\n\n    \/* ===== Tablas base ===== *\/\n    const SIZE_TABLES_BASE={\n      mujer:{\n        top:[[\"XXS\",\"\",\"\",\"76-80\"],[\"XS\",\"0-2\",\"4-6\",\"80-84\"],[\"S\",\"4-6\",\"8-10\",\"84-88\"],[\"M\",\"8-10\",\"12-14\",\"88-96\"],[\"L\",\"12-14\",\"16-18\",\"96-104\"],[\"XL\",\"16-18\",\"20-22\",\"104-112\"],[\"XXL\",\"20-22\",\"24-26\",\"112-120\"],[\"3XL\",\"24-26\",\"28-30\",\"120-128\"]]\n          .map(r=>({eu:r[0],us:r[1],uk:r[2],bust:range(r[3])})),\n        bottom:[[32,0,4,\"66-70\",\"82-86\"],[34,2,6,\"70-74\",\"86-90\"],[36,4,8,\"74-78\",\"90-94\"],[38,6,10,\"78-82\",\"94-98\"],[40,8,12,\"82-86\",\"98-102\"],[42,10,14,\"86-90\",\"102-106\"],[44,12,16,\"90-94\",\"106-110\"],[46,14,18,\"94-98\",\"110-114\"],[48,16,20,\"98-102\",\"114-118\"]]\n          .map(r=>({eu:r[0],us:r[1],uk:r[2],waist:range(r[3]),hip:range(r[4])})),\n        coats:null\n      },\n      hombre:{\n        top:[[\"S\",36,36,\"\",\"92-96\"],[\"M\",38,38,\"\",\"96-100\"],[\"L\",40,40,\"\",\"100-104\"],[\"XL\",42,42,\"\",\"104-108\"],[\"XXL\",44,44,\"\",\"108-112\"],[\"3XL\",46,46,\"\",\"112-116\"],[\"4XL\",48,48,\"\",\"116-120\"]]\n          .map(r=>({eu:r[0],us:r[1],uk:r[2],chest:range(r[4])})),\n        bottom:[[42,26,26,\"70-74\",\"88-92\"],[44,28,28,\"74-78\",\"92-96\"],[46,30,30,\"78-82\",\"96-100\"],[48,32,32,\"82-86\",\"100-104\"],[50,34,34,\"86-90\",\"104-108\"],[52,36,36,\"90-94\",\"108-112\"],[54,38,38,\"94-98\",\"112-116\"],[56,40,40,\"98-102\",\"116-120\"],[58,42,42,\"102-106\",\"120-124\"],[60,44,44,\"106-110\",\"124-128\"]]\n          .map(r=>({eu:r[0],us:r[1],uk:r[2],waist:range(r[3]),hip:range(r[4])})),\n        coats:null\n      },\n      nino:{general:[\"98-102\",\"104-108\",\"108-112\",\"114-118\",\"120-124\",\"126-130\",\"132-136\",\"140-144\",\"146-150\",\"152-156\",\"158-162\",\"164-168\",\"170-176\"].map(h=>({height:range(h),eu:h}))},\n      nina:{general:[\"98-102\",\"104-108\",\"108-112\",\"114-118\",\"120-124\",\"126-130\",\"132-136\",\"140-144\",\"146-150\",\"152-156\",\"158-162\",\"164-168\",\"170-176\"].map(h=>({height:range(h),eu:h}))}\n    };\n\n    \/* ===== Google Sheets opcional ===== *\/\n    const SHEET_GROUPS_BASE=[\n      {base:'Mujer_Tops',    person:'mujer',  key:'top'},\n      {base:'Mujer_Bottom',  person:'mujer',  key:'bottom'},\n      {base:'Mujer_Abrigos', person:'mujer',  key:'coats'},\n      {base:'Hombre_Tops',   person:'hombre', key:'top'},\n      {base:'Hombre_Bottom', person:'hombre', key:'bottom'},\n      {base:'Hombre_Abrigos',person:'hombre', key:'coats'},\n      {base:'Ni\u00f1as',         person:'nina',   key:'general'},\n      {base:'Ni\u00f1os',         person:'nino',   key:'general'}\n    ];\n    const SIZE_TABLES={mujer:{},hombre:{},nina:{},nino:{}};\n    const currentCountrySuffix=()=> ($('[data-ml1=\"countryEU\"]').value || 'ES').toUpperCase();\n\n    async function fetchCSV(sheet){\n      const url=`https:\/\/docs.google.com\/spreadsheets\/d\/${SHEET_ID}\/gviz\/tq?tqx=out:csv&sheet=${encodeURIComponent(sheet)}`;\n      const r=await fetch(url,{cache:'no-store'}); if(!r.ok) throw new Error('Fetch fail '+sheet); return r.text();\n    }\n    function csvToRows(text){\n      const lines = text.replace(\/\\r\/g,'').split('\\n').filter(l=>l.trim());\n      return lines.map(line=>{\n        const out=[]; let cur='', q=false;\n        for (const ch of line) {\n          if (ch === '\"') { q = !q; continue; }\n          if (ch === ',' && !q) { out.push(cur); cur=''; }\n          else { cur += ch; }\n        }\n        out.push(cur);\n        return out.map(s=>s.trim());\n      });\n    }\n    function idx(h,keys){ const H=h.map(strip); for(const k of keys){ const i=H.findIndex(x=>x.includes(k)); if(i>-1) return i; } return -1; }\n    function mapTop(rows){\n      const h=rows[0]; const iEU=idx(h,['eu']), iUS=idx(h,['us']), iUK=idx(h,['uk']);\n      const iBust=idx(h,['busto','bust']), iChest=idx(h,['pecho','chest']), iWaist=idx(h,['cintura','waist']), iHip=idx(h,['cadera','hip']);\n      return rows.slice(1).filter(r=>r.some(Boolean)).map(r=>({\n        eu:r[iEU],us:r[iUS],uk:r[iUK],\n        bust:range(r[iBust])||null, chest:range(r[iChest])||null,\n        waist:range(r[iWaist])||null, hip:range(r[iHip])||null\n      }));\n    }\n    function mapBottom(rows){\n      const h=rows[0]; const iEU=idx(h,['eu']), iUS=idx(h,['us']), iUK=idx(h,['uk']);\n      const iWaist=idx(h,['cintura','waist']), iHip=idx(h,['cadera','hip']);\n      return rows.slice(1).filter(r=>r.some(Boolean)).map(r=>({\n        eu:r[iEU],us:r[iUS],uk:r[iUK],\n        waist:range(r[iWaist])||null, hip:range(r[iHip])||null\n      }));\n    }\n    function mapKids(rows){\n      const h=rows[0]; const iH=idx(h,['altura','height']);\n      return rows.slice(1).filter(r=>r.some(Boolean)).map(r=>({eu:r[iH], height:range(r[iH])||null}));\n    }\n\n    async function loadAll(){\n      const btn=$('[data-ml1=\"btnCalc\"]'); if(btn) btn.disabled=true;\n      const suffix = currentCountrySuffix();\n      show(`Cargando tablas (pa\u00eds: ${suffix})\u2026`);\n      SIZE_TABLES.mujer = {}; SIZE_TABLES.hombre = {}; SIZE_TABLES.nina = {}; SIZE_TABLES.nino = {};\n      if(!SHEET_ID || SHEET_ID.includes('TU_NUEVO_SHEET_ID_AQUI')){\n        show('Usando tablas base locales.');\n        if(btn) btn.disabled=false; return;\n      }\n      try{\n        for(const g of SHEET_GROUPS_BASE){\n          let ok=false, csv, used=null;\n          const candidates = [`${g.base}_${suffix}`,`${g.base} (${suffix})`,g.base,`${g.base} (1)`];\n          for(const name of candidates){\n            try{ csv=await fetchCSV(name); used=name; ok=true; break; }catch(e){}\n          }\n          if(!ok) continue;\n          const rows=csvToRows(csv);\n          const mapped = g.key==='bottom' ? mapBottom(rows) : (g.key==='general' ? mapKids(rows) : mapTop(rows));\n          SIZE_TABLES[g.person] ??= {};\n          SIZE_TABLES[g.person][g.key]=mapped;\n          (SIZE_TABLES[g.person]._sources ??= {})[g.key]=used;\n        }\n        show(`Tablas cargadas (${suffix}). Introduce medidas y calcula.`);\n      }catch(e){\n        console.error(e);\n        show('No se pudieron cargar las tablas. Usar\u00e9 la tabla base local.');\n      }\n      if(btn) btn.disabled=false;\n    }\n\n    \/* ===== UI ===== *\/\n    function show(msg){ $('[data-ml1=\"table\"]').style.display='none'; const n=$('[data-ml1=\"notice\"]'); n.textContent=msg; n.style.display=''; }\n    function render(rows){\n      const tb=$('[data-ml1=\"tbody\"]'); tb.innerHTML='';\n      rows.forEach(r=>{ const tr=document.createElement('tr'); tr.innerHTML=`<td><span class='pill'>${r.system}<\/span><\/td><td>${r.size}<\/td><td>${r.range}<\/td>`;tb.appendChild(tr); });\n      $('[data-ml1=\"notice\"]').style.display='none';\n      $('[data-ml1=\"table\"]').style.display='';\n    }\n\n    function updatePreviewFromSelection(){\n      const sel = $('[data-ml1=\"garment\"]');\n      const opt = sel.options[sel.selectedIndex];\n      const imgUrl = opt?.dataset?.image || '';\n      const title = opt?.text || 'Prenda';\n      const prev = $('[data-ml1=\"preview\"]');\n      const label = $('[data-ml1=\"previewTitle\"]');\n      if (label) label.textContent = title;\n      if (prev) {\n        prev.onerror = ()=>{ prev.src = PLACEHOLDER; };\n        if (imgUrl) prev.src = imgUrl;\n      }\n    }\n\n    function setUnit(u){\n      const cm=(u==='cm');\n      $('[data-ml1=\"btn-cm\"]').classList.toggle('active',cm);\n      $('[data-ml1=\"btn-in\"]').classList.toggle('active',!cm);\n      const ph=cm?['92,0','74,0','98,0','170,0']:['36.2','29.1','38.6','66.9'];\n      [['busto','u-busto'],['cintura','u-cintura'],['cadera','u-cadera'],['altura','u-altura']]\n        .forEach(([inp,label],i)=>{\n          const el=$(`[data-ml1=\"${inp}\"]`);\n          const lb=$(`[data-ml1=\"${label}\"]`);\n          if(el) el.placeholder=ph[i];\n          if(lb) lb.textContent=cm?'(cm)':'(in)';\n        });\n    }\n\n    function toggleInputs(){\n      const persona = $('[data-ml1=\"persona\"]').value || 'hombre';\n      const garment = $('[data-ml1=\"garment\"]').value || 'top';\n      const show = key => { const el=$(`[data-ml1=\"${key}\"]`)?.closest('[data-ml1^=\"grp-\"]') || $(`[data-ml1=\"${key}\"]`); if(el) el.style.display=''; };\n      const hide = key => {\n        const el=$(`[data-ml1=\"${key}\"]`)?.closest('[data-ml1^=\"grp-\"]') || $(`[data-ml1=\"${key}\"]`);\n        if(el){ el.style.display='none'; const input=el.querySelector('input'); if(input) input.value=''; }\n      };\n\n      \/\/ default: mostrar todo\n      show('grp-busto'); show('grp-cintura'); show('grp-cadera'); show('grp-altura');\n\n      if (persona === 'nino' || persona === 'nina') {\n        hide('grp-busto'); hide('grp-cintura'); hide('grp-cadera'); show('grp-altura');\n      } else if (garment === 'bottom') {\n        hide('grp-busto'); show('grp-cintura'); show('grp-cadera'); hide('grp-altura');\n      } else {\n        show('grp-busto'); hide('grp-cintura'); hide('grp-cadera'); hide('grp-altura');\n      }\n    }\n\n    function calc(ev){\n      if(ev) ev.preventDefault();\n      const persona=$('[data-ml1=\"persona\"]').value||'hombre';\n      const garment=$('[data-ml1=\"garment\"]').value;\n\n      const bust=parseCm($('[data-ml1=\"busto\"]'));\n      const waist=parseCm($('[data-ml1=\"cintura\"]'));\n      const hip=parseCm($('[data-ml1=\"cadera\"]'));\n      const height=parseCm($('[data-ml1=\"altura\"]'));\n\n      const loaded=SIZE_TABLES[persona];\n      const tables=(loaded && Object.keys(loaded).length)? loaded : SIZE_TABLES_BASE[persona];\n      if(!tables) return show('No hay tablas para ese grupo.');\n\n      let rows,key,val,groupKey;\n      if(persona==='nino'||persona==='nina'){ rows=tables.general; key='height'; val=height; groupKey='general'; }\n      else if(garment==='bottom'){ rows=tables.bottom; key=(rows?.[0]?.hip?'hip':'waist'); val=(key==='hip'?hip:waist); groupKey='bottom'; }\n      else if(garment==='jacket'){ rows=tables.coats || tables.top; key=(rows?.[0]?.bust?'bust':'chest'); val=bust; groupKey=tables.coats?'coats':'top'; }\n      else { rows=tables.top; key=(rows?.[0]?.bust?'bust':'chest'); val=bust; groupKey='top'; }\n\n      if(!Array.isArray(rows) || !rows.length) return show('No hay datos para esa prenda.');\n      if(!Number.isFinite(val)) return show('Introduce la medida principal para esta prenda.');\n\n      const hit=rows.find(r=> r[key] && between(val,r[key]));\n      if(!hit) return show('No se encontr\u00f3 una talla para esa medida.');\n\n      const src = (loaded && loaded._sources && loaded._sources[groupKey]) ? ` \u00b7 Fuente: ${loaded._sources[groupKey]}` : '';\n      render([\n        {system:'EU', size: hit.eu ?? '\u2014', range:`${key}: ${hit[key][0]}\u2013${hit[key][1]} cm${src}`},\n        {system:'US', size: hit.us ?? '\u2014', range:`${key}: ${hit[key][0]}\u2013${hit[key][1]} cm${src}`},\n        {system:'UK', size: hit.uk ?? '\u2014', range:`${key}: ${hit[key][0]}\u2013${hit[key][1]} cm${src}`}\n      ]);\n    }\n\n    function addInputSanitizers(){\n      ['busto','cintura','cadera','altura'].forEach(name=>{\n        const el = $(`[data-ml1=\"${name}\"]`);\n        if (el && !el._san_) {\n          el.addEventListener('input', e=>{\n            e.target.value = e.target.value.replace(\/[^0-9\\.,]\/g,'');\n          });\n          el._san_ = true;\n        }\n      });\n    }\n\n    function resetForm(){\n      $('[data-ml1=\"form\"]').reset();\n      setUnit('cm');\n      updatePreviewFromSelection();\n      toggleInputs();\n      show('Selecciona grupo e introduce medidas.');\n      loadAll();\n    }\n\n    \/\/ Eventos\n    $('[data-ml1=\"btn-cm\"]').addEventListener('click', ()=>setUnit('cm'));\n    $('[data-ml1=\"btn-in\"]').addEventListener('click', ()=>setUnit('in'));\n    $('[data-ml1=\"garment\"]').addEventListener('change', ()=>{ toggleInputs(); updatePreviewFromSelection(); });\n    $('[data-ml1=\"persona\"]').addEventListener('change', ()=>{ toggleInputs(); updatePreviewFromSelection(); });\n    $('[data-ml1=\"countryEU\"]').addEventListener('change', loadAll);\n    $('[data-ml1=\"btnReset\"]').addEventListener('click', resetForm);\n    $('[data-ml1=\"form\"]').addEventListener('submit', calc);\n\n    \/\/ Init\n    setUnit('cm');\n    addInputSanitizers();\n    toggleInputs();\n    updatePreviewFromSelection();\n    loadAll();\n  })();\n  <\/script>\n<\/section>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div id=\"e-n-tab-content-1056133302\" role=\"tabpanel\" aria-labelledby=\"e-n-tab-title-1056133302\" data-tab-index=\"2\" style=\"--n-tabs-title-order: 2;\" class=\" elementor-element elementor-element-34a79a3 e-con-full e-flex e-con e-child\" data-id=\"34a79a3\" data-element_type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-3793a45 elementor-widget elementor-widget-html\" data-id=\"3793a45\" data-element_type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<!-- ===== Calculadora de tallas \u2014 Modo masivo (aislada v2) ===== -->\n<section id=\"ml-masivo\" aria-label=\"Calculadora masiva de tallas\">\n  <style>\n    \/* Scope total *\/\n    #ml-masivo{--black:#000;--white:#fff;--gray:#555;--light:#f2f2f2;font-family:Arial,Helvetica,sans-serif;color:var(--black)}\n    #ml-masivo .wrap{max-width:1080px;margin:12px auto;padding:24px}\n    #ml-masivo .card{background:#fff;border:1px solid var(--black);border-radius:10px;box-shadow:0 2px 6px rgba(0,0,0,.08)}\n    #ml-masivo header{padding:18px 22px;border-bottom:1px solid var(--black);display:flex;justify-content:space-between;align-items:center}\n    #ml-masivo header h1{font-size:30px;margin:0}\n    #ml-masivo header small{color:var(--gray)}\n\n    \/* Grid principal: dos columnas *\/\n    #ml-masivo .grid{display:grid;gap:22px;padding:24px;grid-template-columns:1fr 1fr}\n    #ml-masivo .col{min-width:0}\n\n    \/* Paneles y tabla *\/\n    #ml-masivo .notice{background:var(--light);padding:12px;border:1px dashed var(--black);border-radius:8px;color:#000}\n    #ml-masivo .table{width:100%;border-collapse:collapse;border:1px solid var(--black)}\n    #ml-masivo .table th,#ml-masivo .table td{padding:12px;border:1px solid var(--black);text-align:center;font-weight:bold;font-size:14px}\n\n    \/* Botones *\/\n    #ml-masivo .actions{display:flex;gap:14px;flex-wrap:wrap;align-items:center}\n    #ml-masivo .btn{border:1px solid var(--black);background:#fff;color:#000;padding:12px 18px;border-radius:8px;cursor:pointer;font-size:16px;font-weight:bold;transition:all .15s}\n    #ml-masivo .btn.primary{background:#000;color:#fff}\n    \/* Hover amarillo *\/\n    #ml-masivo .btn:hover,#ml-masivo .btn.primary:hover{background:#ffd400;color:#000;border-color:#000}\n    #ml-masivo .btn:active{filter:brightness(.95)}\n    #ml-masivo .btn:disabled{opacity:.5;cursor:not-allowed}\n    #ml-masivo .btn:focus-visible{outline:2px solid #000;outline-offset:2px}\n\n    \/* Campos *\/\n    #ml-masivo label{display:block;margin:0 0 8px 2px;font-size:14px;font-weight:700}\n    #ml-masivo input[type=\"file\"]{display:block;width:100%;padding:12px 10px;border:1px solid #000;border-radius:8px;background:#fff;color:#000;font-size:14px}\n    #ml-masivo .hint{font-size:12px;color:var(--gray)}\n\n    \/* Vista previa tabla *\/\n    #ml-masivo [data-ml=\"previewWrap\"]{display:none}\n\n    \/* Responsive *\/\n    @media (max-width:960px){\n      #ml-masivo .grid{grid-template-columns:1fr;gap:18px;padding:18px}\n    }\n  <\/style>\n\n  <div class=\"wrap\">\n    <div class=\"card\">\n      <header>\n        <div>\n          <h1>Calculadora de tallas \u2014 modo masivo<\/h1>\n          <small>EN 13402 \/ UNE-ISO 8559 \u00b7 Prototipo UE<\/small>\n        <\/div>\n      <\/header>\n\n      <section class=\"grid\">\n        <!-- Izquierda: instrucciones + descarga -->\n        <div class=\"col\">\n          <div class=\"notice\" style=\"margin-bottom:16px\">\n            <strong>\u00bfC\u00f3mo funciona?<\/strong>\n            <ul style=\"margin:8px 0 0 18px\">\n              <li>Descarga la plantilla (.csv) con las columnas necesarias.<\/li>\n              <li>Rellena las filas con tus datos (persona, prenda y medidas).<\/li>\n              <li>Sube el archivo y pulsa \u201cConvertir Excel\u201d.<\/li>\n              <li>Descarga el .csv con las tallas calculadas.<\/li>\n            <\/ul>\n          <\/div>\n\n          <button class=\"btn\" data-ml=\"btnTemplate\" type=\"button\">Descargar plantilla<\/button>\n          <div class=\"hint\" style=\"margin-top:6px\">\n            Esta es la plantilla para que puedas descargar y ajustar los datos antes de subirlos aqu\u00ed.\n          <\/div>\n        <\/div>\n\n        <!-- Derecha: subida\/convertir\/descargar -->\n        <div class=\"col\">\n          <div style=\"margin-bottom:12px\">\n            <label>Subir Excel o CSV<\/label>\n            <input data-ml=\"file\" type=\"file\" accept=\".xlsx,.xls,.csv\"\/>\n            <div class=\"hint\" style=\"margin-top:6px\">\n              Formatos aceptados: .xlsx (carga SheetJS en la p\u00e1gina) o .csv (funciona sin librer\u00eda).\n            <\/div>\n          <\/div>\n\n          <div class=\"actions\" style=\"margin:10px 0 16px\">\n            <button class=\"btn primary\" data-ml=\"btnConvert\" type=\"button\">Convertir Excel<\/button>\n            <button class=\"btn\" data-ml=\"btnDownload\" type=\"button\" disabled>Descargar resultados<\/button>\n          <\/div>\n\n          <div class=\"notice\" data-ml=\"status\">Sin archivo cargado.<\/div>\n\n          <div data-ml=\"previewWrap\" style=\"margin-top:16px\">\n            <h3 style=\"margin:0 0 8px 0;font-size:18px\">Vista previa (primeras filas)<\/h3>\n            <table class=\"table\">\n              <thead><tr data-ml=\"previewHead\"><\/tr><\/thead>\n              <tbody data-ml=\"previewBody\"><\/tbody>\n            <\/table>\n          <\/div>\n        <\/div>\n      <\/section>\n    <\/div>\n  <\/div>\n\n  <script>\n  (function(){\n    const root = document.getElementById('ml-masivo');\n    const $ = s => root.querySelector(s);\n    const el = {\n      btnTemplate: $('[data-ml=\"btnTemplate\"]'),\n      file:        $('[data-ml=\"file\"]'),\n      btnConvert:  $('[data-ml=\"btnConvert\"]'),\n      btnDownload: $('[data-ml=\"btnDownload\"]'),\n      status:      $('[data-ml=\"status\"]'),\n      previewWrap: $('[data-ml=\"previewWrap\"]'),\n      previewHead: $('[data-ml=\"previewHead\"]'),\n      previewBody: $('[data-ml=\"previewBody\"]'),\n    };\n\n    \/\/ CSV plantilla\n    const TEMPLATE_HEADERS = ['persona','prenda','busto_pecho_cm','cintura_cm','cadera_cm','altura_cm','pais'];\n    function downloadTemplate(){\n      const rows=[TEMPLATE_HEADERS.join(',')];\n      rows.push('mujer,top,92,,, ,ES');\n      rows.push('hombre,bottom,,86,102,,ES');\n      rows.push('nina,top,,,,140,ES');\n      const blob=new Blob([rows.join('\\\\n')],{type:'text\/csv;charset=utf-8;'});\n      const a=document.createElement('a'); a.href=URL.createObjectURL(blob); a.download='plantilla_calculo_masivo.csv';\n      document.body.appendChild(a); a.click(); document.body.removeChild(a);\n    }\n\n    \/\/ Utils\n    const strip = s => String(s||'').normalize('NFD').replace(\/[\\\\u0300-\\\\u036f]\/g,'').toLowerCase().trim();\n    const num = v => { const s=String(v??'').replace(',','.').replace(\/[^0-9.\\\\-]\/g,''); const n=parseFloat(s); return Number.isFinite(n)?n:NaN; };\n    const range = s => { if(!s) return null; const m=String(s).replace(\/\\\\s\/g,'').replace(\/\u2013\/g,'-').match(\/^(\\\\d+(?:[.,]\\\\d+)?)\\\\-(\\\\d+(?:[.,]\\\\d+)?)\/); if(!m) return null; const n2=x=>Number(String(x).replace(',','.')); return [n2(m[1]),n2(m[2])]; };\n    const between=(x,[a,b])=>Number.isFinite(x)&&x>=a&&x<=b;\n\n    \/\/ Tablas base\n    const SIZE_TABLES_BASE={\n      mujer:{\n        top:[[\"XXS\",\"\",\"\",\"76-80\"],[\"XS\",\"0-2\",\"4-6\",\"80-84\"],[\"S\",\"4-6\",\"8-10\",\"84-88\"],[\"M\",\"8-10\",\"12-14\",\"88-96\"],[\"L\",\"12-14\",\"16-18\",\"96-104\"],[\"XL\",\"16-18\",\"20-22\",\"104-112\"],[\"XXL\",\"20-22\",\"24-26\",\"112-120\"],[\"3XL\",\"24-26\",\"28-30\",\"120-128\"]]\n          .map(r=>({eu:r[0],us:r[1],uk:r[2],bust:range(r[3])})),\n        bottom:[[32,0,4,\"66-70\",\"82-86\"],[34,2,6,\"70-74\",\"86-90\"],[36,4,8,\"74-78\",\"90-94\"],[38,6,10,\"78-82\",\"94-98\"],[40,8,12,\"82-86\",\"98-102\"],[42,10,14,\"86-90\",\"102-106\"],[44,12,16,\"90-94\",\"106-110\"],[46,14,18,\"94-98\",\"110-114\"],[48,16,20,\"98-102\",\"114-118\"]]\n          .map(r=>({eu:r[0],us:r[1],uk:r[2],waist:range(r[3]),hip:range(r[4])})),\n        coats:null\n      },\n      hombre:{\n        top:[[\"S\",36,36,\"\",\"92-96\"],[\"M\",38,38,\"\",\"96-100\"],[\"L\",40,40,\"\",\"100-104\"],[\"XL\",42,42,\"\",\"104-108\"],[\"XXL\",44,44,\"\",\"108-112\"],[\"3XL\",46,46,\"\",\"112-116\"],[\"4XL\",48,48,\"\",\"116-120\"]]\n          .map(r=>({eu:r[0],us:r[1],uk:r[2],chest:range(r[4])})),\n        bottom:[[42,26,26,\"70-74\",\"88-92\"],[44,28,28,\"74-78\",\"92-96\"],[46,30,30,\"78-82\",\"96-100\"],[48,32,32,\"82-86\",\"100-104\"],[50,34,34,\"86-90\",\"104-108\"],[52,36,36,\"90-94\",\"108-112\"],[54,38,38,\"94-98\",\"112-116\"],[56,40,40,\"98-102\",\"116-120\"],[58,42,42,\"102-106\",\"120-124\"],[60,44,44,\"106-110\",\"124-128\"]]\n          .map(r=>({eu:r[0],us:r[1],uk:r[2],waist:range(r[3]),hip:range(r[4])})),\n        coats:null\n      },\n      nino:{general:[\"98-102\",\"104-108\",\"108-112\",\"114-118\",\"120-124\",\"126-130\",\"132-136\",\"140-144\",\"146-150\",\"152-156\",\"158-162\",\"164-168\",\"170-176\"].map(h=>({height:range(h),eu:h}))},\n      nina:{general:[\"98-102\",\"104-108\",\"108-112\",\"114-118\",\"120-124\",\"126-130\",\"132-136\",\"140-144\",\"146-150\",\"152-156\",\"158-162\",\"164-168\",\"170-176\"].map(h=>({height:range(h),eu:h}))}\n    };\n\n    \/\/ Parse CSV simple\n    function parseCSV(text){\n      const lines = text.replace(\/\\\\r\/g,'').split('\\\\n').filter(l=>l.trim());\n      const out=[]; for(const line of lines){\n        const row=[]; let cur=''; let q=false;\n        for(const ch of line){\n          if(ch==='\"'){ q=!q; continue; }\n          if(ch===',' && !q){ row.push(cur); cur=''; } else { cur+=ch; }\n        }\n        row.push(cur); out.push(row.map(s=>s.trim()));\n      }\n      return out;\n    }\n    function normalizeHeaderMap(header){\n      const h = header.map(x=>strip(x));\n      const idx = ks => { for(const k of ks){ const i=h.findIndex(x=>x===k||x.includes(k)); if(i>-1) return i; } return -1; };\n      return {\n        persona: idx(['persona']),\n        prenda:  idx(['prenda','garment','tipo']),\n        busto:   idx(['busto_pecho_cm','busto','pecho','chest']),\n        cintura: idx(['cintura_cm','cintura','waist']),\n        cadera:  idx(['cadera_cm','cadera','hip']),\n        altura:  idx(['altura_cm','altura','height']),\n        pais:    idx(['pais','country'])\n      };\n    }\n    function rowsFromMatrix(mat){\n      if (!mat.length) return [];\n      const map = normalizeHeaderMap(mat[0]);\n      const rows=[];\n      for(const r of mat.slice(1)){\n        if(!r || r.every(c=>!String(c||'').trim())) continue;\n        rows.push({\n          persona:(r[map.persona]||'').toString().trim().toLowerCase(),\n          prenda:(r[map.prenda]||'').toString().trim().toLowerCase(),\n          busto:num(r[map.busto]),\n          cintura:num(r[map.cintura]),\n          cadera:num(r[map.cadera]),\n          altura:num(r[map.altura]),\n          pais:(r[map.pais]||'ES').toString().trim().toUpperCase()\n        });\n      }\n      return rows;\n    }\n\n    \/\/ C\u00e1lculo por fila\n    function calcForRow(r){\n      const p = ['mujer','hombre','nino','ni\u00f1o','nina','ni\u00f1a'].includes(r.persona) ? r.persona : 'hombre';\n      const personaKey = (p==='ni\u00f1o')?'nino':(p==='ni\u00f1a'?'nina':p);\n      const g = ['top','bottom','jacket'].includes(r.prenda) ? r.prenda : 'top';\n\n      const t = SIZE_TABLES_BASE[personaKey];\n      let rows,key,val;\n      if(personaKey==='nino'||personaKey==='nina'){ rows=t.general; key='height'; val=r.altura; }\n      else if(g==='bottom'){ rows=t.bottom; key=(rows?.[0]?.hip?'hip':'waist'); val=(key==='hip'?r.cadera:r.cintura); }\n      else if(g==='jacket'){ rows=t.coats||t.top; key=(rows?.[0]?.bust?'bust':'chest'); val=r.busto; }\n      else { rows=t.top; key=(rows?.[0]?.bust?'bust':'chest'); val=r.busto; }\n\n      let eu='\u2014',us='\u2014',uk='\u2014',rango='\u2014',nota='';\n      if(Array.isArray(rows)&&rows.length&&Number.isFinite(val)){\n        const hit=rows.find(x=>x[key]&&between(val,x[key]));\n        if(hit){ eu=hit.eu??'\u2014'; us=hit.us??'\u2014'; uk=hit.uk??'\u2014'; rango=hit[key]?`${key}: ${hit[key][0]}\u2013${hit[key][1]} cm`:'\u2014'; }\n        else { nota='Sin coincidencia en tabla base'; }\n      } else { nota='Faltan datos de medida principal'; }\n\n      return {\n        persona: personaKey, prenda: g,\n        busto_pecho_cm: Number.isFinite(r.busto)? r.busto : '',\n        cintura_cm:     Number.isFinite(r.cintura)? r.cintura : '',\n        cadera_cm:      Number.isFinite(r.cadera)? r.cadera : '',\n        altura_cm:      Number.isFinite(r.altura)? r.altura : '',\n        pais: r.pais || 'ES',\n        talla_EU: eu, talla_US: us, talla_UK: uk,\n        rango_ref: rango, nota\n      };\n    }\n\n    \/\/ Render preview\n    function renderPreview(rows){\n      el.previewHead.innerHTML=''; el.previewBody.innerHTML='';\n      if(!rows.length){ el.previewWrap.style.display='none'; return; }\n      const cols = Object.keys(rows[0]);\n      cols.forEach(c=>{ const th=document.createElement('th'); th.textContent=c; el.previewHead.appendChild(th); });\n      rows.forEach(r=>{ const tr=document.createElement('tr'); cols.forEach(c=>{ const td=document.createElement('td'); td.textContent=r[c]??''; tr.appendChild(td); }); el.previewBody.appendChild(tr); });\n      el.previewWrap.style.display='';\n    }\n\n    \/\/ Descargar resultados\n    function downloadResults(rows){\n      if(!rows.length) return;\n      const cols = Object.keys(rows[0]);\n      const esc = v => { const s=String(v??''); return (\/[\",\\\\n]\/.test(s))?'\"'+s.replace(\/\"\/g,'\"\"')+'\"':s; };\n      const lines=[cols.join(',')].concat(rows.map(r=>cols.map(c=>esc(r[c])).join(',')));\n      const blob=new Blob([lines.join('\\\\n')],{type:'text\/csv;charset=utf-8;'});\n      const a=document.createElement('a'); a.href=URL.createObjectURL(blob); a.download='resultados_calculo_masivo.csv';\n      document.body.appendChild(a); a.click(); document.body.removeChild(a);\n    }\n\n    \/\/ Estado\n    let parsedInput=[]; let computedRows=[];\n\n    \/\/ Eventos\n    el.btnTemplate.addEventListener('click', downloadTemplate);\n    el.file.addEventListener('change', ()=> el.status.textContent='Archivo seleccionado. Pulsa \u201cConvertir Excel\u201d.');\n    el.btnConvert.addEventListener('click', async ()=>{\n      const file = el.file.files[0];\n      if(!file){ el.status.textContent='Selecciona un archivo primero.'; return; }\n      el.status.textContent='Leyendo archivo\u2026';\n      try{\n        \/\/ CSV directo\n        if(file.name.toLowerCase().endsWith('.csv')){\n          const text = await file.text();\n          parsedInput = rowsFromMatrix(parseCSV(text));\n        }else{\n          if(typeof XLSX==='undefined'){ el.status.textContent='Para .xlsx, carga SheetJS o sube .csv.'; return; }\n          const buf = await file.arrayBuffer();\n          const wb = XLSX.read(buf,{type:'array'});\n          const ws = wb.Sheets[wb.SheetNames[0]];\n          const mat = XLSX.utils.sheet_to_json(ws,{header:1,defval:''});\n          parsedInput = rowsFromMatrix(mat);\n        }\n        if(!parsedInput.length){ el.status.textContent='No se encontraron filas v\u00e1lidas.'; return; }\n        el.status.textContent=`Archivo le\u00eddo: ${parsedInput.length} fila(s). Calculando\u2026`;\n        computedRows = parsedInput.map(calcForRow);\n        renderPreview(computedRows.slice(0,20));\n        el.btnDownload.disabled = computedRows.length===0;\n        el.status.textContent=`Listo. Filas calculadas: ${computedRows.length}.`;\n      }catch(e){\n        console.error(e); el.status.textContent='No se pudo procesar el archivo. Revisa formato y encabezados.';\n      }\n    });\n    el.btnDownload.addEventListener('click', ()=>downloadResults(computedRows));\n  })();\n  <\/script>\n<\/section>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-25e7093 e-flex e-con-boxed e-con e-parent\" data-id=\"25e7093\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Calculadora individual Calculadora masiva Calculadora de tallas EN 13402 \/ UNE-ISO 8559 \u00b7 Prototipo UE Unidades cm in Camiseta \/ Top \u00bfPara qui\u00e9n es la prenda? Selecciona\u2026MujerHombreNi\u00f1aNi\u00f1o Prenda Camiseta \/ TopCamisaPoloSudaderaJerseyCardiganVestido (busto) ChaquetaAbrigoAmericana \/ Traje Pantal\u00f3nVaqueroShortsFaldaLeggings Pijama (pecho\/busto)Ropa interior (cintura) Busto \/ Pecho (cm) Cintura (cm) Cadera (cm) Altura (cm) Pa\u00eds (UE) Espa\u00f1aPortugalFranciaItaliaAlemaniaPa\u00edses BajosB\u00e9lgicaLuxemburgoAustriaIrlandaDinamarcaSueciaFinlandiaPoloniaChequiaEslovaquiaHungr\u00edaRuman\u00edaBulgariaGreciaCroaciaEsloveniaEstoniaLetoniaLituaniaMaltaChipre Reino [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"elementor_canvas","meta":{"footnotes":""},"class_list":["post-6","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/calculadora.demotest.es\/index.php?rest_route=\/wp\/v2\/pages\/6","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/calculadora.demotest.es\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/calculadora.demotest.es\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/calculadora.demotest.es\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/calculadora.demotest.es\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=6"}],"version-history":[{"count":324,"href":"https:\/\/calculadora.demotest.es\/index.php?rest_route=\/wp\/v2\/pages\/6\/revisions"}],"predecessor-version":[{"id":364,"href":"https:\/\/calculadora.demotest.es\/index.php?rest_route=\/wp\/v2\/pages\/6\/revisions\/364"}],"wp:attachment":[{"href":"https:\/\/calculadora.demotest.es\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=6"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}