{"id":6337,"date":"2026-06-02T13:51:36","date_gmt":"2026-06-02T12:51:36","guid":{"rendered":"https:\/\/grinternationaladvisors.com\/income-tax-calculator\/"},"modified":"2026-08-05T14:25:34","modified_gmt":"2026-08-05T13:25:34","slug":"income-tax-calculator","status":"publish","type":"page","link":"https:\/\/grinternationaladvisors.com\/en\/income-tax-calculator\/","title":{"rendered":"Income Tax Calculator 2026"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"6337\" class=\"elementor elementor-6337 elementor-5485\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-0521dbf e-flex e-con-boxed e-con e-parent\" data-id=\"0521dbf\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-1b49b59 elementor-widget elementor-widget-text-editor\" data-id=\"1b49b59\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<style>\n*{box-sizing:border-box;margin:0;padding:0}\nbody{font-family:'Segoe UI',Arial,sans-serif;background:#f0f3fa;min-height:100vh}\nheader{background:#fff;border-bottom:1.5px solid #d0d8ef;padding:16px 40px;display:flex;align-items:center;justify-content:space-between}\nheader img{height:48px}\n.header-title{font-size:13px;color:#6b7fa8;font-weight:500;text-align:right;line-height:1.5}\n.container{max-width:720px;margin:32px auto;padding:0 20px}\nh1{font-size:21px;font-weight:700;color:#1a3fa0;margin-bottom:4px}\n.subtitle{font-size:13px;color:#6b7fa8;margin-bottom:24px}\n.card{background:#fff;border-radius:14px;border:1px solid #d0d8ef;padding:26px 30px;margin-bottom:20px}\n.section-title{font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.07em;color:#8fa0c8;margin-bottom:14px;padding-bottom:8px;border-bottom:1px solid #e8ecf8}\n\n\/* Toggle tipo *\/\n.tipo-toggle{display:flex;gap:0;border:1.5px solid #d0d8ef;border-radius:10px;overflow:hidden;margin-bottom:20px}\n.tipo-btn{flex:1;padding:11px 16px;cursor:pointer;border:none;background:#fff;font-size:13px;font-weight:600;color:#6b7fa8;transition:all .2s;text-align:center}\n.tipo-btn:first-child{border-right:1px solid #d0d8ef}\n.tipo-btn.active{background:#1a3fa0;color:#fff}\n.tipo-btn.active.green{background:#0e7a5a}\n.tipo-btn.active.orange{background:#c05c00}\n.gastos-row{display:flex;align-items:center;gap:10px;margin-top:12px;padding:10px 14px;background:#fff9f0;border-radius:9px;border:1px solid #f0d8b8}\n.gastos-row label{font-size:13px;color:#7a4800;white-space:nowrap;flex:1}\n.gastos-row input[type=range]{flex:2;accent-color:#c05c00}\n.gastos-row .gval{font-size:13px;font-weight:700;color:#c05c00;min-width:40px;text-align:right}\n.reg-block{margin-top:20px;border-top:1px solid #e8ecf8;padding-top:16px}\n.reg-line{display:flex;justify-content:space-between;align-items:center;padding:7px 0;border-bottom:1px solid #f0f4ff;font-size:13px}\n.reg-line:last-child{border-bottom:none}\n.reg-lbl{color:#6b7fa8}\n.reg-val{font-weight:600;color:#1a3fa0}\n.reg-val.red{color:#c0392b}\n.reg-val.gv{color:#0e7a5a}\n.reg-total{display:flex;justify-content:space-between;align-items:center;padding:12px 16px;border-radius:9px;margin-top:12px}\n.reg-total.pos{background:#e6f7f0}\n.reg-total.neg{background:#fde8e8}\n.reg-total-lbl{font-size:14px;font-weight:700;color:#2a3a6a}\n.reg-total-val{font-size:20px;font-weight:700}\n.reg-total.pos .reg-total-val{color:#0e7a5a}\n.reg-total.neg .reg-total-val{color:#c0392b}\n\n\/* Situaci\u00f3n *\/\n.sit-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(128px,1fr));gap:8px}\n.sit-btn{border:1.5px solid #d0d8ef;border-radius:10px;padding:9px 7px;cursor:pointer;background:#fff;text-align:center;transition:all .2s;font-size:11.5px;color:#4a5a8a;font-weight:500;line-height:1.35}\n.sit-btn:hover{border-color:#1a5fe0;background:#f0f4ff}\n.sit-btn.active{border-color:#1a5fe0;background:#eef2fc;color:#1a3fa0}\n.sit-btn .sit-icon{font-size:18px;margin-bottom:3px;display:block}\n.sit-req{font-size:10px;font-weight:400;color:#8fa0c8;display:block;margin-top:2px;line-height:1.2}\n.sit-req-no{color:#c0392b}\n\n\/* Aviso hijo *\/\n.aviso{margin-top:12px;padding:9px 14px;border-radius:8px;font-size:12px;line-height:1.6;display:none}\n\n\/* Slider *\/\n.slider-row{display:flex;align-items:center;gap:14px;margin-top:20px}\n.slider-label{font-size:13px;color:#6b7fa8;white-space:nowrap;min-width:130px}\ninput[type=range]{flex:1;accent-color:#1a5fe0;cursor:pointer}\n.num-wrap{display:flex;align-items:center;gap:4px;border:1.5px solid #c5cfe8;border-radius:8px;padding:6px 10px;background:#f4f6fb}\ninput[type=number]{width:86px;font-size:15px;font-weight:700;color:#1a3fa0;border:none;background:transparent;text-align:right;outline:none}\ninput[type=number]::-webkit-outer-spin-button,input[type=number]::-webkit-inner-spin-button{-webkit-appearance:none}\n.unit{font-size:13px;color:#6b7fa8}\n\n\/* M\u00e9tricas *\/\n.metrics{display:grid;grid-template-columns:repeat(auto-fit,minmax(155px,1fr));gap:12px;margin:20px 0 0}\n.metric{background:#f4f6fb;border-radius:9px;padding:13px 15px}\n.metric.accent{background:#e8f4fd}\n.metric.green{background:#e6f7f0}\n.metric.warn{background:#fff9e6}\n.metric-label{font-size:10.5px;text-transform:uppercase;letter-spacing:.06em;color:#8fa0c8;margin-bottom:5px}\n.metric-value{font-size:22px;font-weight:700;color:#1a3fa0}\n.metric-value.gv{color:#0e7a5a}\n.metric-value.amber{color:#b07a00}\n.metric-sub{font-size:12px;color:#8fa0c8;margin-top:3px}\n\n\/* Tramos *\/\n.tramos-header{display:grid;grid-template-columns:2fr 50px 120px 110px;gap:6px;padding:6px 10px;font-size:10px;text-transform:uppercase;letter-spacing:.06em;color:#8fa0c8;font-weight:700;margin-top:20px}\n.tramo-row{display:grid;grid-template-columns:2fr 50px 120px 110px;gap:6px;align-items:center;padding:8px 10px;border-radius:7px;margin-bottom:3px;font-size:13px}\n.tramo-row.active{background:#eef2fc}\n.bar-wrap{width:100%;background:#dde3f0;border-radius:3px;height:4px;overflow:hidden;margin-top:4px}\n.bar-fill{height:4px;border-radius:3px;transition:width .4s ease}\n.tipo-b{font-size:12px;font-weight:700;color:#1a5fe0;text-align:right}\n.base-v{font-size:12px;color:#4a5a8a;text-align:right}\n.cuota-v{font-size:12px;font-weight:600;color:#1a3fa0;text-align:right}\n.cuota-v.dim{color:#c5cfe8;font-weight:400}\n\n\/* Detalle aut\u00f3nomo *\/\n.det-block{margin-top:20px;border-top:1px solid #e8ecf8;padding-top:16px}\n.det-line{display:flex;justify-content:space-between;align-items:center;padding:6px 0;border-bottom:1px solid #f0f4ff;font-size:13px}\n.det-line:last-child{border-bottom:none;padding-top:8px;margin-top:4px}\n.det-lbl{color:#6b7fa8}\n.det-val{font-weight:600;color:#1a3fa0}\n.det-val.red{color:#c0392b}\n.det-val.gv{color:#0e7a5a}\n\n.nota{font-size:11.5px;color:#8fa0c8;line-height:1.7}\nfooter{text-align:center;font-size:11px;color:#aabace;padding:20px 0 36px}\n@media(max-width:560px){\n  .tramos-header,.tramo-row{grid-template-columns:1.5fr 40px 90px 80px;font-size:11px}\n  header{padding:12px 16px;flex-direction:column;gap:8px;align-items:flex-start}\n  .sit-grid{grid-template-columns:repeat(3,1fr)}\n  .tipo-btn{font-size:12px;padding:9px 8px}\n}\n<\/style>\n<script src=\"https:\/\/cdn.jsdelivr.net\/npm\/@emailjs\/browser@4\/dist\/email.min.js\"><\/script>\n<script>emailjs.init(\"JO_d2UP9OhEX5JVTu\");<\/script>\n\n\n\n<div class=\"container\">\n\n\n  <div class=\"card\">\n    \n    <div class=\"section-title\">Tipo de contribuyente<\/div>\n    <div class=\"tipo-toggle\" style=\"flex-wrap:wrap\">\n      <button class=\"tipo-btn active\" id=\"btnAsal\" onclick=\"setTipo('asalariado')\" style=\"border-right:1px solid #d0d8ef;flex:1;min-width:140px\">\ud83d\udc54 Employee<\/button>\n<button class=\"tipo-btn\" id=\"btnAut\" onclick=\"setTipo('autonomo')\" style=\"border-right:1px solid #d0d8ef;flex:1;min-width:140px\">\ud83c\udfe2 Self-employed (company)<\/button>\n<button class=\"tipo-btn\" id=\"btnAct\" onclick=\"setTipo('actividad')\" style=\"flex:1;min-width:140px\">\ud83e\uddfe Self-employed (active)<\/button>\n    <\/div>\n\n    \n    <div class=\"section-title\">Personal and family circumstances<\/div>\n\n    <div style=\"display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:12px\">\n      <div>\n        <div style=\"font-size:11px;text-transform:uppercase;letter-spacing:.06em;color:#8fa0c8;margin-bottom:6px\">Marital status<\/div>\n        <div style=\"display:flex;flex-wrap:wrap;gap:6px\" id=\"civil-btns\">\n          <button class=\"sit-btn active\" data-civil=\"soltero\" onclick=\"setCivil(this)\">\ud83d\udc64 Single<\/button>\n<button class=\"sit-btn\" data-civil=\"casado\" onclick=\"setCivil(this)\">\ud83d\udc6b Married<\/button>\n<button class=\"sit-btn\" data-civil=\"separado\" onclick=\"setCivil(this)\">\u2696\ufe0f Separated<\/button>\n<button class=\"sit-btn\" data-civil=\"mono\" onclick=\"setCivil(this)\">\ud83c\udfe0 Single parent<\/button>\n        <\/div>\n      <\/div>\n      <div>\n        <div style=\"font-size:11px;text-transform:uppercase;letter-spacing:.06em;color:#8fa0c8;margin-bottom:6px\">Number of children<\/div>\n        <div style=\"display:flex;flex-wrap:wrap;gap:6px\" id=\"nhijos-btns\">\n          <button class=\"sit-btn active\" data-n=\"0\" onclick=\"setNHijos(this)\">0<\/button>\n<button class=\"sit-btn\" data-n=\"1\" onclick=\"setNHijos(this)\">1<\/button>\n<button class=\"sit-btn\" data-n=\"2\" onclick=\"setNHijos(this)\">2<\/button>\n<button class=\"sit-btn\" data-n=\"3\" onclick=\"setNHijos(this)\">3<\/button>\n<button class=\"sit-btn\" data-n=\"4\" onclick=\"setNHijos(this)\">4+<\/button>\n        <\/div>\n      <\/div>\n    <\/div>\n\n    \n    <div id=\"hijos-detalle\"><\/div>\n\n    <div class=\"aviso\" id=\"hijo-aviso\"><\/div>\n\n    \n    <div style=\"margin-top:14px\">\n      <div style=\"font-size:11px;text-transform:uppercase;letter-spacing:.06em;color:#8fa0c8;margin-bottom:6px\">Dependent ascendants (parents\/grandparents)<\/div>\n      <div style=\"display:flex;flex-wrap:wrap;gap:6px\" id=\"nasc-btns\">\n        <button class=\"sit-btn active\" data-n=\"0\" onclick=\"setNAsc(this)\">0<\/button>\n <button class=\"sit-btn\" data-n=\"1\" onclick=\"setNAsc(this)\">1<\/button>\n <button class=\"sit-btn\" data-n=\"2\" onclick=\"setNAsc(this)\">2+<\/button>\n      <\/div>\n    <\/div>\n    <div id=\"asc-detalle\"><\/div>\n    <div class=\"aviso\" id=\"asc-aviso\"><\/div>\n\n    \n    <div class=\"gastos-row\" id=\"gastos-row\" style=\"display:none\">\n      <span class=\"slider-label\" style=\"color:#7a4800;min-width:130px\">Deductible expenses<\/span>\n      <input type=\"range\" id=\"gastosSlider\" min=\"0\" max=\"80000\" step=\"500\" value=\"10000\">\n      <div class=\"num-wrap\" style=\"border-color:#f0d8b8;background:#fff9f0\">\n        <input type=\"number\" id=\"gastosNum\" value=\"10000\" min=\"0\" max=\"80000\" step=\"500\" style=\"color:#c05c00\">\n        <span class=\"unit\">\u20ac<\/span>\n      <\/div>\n    <\/div>\n\n    \n    <div class=\"slider-row\">\n      <span class=\"slider-label\" id=\"sliderLabel\">Gross annual salary<\/span>\n      <input type=\"range\" id=\"slider\" min=\"15000\" max=\"150000\" step=\"500\" value=\"53000\">\n      <div class=\"num-wrap\">\n        <input type=\"number\" id=\"inputNum\" value=\"53000\" min=\"15000\" max=\"150000\" step=\"500\">\n        <span class=\"unit\">\u20ac<\/span>\n      <\/div>\n    <\/div>\n  <\/div>\n\n  \n  <div class=\"card\" id=\"resultCard\">\n    <div class=\"section-title\" id=\"resTitle\">Result \u2014 Employee<\/div>\n\n    <div class=\"metrics\">\n      <div class=\"metric\">\n        <div class=\"metric-label\">Income tax liability<\/div>\n        <div class=\"metric-value\" id=\"r-cuota\">\u2014<\/div>\n        <div class=\"metric-sub\" id=\"r-tef\">\u2014<\/div>\n      <\/div>\n      <div class=\"metric\" id=\"r-ss-card\">\n        <div class=\"metric-label\" id=\"r-ss-label\">Social Security contribution (~6.35%)<\/div>\n        <div class=\"metric-value\" id=\"r-ss\">\u2014<\/div>\n        <div class=\"metric-sub\" id=\"r-ss-sub\"><\/div>\n      <\/div>\n      <div class=\"metric accent\">\n        <div class=\"metric-label\">Estimated take-home pay<\/div>\n        <div class=\"metric-value\" id=\"r-neto\">\u2014<\/div>\n        <div class=\"metric-sub\" id=\"r-mes\">\u2014<\/div>\n      <\/div>\n    <\/div>\n\n    \n    <div class=\"det-block\" id=\"aut-detalle\" style=\"display:none\">\n      <div class=\"section-title\" style=\"margin-top:0\">Calculation details<\/div>\n      <div class=\"det-line\"><span class=\"det-lbl\">Ingresos brutos<\/span><span class=\"det-val\" id=\"d-base\">\u2014<\/span><\/div>\n      <div class=\"det-line\">Minimum staff and family members included\u2014<\/div>\n      <div class=\"det-line\"><span class=\"det-lbl\">Taxable base<\/span><span class=\"det-val\" id=\"d-bliq\">\u2014<\/span><\/div>\n      <div class=\"det-line\"><span class=\"det-lbl\">Calculated personal income tax<\/span>\u2014<\/div>\n      <div class=\"det-line\"><span class=\"det-lbl\">Company social security contributions (\u20ac448\/month \u00d7 12)<\/span><span class=\"det-val red\" id=\"d-ss\">\u2014<\/span><\/div>\n      <div class=\"det-line\" style=\"border-top:2px solid #e8ecf8;margin-top:4px\"><span class=\"det-lbl\" style=\"font-weight:700;color:#2a3a6a\">Final net total<\/span><span class=\"det-val gv\" style=\"font-size:16px\" id=\"d-neto\">\u2014<\/span><\/div>\n    <\/div>\n\n    \n    <div class=\"reg-block\" id=\"act-detalle\" style=\"display:none\">\n      <div class=\"section-title\" style=\"margin-top:0\">Income tax adjustment \u2014 Mod. 130<\/div>\n      <div class=\"reg-line\"><span class=\"reg-lbl\">Annual turnover (gross)<\/span><span class=\"reg-val\" id=\"ac-factura\">\u2014<\/span><\/div>\n      <div class=\"reg-line\"><span class=\"reg-lbl\">Deductible expenses<\/span><span class=\"reg-val red\" id=\"ac-gastos\">\u2014<\/span><\/div>\n      <div class=\"reg-line\"><span class=\"reg-lbl\">Net return (for income tax purposes)<\/span><span class=\"reg-val\" id=\"ac-redneto\">\u2014<\/span><\/div>\n      <div class=\"reg-line\"><span class=\"reg-lbl\">Just a few staff and family members<\/span><span class=\"reg-val gv\" id=\"ac-minimo\">\u2014<\/span><\/div>\n      <div class=\"reg-line\"><span class=\"reg-lbl\">Base imponible<\/span><span class=\"reg-val\" id=\"ac-bliq\">\u2014<\/span><\/div>\n      <div class=\"reg-line\"><span class=\"reg-lbl\">Total personal income tax based on income<\/span><span class=\"reg-val\" id=\"ac-irpftotal\">\u2014<\/span><\/div>\n      <div class=\"reg-line\"><span class=\"reg-lbl\">Income tax already paid (15% withholding tax)<\/span><span class=\"reg-val red\" id=\"ac-retenido\">\u2014<\/span><\/div>\n      <div id=\"ac-totalblock\" class=\"reg-total neg\">\n        <span class=\"reg-total-lbl\">To be paid \/ refunded on rent<\/span>\n<span class=\"reg-total-val\" id=\"ac-total\">\u2014<\/span>\n      <\/div>\n    <\/div>\n\n    \n    <div class=\"tramos-header\" id=\"tramos-header\">\n      <span>Taxable income bracket<\/span>\n<span style=\"text-align:right\">Rate<\/span>\n<span style=\"text-align:right\">Base amount applied<\/span>\n<span style=\"text-align:right\">Tax payable for the bracket<\/span>\n    <\/div>\n    <div id=\"tramos-container\"><\/div>\n    <p id=\"tramos-nota-act\" style=\"display:none;font-size:11.5px;color:#8fa0c8;margin-top:10px;line-height:1.6\">The brackets show the personal income tax calculated on the net income (turnover \u2212 expenses \u2212 allowances). The marginal rate indicates the tax rate applied to the last euro of profit. <\/p>\n  <\/div>\n\n  <div class=\"card\">\n    <p class=\"nota\">\n      <strong>Methodological note 2026: <\/strong>Tax brackets remain unchanged from 2025 (source: AEAT). Minimum thresholds under Articles 57\u201361 of the Personal Income Tax Act (LIRPF): taxpayer \u20ac5,550; 1st child \u20ac2,400; 2nd child \u20ac2,700; 3rd child \u20ac4,000; 4th and subsequent children \u20ac4,500. Each child can be marked individually as \u2018meets\u2019 or \u2018does not meet\u2019 the requirements (Article 58: under 25 years of age and income < \u20ac8,000). Parents, Art. 59: \u20ac1,150 (1st) and \u20ac2,550 (2nd and subsequent); eligibility criteria: aged over 65 or disability \u226533 per cent, living in the same household and income < \u20ac8,000. Ascendants (Art. 59): \u20ac1,150 (1st) and \u20ac2,550 (2nd and subsequent); requirements: aged over 65 or disability \u226533 per cent, living together and income < \u20ac8,000. Single parent\/separated with custody: +\u20ac2,150 reduction in tax base; joint taxation: \u2212\u20ac3,400 from tax base. Reduction on employment income (Art. 20): up to \u20ac14,000 net income \u2192 \u20ac6,498; degressive bracket up to \u20ac19,747. Social security contributions for employees ~6.35% (CC 4.70% + unemployment 1.55% + vocational training 0.10%). Self-employed person registered as a company: minimum tax base \u20ac1,424.60\/month, minimum contribution \u20ac448\/month (rate 31.4% incl. MEI 0.9%) not deducted from the personal income tax base in this model. Indicative calculation \u2014 does not include regional deductions or individual circumstances.          <strong>Please contact GR International Advisors for personalised tax planning.<\/strong>\n    <\/p>\n  <\/div>\n<\/div>\n\n\n<div id=\"email-overlay\" style=\"display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.45);z-index:1000;align-items:center;justify-content:center\">\n  <div style=\"background:#fff;border-radius:14px;padding:32px 28px;max-width:420px;width:90%;box-shadow:0 8px 40px rgba(0,0,0,0.18);position:relative\">\n    <button onclick=\"closeEmailModal()\" style=\"position:absolute;top:14px;right:16px;border:none;background:none;font-size:20px;cursor:pointer;color:#8fa0c8\">\u2715<\/button>\n    <div style=\"text-align:center;margin-bottom:20px\">\n      <img id=\"modal-logo\" style=\"height:36px\" alt=\"GR International Advisors\">\n    <\/div>\n    <h2 style=\"font-size:17px;font-weight:700;color:#1a3fa0;margin-bottom:6px;text-align:center\">Send simulation by email<\/h2>\n    <p style=\"font-size:13px;color:#8fa0c8;text-align:center;margin-bottom:20px;line-height:1.5\">You will receive a summary of your 2026 income tax simulation.<br\/>GR International Advisors will receive a copy.<\/p>\n    <div style=\"margin-bottom:14px\">\n      <label style=\"font-size:12px;color:#6b7fa8;font-weight:600;display:block;margin-bottom:5px\">Your email address<\/label>\n      <input id=\"email-input\" type=\"email\" placeholder=\"tucorreo@ejemplo.com\" style=\"width:100%;padding:10px 14px;border:1.5px solid #c5cfe8;border-radius:8px;font-size:14px;outline:none;color:#2a3a6a\">\n    <\/div>\n    <button id=\"email-send-btn\" onclick=\"enviarEmail()\" style=\"width:100%;padding:12px;background:#1a3fa0;color:#fff;border:none;border-radius:9px;font-size:14px;font-weight:700;cursor:pointer;transition:all .2s\">\n \ud83d\udce7 Submit simulation\n    <\/button>\n    <div id=\"email-status\" style=\"margin-top:12px;font-size:13px;text-align:center;min-height:20px\"><\/div>\n  <\/div>\n<\/div>\n\n\n<div style=\"position:fixed;bottom:28px;left:50%;transform:translateX(-50%);z-index:999\">\n  <button onclick=\"openEmailModal()\" style=\"background:#1a3fa0;color:#fff;border:none;border-radius:50px;padding:13px 22px;font-size:13px;font-weight:700;cursor:pointer;box-shadow:0 4px 16px rgba(26,63,160,0.35);display:flex;align-items:center;gap:8px;transition:all .2s\">\n    <img decoding=\"async\" draggable=\"false\" role=\"img\" class=\"emoji\" alt=\"\ud83d\udce7\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/17.0.2\/svg\/1f4e7.svg\"> Send report by email\n  <\/button>\n<\/div>\n\n<footer>\u00a9 2026 GR International Advisors \u00b7 Internal guidance document \u00b7 Personal Income Tax for the 2026 tax year<\/footer>\n\n<script>\nconst tramos = [\n  {min:0,      max:12450,   tipo:.19, label:\"0 \u2013 12.450 \u20ac\",       color:\"#1aaa7a\"},\n  {min:12450,  max:20200,   tipo:.24, label:\"12.450 \u2013 20.200 \u20ac\",  color:\"#1a5fe0\"},\n  {min:20200,  max:35200,   tipo:.30, label:\"20.200 \u2013 35.200 \u20ac\",  color:\"#7f77dd\"},\n  {min:35200,  max:60000,   tipo:.37, label:\"35.200 \u2013 60.000 \u20ac\",  color:\"#e08a1a\"},\n  {min:60000,  max:300000,  tipo:.45, label:\"60.000 \u2013 300.000 \u20ac\", color:\"#d85a30\"},\n  {min:300000, max:Infinity,tipo:.47, label:\"M\u00e1s de 300.000 \u20ac\",   color:\"#a32d2d\"},\n];\n\nconst MINS_HIJO = [2400, 2700, 4000, 4500]; \/\/ index 0=1er hijo ... 3+=4o\nconst MINS_ASC  = [1150, 2550]; \/\/ 1.er ascendiente, 2.\u00ba y siguientes (art. 59 LIRPF)\n\nlet currentCivil  = 'soltero';\nlet currentNHijos = 0;\nlet hijosState    = [];\nlet currentNAsc   = 0;\nlet ascState      = [];\nlet currentTipo   = 'asalariado';\n\n\/* \u2500\u2500 Estado civil \u2500\u2500 *\/\nfunction setCivil(btn){\n  document.querySelectorAll('#civil-btns .sit-btn').forEach(function(b){ b.classList.remove('active'); });\n  btn.classList.add('active');\n  currentCivil = btn.dataset.civil;\n  updateHijosDetalle();\n  updateAviso();\n  updateAscDetalle();\n  updateAscAviso();\n  render(+document.getElementById('slider').value);\n}\n\n\/* \u2500\u2500 N\u00famero de hijos \u2500\u2500 *\/\nfunction setNHijos(btn){\n  document.querySelectorAll('#nhijos-btns .sit-btn').forEach(function(b){ b.classList.remove('active'); });\n  btn.classList.add('active');\n  var n = btn.dataset.n === '4' ? 4 : +btn.dataset.n;\n  currentNHijos = n;\n  while(hijosState.length < n) hijosState.push({ok: true});\n  hijosState = hijosState.slice(0, n);\n  updateHijosDetalle();\n  updateAviso();\n  render(+document.getElementById('slider').value);\n}\n\n\/* \u2500\u2500 Toggle requisito por hijo \u2500\u2500 *\/\nfunction toggleHijoOk(idx){\n  hijosState[idx].ok = !hijosState[idx].ok;\n  var btn = document.getElementById('hijo-ok-btn-' + idx);\n  applyHijoBtnStyle(btn, hijosState[idx].ok);\n  updateAviso();\n  render(+document.getElementById('slider').value);\n}\n\nfunction applyHijoBtnStyle(btn, ok){\n  btn.textContent   = ok ? '\u2714 Cumple requisitos' : '\u2717 No cumple';\n  btn.style.background  = ok ? '#e6f7f0' : '#fde8e8';\n  btn.style.color       = ok ? '#0e7a5a' : '#c0392b';\n  btn.style.borderColor = ok ? '#9edfc8' : '#f5b8b8';\n}\n\n\/* \u2500\u2500 Render tarjetas de hijos \u2500\u2500 *\/\nfunction updateHijosDetalle(){\n  var cont = document.getElementById('hijos-detalle');\n  cont.innerHTML = '';\n  if(currentNHijos === 0) return;\n  var labels = ['1.er hijo','2.\u00ba hijo','3.er hijo','4.\u00ba hijo'];\n  var wrap = document.createElement('div');\n  wrap.style.cssText = 'margin-bottom:10px;display:flex;flex-wrap:wrap;gap:8px';\n  for(var i = 0; i < currentNHijos; i++){\n    var ok  = hijosState[i] ? hijosState[i].ok : true;\n    var lbl = i < 4 ? labels[i] : (i+1)+'.\u00ba hijo';\n    var min = i < 3 ? MINS_HIJO[i] : MINS_HIJO[3];\n    var card = document.createElement('div');\n    card.style.cssText = 'border:1px solid #dde3f0;border-radius:9px;padding:8px 12px;background:#f8f9fd;min-width:140px;flex:1';\n    var title = document.createElement('div');\n    title.style.cssText = 'font-size:11px;color:#8fa0c8;font-weight:700;text-transform:uppercase;letter-spacing:.05em;margin-bottom:5px';\n    title.textContent = lbl + ' \u00b7 ' + min.toLocaleString('es-ES') + ' \u20ac';\n    var obtn = document.createElement('button');\n    obtn.id = 'hijo-ok-btn-' + i;\n    obtn.style.cssText = 'width:100%;padding:5px 8px;border-radius:6px;border:1px solid;cursor:pointer;font-size:12px;font-weight:600;transition:all .2s';\n    obtn.setAttribute('data-idx', i);\n    obtn.addEventListener('click', (function(idx){ return function(){ toggleHijoOk(idx); }; })(i));\n    applyHijoBtnStyle(obtn, ok);\n    var hint = document.createElement('div');\n    hint.style.cssText = 'font-size:10px;color:#8fa0c8;margin-top:4px;line-height:1.4';\n    hint.textContent = '<25 a. y rentas <8.000 \u20ac';\n    card.appendChild(title);\n    card.appendChild(obtn);\n    card.appendChild(hint);\n    wrap.appendChild(card);\n  }\n  cont.appendChild(wrap);\n}\n\n\/* \u2500\u2500 Aviso resumen hijos \u2500\u2500 *\/\nfunction updateAviso(){\n  var el = document.getElementById('hijo-aviso');\n  if(currentNHijos === 0){ el.style.display = 'none'; return; }\n  var okCount = hijosState.filter(function(h){ return h.ok; }).length;\n  var noCount = currentNHijos - okCount;\n  var total = 0;\n  for(var i = 0; i < currentNHijos; i++){\n    if(hijosState[i] &#038;&#038; hijosState[i].ok) total += i < 3 ? MINS_HIJO[i] : MINS_HIJO[3];\n  }\n  var fmtTotal = total.toLocaleString('es-ES');\n  var msg = '';\n  if(okCount > 0 && noCount === 0){\n    el.style.background = '#e6f7f0'; el.style.color = '#0e7a5a';\n    msg = '<strong>\u2714 M\u00ednimo por descendientes aplicado: ' + fmtTotal + ' \u20ac<\/strong> \u2014 ' + okCount + ' hijo\/s cumplen requisitos (art. 58 LIRPF).';\n  } else if(okCount === 0){\n    el.style.background = '#fde8e8'; el.style.color = '#c0392b';\n    msg = '<strong>\u2717 Ning\u00fan hijo cumple los requisitos<\/strong> \u2014 m\u00ednimo 0 \u20ac. Todos tienen \u226525 a\u00f1os o rentas \u22658.000 \u20ac.';\n  } else {\n    el.style.background = '#fff9e6'; el.style.color = '#b07a00';\n    msg = '<strong>\u26a0 M\u00ednimo parcial: ' + fmtTotal + ' \u20ac<\/strong> \u2014 ' + okCount + ' cumplen, ' + noCount + ' no cumplen (\u226525 a. o \u22658.000 \u20ac).';\n  }\n  el.style.display = 'block';\n  el.innerHTML = msg;\n}\n\n\/* \u2500\u2500 C\u00e1lculo m\u00ednimo familiar \u2500\u2500 *\/\nfunction calcMinFamiliar(){\n  var total = 5550;\n  for(var i = 0; i < currentNHijos; i++){\n    if(hijosState[i] &#038;&#038; hijosState[i].ok) total += i < 3 ? MINS_HIJO[i] : MINS_HIJO[3];\n  }\n  for(var j = 0; j < currentNAsc; j++){\n    if(ascState[j] &#038;&#038; ascState[j].ok) total += j === 0 ? MINS_ASC[0] : MINS_ASC[1];\n  }\n  return total;\n}\n\n\/* \u2500\u2500 Ascendientes \u2500\u2500 *\/\nfunction setNAsc(btn){\n  document.querySelectorAll('#nasc-btns .sit-btn').forEach(function(b){ b.classList.remove('active'); });\n  btn.classList.add('active');\n  var n = btn.dataset.n === '2' ? 2 : +btn.dataset.n;\n  currentNAsc = n;\n  while(ascState.length < n) ascState.push({ok: true});\n  ascState = ascState.slice(0, n);\n  updateAscDetalle();\n  updateAscAviso();\n  render(+document.getElementById('slider').value);\n}\n\nfunction toggleAscOk(idx){\n  ascState[idx].ok = !ascState[idx].ok;\n  var btn = document.getElementById('asc-ok-btn-' + idx);\n  applyAscBtnStyle(btn, ascState[idx].ok);\n  updateAscAviso();\n  render(+document.getElementById('slider').value);\n}\n\nfunction applyAscBtnStyle(btn, ok){\n  btn.textContent   = ok ? '\u2714 Cumple requisitos' : '\u2717 No cumple';\n  btn.style.background  = ok ? '#e6f7f0' : '#fde8e8';\n  btn.style.color       = ok ? '#0e7a5a' : '#c0392b';\n  btn.style.borderColor = ok ? '#9edfc8' : '#f5b8b8';\n}\n\nfunction updateAscDetalle(){\n  var cont = document.getElementById('asc-detalle');\n  cont.innerHTML = '';\n  if(currentNAsc === 0) return;\n  var labels = ['1.er ascendiente','2.\u00ba ascendiente'];\n  var wrap = document.createElement('div');\n  wrap.style.cssText = 'margin-top:10px;margin-bottom:4px;display:flex;flex-wrap:wrap;gap:8px';\n  for(var i = 0; i < currentNAsc; i++){\n    var ok  = ascState[i] ? ascState[i].ok : true;\n    var lbl = i < 2 ? labels[i] : (i+1)+'.\u00ba ascendiente';\n    var mn  = i === 0 ? MINS_ASC[0] : MINS_ASC[1];\n    var card = document.createElement('div');\n    card.style.cssText = 'border:1px solid #dde3f0;border-radius:9px;padding:8px 12px;background:#f8f9fd;min-width:160px;flex:1';\n    var title = document.createElement('div');\n    title.style.cssText = 'font-size:11px;color:#8fa0c8;font-weight:700;text-transform:uppercase;letter-spacing:.05em;margin-bottom:5px';\n    title.textContent = lbl + ' \u00b7 ' + mn.toLocaleString('es-ES') + ' \u20ac';\n    var obtn = document.createElement('button');\n    obtn.id = 'asc-ok-btn-' + i;\n    obtn.style.cssText = 'width:100%;padding:5px 8px;border-radius:6px;border:1px solid;cursor:pointer;font-size:12px;font-weight:600;transition:all .2s';\n    obtn.addEventListener('click', (function(idx){ return function(){ toggleAscOk(idx); }; })(i));\n    applyAscBtnStyle(obtn, ok);\n    var hint = document.createElement('div');\n    hint.style.cssText = 'font-size:10px;color:#8fa0c8;margin-top:4px;line-height:1.4';\n    hint.textContent = '>65 a\u00f1os (o discapacidad \u226533%) \u00b7 convivencia \u00b7 rentas <8.000 \u20ac';\n    card.appendChild(title);\n    card.appendChild(obtn);\n    card.appendChild(hint);\n    wrap.appendChild(card);\n  }\n  cont.appendChild(wrap);\n}\n\nfunction updateAscAviso(){\n  var el = document.getElementById('asc-aviso');\n  if(currentNAsc === 0){ el.style.display = 'none'; return; }\n  var okCount = ascState.filter(function(a){ return a.ok; }).length;\n  var noCount = currentNAsc - okCount;\n  var total = 0;\n  for(var i = 0; i < currentNAsc; i++){\n    if(ascState[i] &#038;&#038; ascState[i].ok) total += i === 0 ? MINS_ASC[0] : MINS_ASC[1];\n  }\n  var fmtTotal = total.toLocaleString('es-ES');\n  var msg = '';\n  if(okCount > 0 && noCount === 0){\n    el.style.background = '#e6f7f0'; el.style.color = '#0e7a5a';\n    msg = '<strong>\u2714 M\u00ednimo por ascendientes aplicado: ' + fmtTotal + ' \u20ac<\/strong> \u2014 ' + okCount + ' ascendiente\/s cumplen requisitos (art. 59 LIRPF).';\n  } else if(okCount === 0){\n    el.style.background = '#fde8e8'; el.style.color = '#c0392b';\n    msg = '<strong>\u2717 Ning\u00fan ascendiente cumple los requisitos<\/strong> \u2014 m\u00ednimo 0 \u20ac.';\n  } else {\n    el.style.background = '#fff9e6'; el.style.color = '#b07a00';\n    msg = '<strong>\u26a0 M\u00ednimo parcial: ' + fmtTotal + ' \u20ac<\/strong> \u2014 ' + okCount + ' cumplen, ' + noCount + ' no cumplen.';\n  }\n  el.style.display = 'block';\n  el.innerHTML = msg;\n}\n\n\/* \u2500\u2500 Ascendientes \u2500\u2500 *\/\nfunction setNAsc(btn){\n  document.querySelectorAll('#nasc-btns .sit-btn').forEach(function(b){ b.classList.remove('active'); });\n  btn.classList.add('active');\n  var n = btn.dataset.n === '2' ? 2 : +btn.dataset.n;\n  currentNAsc = n;\n  while(ascState.length < n) ascState.push({ok: true});\n  ascState = ascState.slice(0, n);\n  updateAscDetalle();\n  updateAscAviso();\n  render(+document.getElementById('slider').value);\n}\n\nfunction toggleAscOk(idx){\n  ascState[idx].ok = !ascState[idx].ok;\n  var btn = document.getElementById('asc-ok-btn-' + idx);\n  applyAscBtnStyle(btn, ascState[idx].ok);\n  updateAscAviso();\n  render(+document.getElementById('slider').value);\n}\n\nfunction applyAscBtnStyle(btn, ok){\n  btn.textContent   = ok ? '\u2714 Cumple requisitos' : '\u2717 No cumple';\n  btn.style.background  = ok ? '#e6f7f0' : '#fde8e8';\n  btn.style.color       = ok ? '#0e7a5a' : '#c0392b';\n  btn.style.borderColor = ok ? '#9edfc8' : '#f5b8b8';\n}\n\nfunction updateAscDetalle(){\n  var cont = document.getElementById('asc-detalle');\n  cont.innerHTML = '';\n  if(currentNAsc === 0) return;\n  var labels = ['1.er ascendiente','2.\u00ba ascendiente'];\n  var wrap = document.createElement('div');\n  wrap.style.cssText = 'margin-top:10px;margin-bottom:4px;display:flex;flex-wrap:wrap;gap:8px';\n  for(var i = 0; i < currentNAsc; i++){\n    var ok  = ascState[i] ? ascState[i].ok : true;\n    var lbl = i < 2 ? labels[i] : (i+1)+'.\u00ba ascendiente';\n    var mn  = i === 0 ? MINS_ASC[0] : MINS_ASC[1];\n    var card = document.createElement('div');\n    card.style.cssText = 'border:1px solid #dde3f0;border-radius:9px;padding:8px 12px;background:#f8f9fd;min-width:160px;flex:1';\n    var title = document.createElement('div');\n    title.style.cssText = 'font-size:11px;color:#8fa0c8;font-weight:700;text-transform:uppercase;letter-spacing:.05em;margin-bottom:5px';\n    title.textContent = lbl + ' \u00b7 ' + mn.toLocaleString('es-ES') + ' \u20ac';\n    var obtn = document.createElement('button');\n    obtn.id = 'asc-ok-btn-' + i;\n    obtn.style.cssText = 'width:100%;padding:5px 8px;border-radius:6px;border:1px solid;cursor:pointer;font-size:12px;font-weight:600;transition:all .2s';\n    obtn.addEventListener('click', (function(idx){ return function(){ toggleAscOk(idx); }; })(i));\n    applyAscBtnStyle(obtn, ok);\n    var hint = document.createElement('div');\n    hint.style.cssText = 'font-size:10px;color:#8fa0c8;margin-top:4px;line-height:1.4';\n    hint.textContent = '>65 a\u00f1os (o discapacidad \u226533%) \u00b7 convivencia \u00b7 rentas <8.000 \u20ac';\n    card.appendChild(title);\n    card.appendChild(obtn);\n    card.appendChild(hint);\n    wrap.appendChild(card);\n  }\n  cont.appendChild(wrap);\n}\n\nfunction updateAscAviso(){\n  var el = document.getElementById('asc-aviso');\n  if(currentNAsc === 0){ el.style.display = 'none'; return; }\n  var okCount = ascState.filter(function(a){ return a.ok; }).length;\n  var noCount = currentNAsc - okCount;\n  var total = 0;\n  for(var i = 0; i < currentNAsc; i++){\n    if(ascState[i] &#038;&#038; ascState[i].ok) total += i === 0 ? MINS_ASC[0] : MINS_ASC[1];\n  }\n  var fmtTotal = total.toLocaleString('es-ES');\n  var msg = '';\n  if(okCount > 0 && noCount === 0){\n    el.style.background = '#e6f7f0'; el.style.color = '#0e7a5a';\n    msg = '<strong>\u2714 M\u00ednimo por ascendientes aplicado: ' + fmtTotal + ' \u20ac<\/strong> \u2014 ' + okCount + ' ascendiente\/s cumplen requisitos (art. 59 LIRPF).';\n  } else if(okCount === 0){\n    el.style.background = '#fde8e8'; el.style.color = '#c0392b';\n    msg = '<strong>\u2717 Ning\u00fan ascendiente cumple los requisitos<\/strong> \u2014 m\u00ednimo 0 \u20ac.';\n  } else {\n    el.style.background = '#fff9e6'; el.style.color = '#b07a00';\n    msg = '<strong>\u26a0 M\u00ednimo parcial: ' + fmtTotal + ' \u20ac<\/strong> \u2014 ' + okCount + ' cumplen, ' + noCount + ' no cumplen.';\n  }\n  el.style.display = 'block';\n  el.innerHTML = msg;\n}\n\nfunction calcReducciones(){\n  var redConjunta = currentCivil === 'casado' ? 3400 : 0;\n  var redMono     = (currentCivil === 'separado' || currentCivil === 'mono') ? 2150 : 0;\n  return {redConjunta: redConjunta, redMono: redMono};\n}\n\n\/* \u2500\u2500 Tipo de contribuyente \u2500\u2500 *\/\nfunction setTipo(tipo){\n  currentTipo = tipo;\n  var bA   = document.getElementById('btnAsal');\n  var bS   = document.getElementById('btnAut');\n  var bAct = document.getElementById('btnAct');\n  [bA, bS, bAct].forEach(function(b){ b.classList.remove('active','green','orange'); });\n  if(tipo === 'asalariado') bA.classList.add('active');\n  if(tipo === 'autonomo')   bS.classList.add('active','green');\n  if(tipo === 'actividad')  bAct.classList.add('active','orange');\n\n  var isAsal = tipo === 'asalariado';\n  var isAut  = tipo === 'autonomo';\n  var isAct  = tipo === 'actividad';\n\n  document.getElementById('sliderLabel').textContent   = isAct ? 'Facturaci\u00f3n anual (bruto)' : isAut ? 'Ingresos brutos anuales' : 'Salario bruto anual';\n  document.getElementById('resTitle').textContent       = isAct ? 'Resultado \u2014 Aut\u00f3nomo con Actividad' : isAut ? 'Resultado \u2014 Aut\u00f3nomo Societario' : 'Resultado \u2014 Asalariado';\n  document.getElementById('r-ss-label').textContent    = isAsal ? 'Cotizaci\u00f3n SS (~6,35%)' : isAut ? 'Cuota SS societario (m\u00edn.)' : 'IRPF retenido en factura (15%)';\n  document.getElementById('r-ss-sub').textContent      = isAut ? '448 \u20ac\/mes \u00b7 base 1.424,60 \u20ac\/mes' : isAct ? 'Pagos a cuenta mod. 130 \/ 131' : '';\n  document.getElementById('r-ss-card').style.background = isAut ? '#fff9e6' : isAct ? '#fff3e0' : '#f4f6fb';\n  document.getElementById('r-ss').style.color           = isAut ? '#b07a00' : isAct ? '#c05c00' : '#1a3fa0';\n  document.getElementById('aut-detalle').style.display  = isAut ? 'block' : 'none';\n  document.getElementById('act-detalle').style.display  = isAct ? 'block' : 'none';\n  document.getElementById('gastos-row').style.display   = isAct ? 'flex' : 'none';\n  document.getElementById('tramos-nota-act').style.display = isAct ? 'block' : 'none';\n  document.querySelector('.metric.accent .metric-label').textContent = isAct ? 'Neto estimado (tras IRPF)' : 'Salario neto estimado';\n\n  render(+document.getElementById('slider').value);\n}\n\n\/* \u2500\u2500 Gastos slider sync \u2500\u2500 *\/\nfunction syncGastos(val){\n  document.getElementById('gastosNum').value = val;\n  render(+document.getElementById('slider').value);\n}\n\n\/* \u2500\u2500 IRPF helpers \u2500\u2500 *\/\nfunction calcIRPF(baseLiq){\n  var cuota = 0;\n  var rows  = [];\n  for(var i = 0; i < tramos.length; i++){\n    var t = tramos[i];\n    if(baseLiq <= t.min) break;\n    var base = Math.min(baseLiq, t.max) - t.min;\n    var c    = base * t.tipo;\n    cuota += c;\n    rows.push({label:t.label, tipo:t.tipo, base:base, cuota:c, color:t.color});\n  }\n  return {cuota: cuota, rows: rows};\n}\n\nfunction redTrabajoArt20(renNeto){\n  if(renNeto <= 14000)   return 6498;\n  if(renNeto <= 19747.5) return 6498 - 1.14286 * (renNeto - 14000);\n  return 0;\n}\n\nfunction getMarginal(baseLiq){\n  for(var i = tramos.length - 1; i >= 0; i--){\n    if(baseLiq > tramos[i].min) return Math.round(tramos[i].tipo * 100);\n  }\n  return 19;\n}\n\nfunction fmt(n){\n  return n.toLocaleString('es-ES', {minimumFractionDigits:0, maximumFractionDigits:0}) + ' \u20ac';\n}\n\n\/* \u2500\u2500 Render principal \u2500\u2500 *\/\nfunction render(bruto){\n  var minFamiliar = calcMinFamiliar();\n  var reds        = calcReducciones();\n  var redConjunta = reds.redConjunta;\n  var redMono     = reds.redMono;\n  var SS_SOCIETARIO = 448 * 12;\n\n  var cuota = 0, neto = 0, baseLiq = 0;\n\n  if(currentTipo === 'asalariado'){\n    var ssAsal  = bruto * 0.0635;\n    var renNeto = bruto - ssAsal - 2000;\n    var red20   = redTrabajoArt20(renNeto);\n    baseLiq = Math.max(0, bruto - ssAsal - 2000 - red20 - redConjunta - redMono);\n    var cBL  = calcIRPF(baseLiq).cuota;\n    var cMin = calcIRPF(Math.min(baseLiq, minFamiliar)).cuota;\n    cuota = Math.max(0, cBL - cMin);\n    neto  = bruto - ssAsal - cuota;\n    document.getElementById('r-ss').textContent = fmt(Math.round(ssAsal));\n\n  } else if(currentTipo === 'autonomo'){\n    baseLiq = Math.max(0, bruto - redConjunta - redMono - 2000);\n    var cBL2  = calcIRPF(baseLiq).cuota;\n    var cMin2 = calcIRPF(Math.min(baseLiq, minFamiliar)).cuota;\n    cuota = Math.max(0, cBL2 - cMin2);\n    neto  = bruto - cuota - SS_SOCIETARIO;\n    document.getElementById('r-ss').textContent = fmt(SS_SOCIETARIO);\n    document.getElementById('d-base').textContent   = fmt(Math.round(bruto));\n    document.getElementById('d-minimo').textContent = '- ' + fmt(minFamiliar);\n    document.getElementById('d-bliq').textContent   = fmt(Math.round(baseLiq));\n    document.getElementById('d-irpf').textContent   = '- ' + fmt(Math.round(cuota));\n    document.getElementById('d-ss').textContent     = '- ' + fmt(SS_SOCIETARIO);\n    document.getElementById('d-neto').textContent   = fmt(Math.round(neto));\n\n  } else {\n    var gastos   = +document.getElementById('gastosSlider').value;\n    var retenido = Math.round(bruto * 0.15);\n    var rendNeto = Math.max(0, bruto - gastos);\n    baseLiq = Math.max(0, rendNeto - redConjunta - redMono);\n    var cBL3  = calcIRPF(baseLiq).cuota;\n    var cMin3 = calcIRPF(Math.min(baseLiq, minFamiliar)).cuota;\n    cuota = Math.max(0, cBL3 - cMin3);\n    neto  = bruto - gastos - cuota;\n    var regularizar = cuota - retenido;\n\n    document.getElementById('r-ss').textContent          = fmt(retenido);\n    document.getElementById('ac-factura').textContent    = fmt(Math.round(bruto));\n    document.getElementById('ac-gastos').textContent     = '- ' + fmt(Math.round(gastos));\n    document.getElementById('ac-redneto').textContent    = fmt(Math.round(rendNeto));\n    document.getElementById('ac-minimo').textContent     = '- ' + fmt(minFamiliar);\n    document.getElementById('ac-bliq').textContent       = fmt(Math.round(baseLiq));\n    document.getElementById('ac-irpftotal').textContent  = fmt(Math.round(cuota));\n    document.getElementById('ac-retenido').textContent   = '- ' + fmt(retenido);\n\n    var totalBlock = document.getElementById('ac-totalblock');\n    var totalVal   = document.getElementById('ac-total');\n    totalBlock.className = 'reg-total ' + (regularizar >= 0 ? 'neg' : 'pos');\n    totalVal.textContent = (regularizar >= 0 ? '\u25b2 A pagar: ' : '\u25bc A devolver: ') + fmt(Math.abs(Math.round(regularizar)));\n  }\n\n  var tef = bruto > 0 ? cuota \/ bruto : 0;\n  document.getElementById('r-cuota').textContent = fmt(Math.round(cuota));\n  document.getElementById('r-tef').textContent   = 'Tipo efectivo ' + (tef * 100).toFixed(1) + '%  \u00b7  Marginal ' + getMarginal(baseLiq) + '%';\n  document.getElementById('r-neto').textContent  = fmt(Math.round(neto));\n  document.getElementById('r-mes').textContent   = fmt(Math.round(neto \/ 12)) + ' \/ mes';\n\n  \/\/ Tramos\n  var rows = calcIRPF(baseLiq).rows;\n  var cont = document.getElementById('tramos-container');\n  cont.innerHTML = '';\n  for(var i = 0; i < tramos.length; i++){\n    var t    = tramos[i];\n    var row  = null;\n    for(var j = 0; j < rows.length; j++){ if(rows[j].label === t.label){ row = rows[j]; break; } }\n    var base = row ? row.base : 0;\n    var ct   = row ? row.cuota : 0;\n    var pct  = bruto > 0 && base > 0 ? Math.min(100, (base \/ bruto) * 100) : 0;\n    var d    = document.createElement('div');\n    d.className = 'tramo-row' + (row ? ' active' : '');\n    d.innerHTML = '<div><div>' + t.label + '<\/div>'\n      + '<div class=\"bar-wrap\"><div class=\"bar-fill\" style=\"width:' + pct.toFixed(1) + '%;background:' + t.color + '\"><\/div><\/div><\/div>'\n      + '<div class=\"tipo-b\">' + Math.round(t.tipo * 100) + '%<\/div>'\n      + '<div class=\"base-v\">' + (base > 0 ? fmt(Math.round(base)) : '\u2014') + '<\/div>'\n      + '<div class=\"cuota-v' + (row ? '' : ' dim') + '\">' + (ct > 0 ? fmt(Math.round(ct)) : '\u2014') + '<\/div>';\n    cont.appendChild(d);\n  }\n}\n\n\/* \u2500\u2500 Event listeners \u2500\u2500 *\/\nvar slider   = document.getElementById('slider');\nvar inputNum = document.getElementById('inputNum');\nslider.addEventListener('input', function(){ inputNum.value = slider.value; render(+slider.value); });\ninputNum.addEventListener('input', function(){\n  var v = Math.max(15000, Math.min(150000, +inputNum.value || 53000));\n  slider.value = v; render(v);\n});\n\nvar gastosSlider = document.getElementById('gastosSlider');\nvar gastosNum    = document.getElementById('gastosNum');\ngastosSlider.addEventListener('input', function(){ gastosNum.value = gastosSlider.value; render(+slider.value); });\ngastosNum.addEventListener('input', function(){\n  var v = Math.max(0, Math.min(80000, +gastosNum.value || 0));\n  gastosSlider.value = v; render(+slider.value);\n});\n\n\/* \u2500\u2500 Init \u2500\u2500 *\/\nupdateHijosDetalle();\nupdateAviso();\nupdateAscDetalle();\nupdateAscAviso();\nrender(53000);\n\n\/* \u2500\u2500 Copy logo to modal \u2500\u2500 *\/\nwindow.addEventListener('load', function(){\n  var src = document.getElementById('logo-img').src;\n  document.getElementById('modal-logo').src = src;\n});\n\n\/* \u2500\u2500 Email modal \u2500\u2500 *\/\nfunction openEmailModal(){\n  document.getElementById('email-overlay').style.display = 'flex';\n  document.getElementById('email-status').textContent = '';\n  document.getElementById('email-input').value = '';\n}\nfunction closeEmailModal(){\n  document.getElementById('email-overlay').style.display = 'none';\n}\n\nfunction buildResumenHTML(){\n  var tipo = currentTipo === 'asalariado' ? 'Asalariado (R\u00e9gimen General)'\n           : currentTipo === 'autonomo'   ? 'Aut\u00f3nomo Societario'\n           : 'Aut\u00f3nomo con Actividad';\n  var civil = {soltero:'Soltero\/a', casado:'Casado\/a', separado:'Separado\/a', mono:'Monoparental'}[currentCivil] || currentCivil;\n  var hijosDesc = currentNHijos === 0 ? 'Sin hijos' : currentNHijos + ' hijo\/s';\n  var minFam = calcMinFamiliar();\n  var bruto = +document.getElementById('slider').value;\n\n  var cuotaEl  = document.getElementById('r-cuota').textContent;\n  var tefEl    = document.getElementById('r-tef').textContent;\n  var netoEl   = document.getElementById('r-neto').textContent;\n  var mesEl    = document.getElementById('r-mes').textContent;\n\n  var extra = '';\n  if(currentTipo === 'actividad'){\n    var reg = document.getElementById('ac-total').textContent;\n    extra = '<tr><td style=\"padding:8px 12px;color:#6b7fa8\">Regularizaci\u00f3n en renta<\/td>'\n          + '<td style=\"padding:8px 12px;font-weight:700;color:#c0392b;text-align:right\">' + reg + '<\/td><\/tr>';\n  }\n  if(currentTipo === 'autonomo'){\n    var neto2 = document.getElementById('d-neto').textContent;\n    extra = '<tr><td style=\"padding:8px 12px;color:#6b7fa8\">Neto final (tras SS)<\/td>'\n          + '<td style=\"padding:8px 12px;font-weight:700;color:#0e7a5a;text-align:right\">' + neto2 + '<\/td><\/tr>';\n  }\n\n  return '<div style=\"font-family:Arial,sans-serif;max-width:600px;margin:0 auto\">'\n    + '<div style=\"background:#1a3fa0;padding:24px 28px;border-radius:10px 10px 0 0\">'\n    + '<h1 style=\"color:#fff;font-size:20px;margin:0\">Simulaci\u00f3n IRPF 2026<\/h1>'\n    + '<p style=\"color:#a0b8f0;font-size:13px;margin:4px 0 0\">GR International Advisors \u00b7 Uso orientativo<\/p>'\n    + '<\/div>'\n    + '<div style=\"background:#f4f6fb;padding:20px 28px;border-radius:0 0 10px 10px\">'\n    + '<table style=\"width:100%;border-collapse:collapse;background:#fff;border-radius:8px;overflow:hidden\">'\n    + '<tr style=\"background:#eef2fc\"><td colspan=\"2\" style=\"padding:10px 12px;font-weight:700;color:#1a3fa0;font-size:13px;text-transform:uppercase;letter-spacing:.05em\">Datos del contribuyente<\/td><\/tr>'\n    + '<tr><td style=\"padding:8px 12px;color:#6b7fa8\">Tipo<\/td><td style=\"padding:8px 12px;font-weight:600;text-align:right\">' + tipo + '<\/td><\/tr>'\n    + '<tr style=\"background:#f8f9fd\"><td style=\"padding:8px 12px;color:#6b7fa8\">Estado civil<\/td><td style=\"padding:8px 12px;font-weight:600;text-align:right\">' + civil + '<\/td><\/tr>'\n    + '<tr><td style=\"padding:8px 12px;color:#6b7fa8\">Hijos<\/td><td style=\"padding:8px 12px;font-weight:600;text-align:right\">' + hijosDesc + '<\/td><\/tr>'\n    + '<tr style=\"background:#f8f9fd\"><td style=\"padding:8px 12px;color:#6b7fa8\">M\u00ednimo personal + familiar<\/td><td style=\"padding:8px 12px;font-weight:600;text-align:right\">' + minFam.toLocaleString('es-ES') + ' \u20ac<\/td><\/tr>'\n    + '<tr><td style=\"padding:8px 12px;color:#6b7fa8\">Bruto \/ Facturaci\u00f3n<\/td><td style=\"padding:8px 12px;font-weight:600;text-align:right\">' + bruto.toLocaleString('es-ES') + ' \u20ac<\/td><\/tr>'\n    + '<tr style=\"background:#eef2fc\"><td colspan=\"2\" style=\"padding:10px 12px;font-weight:700;color:#1a3fa0;font-size:13px;text-transform:uppercase;letter-spacing:.05em\">Resultado<\/td><\/tr>'\n    + '<tr><td style=\"padding:8px 12px;color:#6b7fa8\">Cuota IRPF<\/td><td style=\"padding:8px 12px;font-weight:700;color:#c0392b;text-align:right\">' + cuotaEl + '<\/td><\/tr>'\n    + '<tr style=\"background:#f8f9fd\"><td style=\"padding:8px 12px;color:#6b7fa8\">Tipo efectivo \/ marginal<\/td><td style=\"padding:8px 12px;text-align:right\">' + tefEl + '<\/td><\/tr>'\n    + '<tr><td style=\"padding:8px 12px;color:#6b7fa8\">Neto estimado<\/td><td style=\"padding:8px 12px;font-weight:700;color:#0e7a5a;text-align:right\">' + netoEl + '<\/td><\/tr>'\n    + '<tr style=\"background:#f8f9fd\"><td style=\"padding:8px 12px;color:#6b7fa8\">Neto mensual<\/td><td style=\"padding:8px 12px;font-weight:600;text-align:right\">' + mesEl + '<\/td><\/tr>'\n    + extra\n    + '<\/table>'\n    + '<p style=\"font-size:11px;color:#aabace;margin-top:16px;line-height:1.6\">C\u00e1lculo orientativo basado en escala agregada estatal + auton\u00f3mica media 2026. No incluye deducciones auton\u00f3micas ni circunstancias individuales. Para planificaci\u00f3n fiscal personalizada contacte con GR International Advisors.<\/p>'\n    + '<\/div><\/div>';\n}\n\nfunction enviarEmail(){\n  var email = document.getElementById('email-input').value.trim();\n  var statusEl = document.getElementById('email-status');\n  var sendBtn  = document.getElementById('email-send-btn');\n\n  if(!email || !\/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$\/.test(email)){\n    statusEl.style.color = '#c0392b';\n    statusEl.textContent = 'Por favor introduce un correo v\u00e1lido.';\n    return;\n  }\n\n  sendBtn.disabled = true;\n  sendBtn.textContent = 'Enviando...';\n  statusEl.textContent = '';\n\n  var params = {\n    to_email:     email,\n    email:        email,\n    resumen_html: buildResumenHTML(),\n    name:         email,\n    message:      'Simulaci\u00f3n IRPF 2026 adjunta.'\n  };\n\n  emailjs.send('service_42018cx', 'template_f6gw5u9', params)\n    .then(function(){\n      statusEl.style.color = '#0e7a5a';\n      statusEl.innerHTML = '\u2714 Email enviado correctamente a <strong>' + email + '<\/strong>';\n      sendBtn.textContent = '\u2714 Enviado';\n      sendBtn.style.background = '#0e7a5a';\n      setTimeout(function(){ closeEmailModal(); sendBtn.disabled=false; sendBtn.textContent='\ud83d\udce7 Enviar simulaci\u00f3n'; sendBtn.style.background='#1a3fa0'; }, 3000);\n    }, function(err){\n      statusEl.style.color = '#c0392b';\n      statusEl.textContent = 'Error al enviar: ' + (err.text || JSON.stringify(err));\n      sendBtn.disabled = false;\n      sendBtn.textContent = '\ud83d\udce7 Enviar simulaci\u00f3n';\n    });\n}\n\n\/* Close modal clicking outside *\/\ndocument.getElementById('email-overlay').addEventListener('click', function(e){\n  if(e.target === this) closeEmailModal();\n});\n<\/script>\t\t\t\t\t\t\t\t<\/div>\n\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-1fed1c3 e-flex e-con-boxed e-con e-parent\" data-id=\"1fed1c3\" data-element_type=\"container\" data-e-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<div class=\"elementor-element elementor-element-233dd7a e-flex e-con-boxed e-con e-parent\" data-id=\"233dd7a\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-89c9bca elementor-widget elementor-widget-html\" data-id=\"89c9bca\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<script src=\"https:\/\/cdn.jsdelivr.net\/npm\/@emailjs\/browser@4\/dist\/email.min.js\"><\/script>\n<script>emailjs.init(\"JO_d2UP9OhEX5JVTu\");<\/script>\n\n<script>\nconst tramos = [\n  {min:0,      max:12450,   tipo:.19, label:\"0 \u2013 12.450 \u20ac\",       color:\"#1aaa7a\"},\n  {min:12450,  max:20200,   tipo:.24, label:\"12.450 \u2013 20.200 \u20ac\",  color:\"#1a5fe0\"},\n  {min:20200,  max:35200,   tipo:.30, label:\"20.200 \u2013 35.200 \u20ac\",  color:\"#7f77dd\"},\n  {min:35200,  max:60000,   tipo:.37, label:\"35.200 \u2013 60.000 \u20ac\",  color:\"#e08a1a\"},\n  {min:60000,  max:300000,  tipo:.45, label:\"60.000 \u2013 300.000 \u20ac\", color:\"#d85a30\"},\n  {min:300000, max:Infinity,tipo:.47, label:\"M\u00e1s de 300.000 \u20ac\",   color:\"#a32d2d\"},\n];\n\nconst MINS_HIJO = [2400, 2700, 4000, 4500]; \/\/ index 0=1er hijo ... 3+=4o\n\nlet currentCivil  = 'soltero';\nlet currentNHijos = 0;\nlet hijosState    = [];\nlet currentTipo   = 'asalariado';\n\n\/* \u2500\u2500 Estado civil \u2500\u2500 *\/\nfunction setCivil(btn){\n  document.querySelectorAll('#civil-btns .sit-btn').forEach(function(b){ b.classList.remove('active'); });\n  btn.classList.add('active');\n  currentCivil = btn.dataset.civil;\n  updateHijosDetalle();\n  updateAviso();\n  render(+document.getElementById('slider').value);\n}\n\n\/* \u2500\u2500 N\u00famero de hijos \u2500\u2500 *\/\nfunction setNHijos(btn){\n  document.querySelectorAll('#nhijos-btns .sit-btn').forEach(function(b){ b.classList.remove('active'); });\n  btn.classList.add('active');\n  var n = btn.dataset.n === '4' ? 4 : +btn.dataset.n;\n  currentNHijos = n;\n  while(hijosState.length < n) hijosState.push({ok: true});\n  hijosState = hijosState.slice(0, n);\n  updateHijosDetalle();\n  updateAviso();\n  render(+document.getElementById('slider').value);\n}\n\n\/* \u2500\u2500 Toggle requisito por hijo \u2500\u2500 *\/\nfunction toggleHijoOk(idx){\n  hijosState[idx].ok = !hijosState[idx].ok;\n  var btn = document.getElementById('hijo-ok-btn-' + idx);\n  applyHijoBtnStyle(btn, hijosState[idx].ok);\n  updateAviso();\n  render(+document.getElementById('slider').value);\n}\n\nfunction applyHijoBtnStyle(btn, ok){\n  btn.textContent   = ok ? '\u2714 Cumple requisitos' : '\u2717 No cumple';\n  btn.style.background  = ok ? '#e6f7f0' : '#fde8e8';\n  btn.style.color       = ok ? '#0e7a5a' : '#c0392b';\n  btn.style.borderColor = ok ? '#9edfc8' : '#f5b8b8';\n}\n\n\/* \u2500\u2500 Render tarjetas de hijos \u2500\u2500 *\/\nfunction updateHijosDetalle(){\n  var cont = document.getElementById('hijos-detalle');\n  cont.innerHTML = '';\n  if(currentNHijos === 0) return;\n  var labels = ['1.er hijo','2.\u00ba hijo','3.er hijo','4.\u00ba hijo'];\n  var wrap = document.createElement('div');\n  wrap.style.cssText = 'margin-bottom:10px;display:flex;flex-wrap:wrap;gap:8px';\n  for(var i = 0; i < currentNHijos; i++){\n    var ok  = hijosState[i] ? hijosState[i].ok : true;\n    var lbl = i < 4 ? labels[i] : (i+1)+'.\u00ba hijo';\n    var min = i < 3 ? MINS_HIJO[i] : MINS_HIJO[3];\n    var card = document.createElement('div');\n    card.style.cssText = 'border:1px solid #dde3f0;border-radius:9px;padding:8px 12px;background:#f8f9fd;min-width:140px;flex:1';\n    var title = document.createElement('div');\n    title.style.cssText = 'font-size:11px;color:#8fa0c8;font-weight:700;text-transform:uppercase;letter-spacing:.05em;margin-bottom:5px';\n    title.textContent = lbl + ' \u00b7 ' + min.toLocaleString('es-ES') + ' \u20ac';\n    var obtn = document.createElement('button');\n    obtn.id = 'hijo-ok-btn-' + i;\n    obtn.style.cssText = 'width:100%;padding:5px 8px;border-radius:6px;border:1px solid;cursor:pointer;font-size:12px;font-weight:600;transition:all .2s';\n    obtn.setAttribute('data-idx', i);\n    obtn.addEventListener('click', (function(idx){ return function(){ toggleHijoOk(idx); }; })(i));\n    applyHijoBtnStyle(obtn, ok);\n    var hint = document.createElement('div');\n    hint.style.cssText = 'font-size:10px;color:#8fa0c8;margin-top:4px;line-height:1.4';\n    hint.textContent = '<25 a. y rentas <8.000 \u20ac';\n    card.appendChild(title);\n    card.appendChild(obtn);\n    card.appendChild(hint);\n    wrap.appendChild(card);\n  }\n  cont.appendChild(wrap);\n}\n\n\/* \u2500\u2500 Aviso resumen hijos \u2500\u2500 *\/\nfunction updateAviso(){\n  var el = document.getElementById('hijo-aviso');\n  if(currentNHijos === 0){ el.style.display = 'none'; return; }\n  var okCount = hijosState.filter(function(h){ return h.ok; }).length;\n  var noCount = currentNHijos - okCount;\n  var total = 0;\n  for(var i = 0; i < currentNHijos; i++){\n    if(hijosState[i] && hijosState[i].ok) total += i < 3 ? MINS_HIJO[i] : MINS_HIJO[3];\n  }\n  var fmtTotal = total.toLocaleString('es-ES');\n  var msg = '';\n  if(okCount > 0 && noCount === 0){\n    el.style.background = '#e6f7f0'; el.style.color = '#0e7a5a';\n    msg = '<strong>\u2714 M\u00ednimo por descendientes aplicado: ' + fmtTotal + ' \u20ac<\/strong> \u2014 ' + okCount + ' hijo\/s cumplen requisitos (art. 58 LIRPF).';\n  } else if(okCount === 0){\n    el.style.background = '#fde8e8'; el.style.color = '#c0392b';\n    msg = '<strong>\u2717 Ning\u00fan hijo cumple los requisitos<\/strong> \u2014 m\u00ednimo 0 \u20ac. Todos tienen \u226525 a\u00f1os o rentas \u22658.000 \u20ac.';\n  } else {\n    el.style.background = '#fff9e6'; el.style.color = '#b07a00';\n    msg = '<strong>\u26a0 M\u00ednimo parcial: ' + fmtTotal + ' \u20ac<\/strong> \u2014 ' + okCount + ' cumplen, ' + noCount + ' no cumplen (\u226525 a. o \u22658.000 \u20ac).';\n  }\n  el.style.display = 'block';\n  el.innerHTML = msg;\n}\n\n\/* \u2500\u2500 C\u00e1lculo m\u00ednimo familiar \u2500\u2500 *\/\nfunction calcMinFamiliar(){\n  var total = 5550;\n  for(var i = 0; i < currentNHijos; i++){\n    if(hijosState[i] && hijosState[i].ok) total += i < 3 ? MINS_HIJO[i] : MINS_HIJO[3];\n  }\n  return total;\n}\n\nfunction calcReducciones(){\n  var redConjunta = currentCivil === 'casado' ? 3400 : 0;\n  var redMono     = (currentCivil === 'separado' || currentCivil === 'mono') ? 2150 : 0;\n  return {redConjunta: redConjunta, redMono: redMono};\n}\n\n\/* \u2500\u2500 Tipo de contribuyente \u2500\u2500 *\/\nfunction setTipo(tipo){\n  currentTipo = tipo;\n  var bA   = document.getElementById('btnAsal');\n  var bS   = document.getElementById('btnAut');\n  var bAct = document.getElementById('btnAct');\n  [bA, bS, bAct].forEach(function(b){ b.classList.remove('active','green','orange'); });\n  if(tipo === 'asalariado') bA.classList.add('active');\n  if(tipo === 'autonomo')   bS.classList.add('active','green');\n  if(tipo === 'actividad')  bAct.classList.add('active','orange');\n\n  var isAsal = tipo === 'asalariado';\n  var isAut  = tipo === 'autonomo';\n  var isAct  = tipo === 'actividad';\n\n  document.getElementById('sliderLabel').textContent   = isAct ? 'Facturaci\u00f3n anual (bruto)' : isAut ? 'Ingresos brutos anuales' : 'Salario bruto anual';\n  document.getElementById('resTitle').textContent       = isAct ? 'Resultado \u2014 Aut\u00f3nomo con Actividad' : isAut ? 'Resultado \u2014 Aut\u00f3nomo Societario' : 'Resultado \u2014 Asalariado';\n  document.getElementById('r-ss-label').textContent    = isAsal ? 'Cotizaci\u00f3n SS (~6,35%)' : isAut ? 'Cuota SS societario (m\u00edn.)' : 'IRPF retenido en factura (15%)';\n  document.getElementById('r-ss-sub').textContent      = isAut ? '448 \u20ac\/mes \u00b7 base 1.424,60 \u20ac\/mes' : isAct ? 'Pagos a cuenta mod. 130 \/ 131' : '';\n  document.getElementById('r-ss-card').style.background = isAut ? '#fff9e6' : isAct ? '#fff3e0' : '#f4f6fb';\n  document.getElementById('r-ss').style.color           = isAut ? '#b07a00' : isAct ? '#c05c00' : '#1a3fa0';\n  document.getElementById('aut-detalle').style.display  = isAut ? 'block' : 'none';\n  document.getElementById('act-detalle').style.display  = isAct ? 'block' : 'none';\n  document.getElementById('gastos-row').style.display   = isAct ? 'flex' : 'none';\n  document.getElementById('tramos-nota-act').style.display = isAct ? 'block' : 'none';\n  document.querySelector('.metric.accent .metric-label').textContent = isAct ? 'Neto estimado (tras IRPF)' : 'Salario neto estimado';\n\n  render(+document.getElementById('slider').value);\n}\n\n\/* \u2500\u2500 Gastos slider sync \u2500\u2500 *\/\nfunction syncGastos(val){\n  document.getElementById('gastosNum').value = val;\n  render(+document.getElementById('slider').value);\n}\n\n\/* \u2500\u2500 IRPF helpers \u2500\u2500 *\/\nfunction calcIRPF(baseLiq){\n  var cuota = 0;\n  var rows  = [];\n  for(var i = 0; i < tramos.length; i++){\n    var t = tramos[i];\n    if(baseLiq <= t.min) break;\n    var base = Math.min(baseLiq, t.max) - t.min;\n    var c    = base * t.tipo;\n    cuota += c;\n    rows.push({label:t.label, tipo:t.tipo, base:base, cuota:c, color:t.color});\n  }\n  return {cuota: cuota, rows: rows};\n}\n\nfunction redTrabajoArt20(renNeto){\n  if(renNeto <= 14000)   return 6498;\n  if(renNeto <= 19747.5) return 6498 - 1.14286 * (renNeto - 14000);\n  return 0;\n}\n\nfunction getMarginal(baseLiq){\n  for(var i = tramos.length - 1; i >= 0; i--){\n    if(baseLiq > tramos[i].min) return Math.round(tramos[i].tipo * 100);\n  }\n  return 19;\n}\n\nfunction fmt(n){\n  return n.toLocaleString('es-ES', {minimumFractionDigits:0, maximumFractionDigits:0}) + ' \u20ac';\n}\n\n\/* \u2500\u2500 Render principal \u2500\u2500 *\/\nfunction render(bruto){\n  var minFamiliar = calcMinFamiliar();\n  var reds        = calcReducciones();\n  var redConjunta = reds.redConjunta;\n  var redMono     = reds.redMono;\n  var SS_SOCIETARIO = 448 * 12;\n\n  var cuota = 0, neto = 0, baseLiq = 0;\n\n  if(currentTipo === 'asalariado'){\n    var ssAsal  = bruto * 0.0635;\n    var renNeto = bruto - ssAsal - 2000;\n    var red20   = redTrabajoArt20(renNeto);\n    baseLiq = Math.max(0, bruto - ssAsal - 2000 - red20 - redConjunta - redMono);\n    var cBL  = calcIRPF(baseLiq).cuota;\n    var cMin = calcIRPF(Math.min(baseLiq, minFamiliar)).cuota;\n    cuota = Math.max(0, cBL - cMin);\n    neto  = bruto - ssAsal - cuota;\n    document.getElementById('r-ss').textContent = fmt(Math.round(ssAsal));\n\n  } else if(currentTipo === 'autonomo'){\n    baseLiq = Math.max(0, bruto - redConjunta - redMono - 2000);\n    var cBL2  = calcIRPF(baseLiq).cuota;\n    var cMin2 = calcIRPF(Math.min(baseLiq, minFamiliar)).cuota;\n    cuota = Math.max(0, cBL2 - cMin2);\n    neto  = bruto - cuota - SS_SOCIETARIO;\n    document.getElementById('r-ss').textContent = fmt(SS_SOCIETARIO);\n    document.getElementById('d-base').textContent   = fmt(Math.round(bruto));\n    document.getElementById('d-minimo').textContent = '- ' + fmt(minFamiliar);\n    document.getElementById('d-bliq').textContent   = fmt(Math.round(baseLiq));\n    document.getElementById('d-irpf').textContent   = '- ' + fmt(Math.round(cuota));\n    document.getElementById('d-ss').textContent     = '- ' + fmt(SS_SOCIETARIO);\n    document.getElementById('d-neto').textContent   = fmt(Math.round(neto));\n\n  } else {\n    var gastos   = +document.getElementById('gastosSlider').value;\n    var retenido = Math.round(bruto * 0.15);\n    var rendNeto = Math.max(0, bruto - gastos);\n    baseLiq = Math.max(0, rendNeto - redConjunta - redMono);\n    var cBL3  = calcIRPF(baseLiq).cuota;\n    var cMin3 = calcIRPF(Math.min(baseLiq, minFamiliar)).cuota;\n    cuota = Math.max(0, cBL3 - cMin3);\n    neto  = bruto - gastos - cuota;\n    var regularizar = cuota - retenido;\n\n    document.getElementById('r-ss').textContent          = fmt(retenido);\n    document.getElementById('ac-factura').textContent    = fmt(Math.round(bruto));\n    document.getElementById('ac-gastos').textContent     = '- ' + fmt(Math.round(gastos));\n    document.getElementById('ac-redneto').textContent    = fmt(Math.round(rendNeto));\n    document.getElementById('ac-minimo').textContent     = '- ' + fmt(minFamiliar);\n    document.getElementById('ac-bliq').textContent       = fmt(Math.round(baseLiq));\n    document.getElementById('ac-irpftotal').textContent  = fmt(Math.round(cuota));\n    document.getElementById('ac-retenido').textContent   = '- ' + fmt(retenido);\n\n    var totalBlock = document.getElementById('ac-totalblock');\n    var totalVal   = document.getElementById('ac-total');\n    totalBlock.className = 'reg-total ' + (regularizar >= 0 ? 'neg' : 'pos');\n    totalVal.textContent = (regularizar >= 0 ? '\u25b2 A pagar: ' : '\u25bc A devolver: ') + fmt(Math.abs(Math.round(regularizar)));\n  }\n\n  var tef = bruto > 0 ? cuota \/ bruto : 0;\n  document.getElementById('r-cuota').textContent = fmt(Math.round(cuota));\n  document.getElementById('r-tef').textContent   = 'Tipo efectivo ' + (tef * 100).toFixed(1) + '%  \u00b7  Marginal ' + getMarginal(baseLiq) + '%';\n  document.getElementById('r-neto').textContent  = fmt(Math.round(neto));\n  document.getElementById('r-mes').textContent   = fmt(Math.round(neto \/ 12)) + ' \/ mes';\n\n  \/\/ Tramos\n  var rows = calcIRPF(baseLiq).rows;\n  var cont = document.getElementById('tramos-container');\n  cont.innerHTML = '';\n  for(var i = 0; i < tramos.length; i++){\n    var t    = tramos[i];\n    var row  = null;\n    for(var j = 0; j < rows.length; j++){ if(rows[j].label === t.label){ row = rows[j]; break; } }\n    var base = row ? row.base : 0;\n    var ct   = row ? row.cuota : 0;\n    var pct  = bruto > 0 && base > 0 ? Math.min(100, (base \/ bruto) * 100) : 0;\n    var d    = document.createElement('div');\n    d.className = 'tramo-row' + (row ? ' active' : '');\n    d.innerHTML = '<div><div>' + t.label + '<\/div>'\n      + '<div class=\"bar-wrap\"><div class=\"bar-fill\" style=\"width:' + pct.toFixed(1) + '%;background:' + t.color + '\"><\/div><\/div><\/div>'\n      + '<div class=\"tipo-b\">' + Math.round(t.tipo * 100) + '%<\/div>'\n      + '<div class=\"base-v\">' + (base > 0 ? fmt(Math.round(base)) : '\u2014') + '<\/div>'\n      + '<div class=\"cuota-v' + (row ? '' : ' dim') + '\">' + (ct > 0 ? fmt(Math.round(ct)) : '\u2014') + '<\/div>';\n    cont.appendChild(d);\n  }\n}\n\n\/* \u2500\u2500 Event listeners \u2500\u2500 *\/\nvar slider   = document.getElementById('slider');\nvar inputNum = document.getElementById('inputNum');\nslider.addEventListener('input', function(){ inputNum.value = slider.value; render(+slider.value); });\ninputNum.addEventListener('input', function(){\n  var v = Math.max(15000, Math.min(150000, +inputNum.value || 53000));\n  slider.value = v; render(v);\n});\n\nvar gastosSlider = document.getElementById('gastosSlider');\nvar gastosNum    = document.getElementById('gastosNum');\ngastosSlider.addEventListener('input', function(){ gastosNum.value = gastosSlider.value; render(+slider.value); });\ngastosNum.addEventListener('input', function(){\n  var v = Math.max(0, Math.min(80000, +gastosNum.value || 0));\n  gastosSlider.value = v; render(+slider.value);\n});\n\n\/* \u2500\u2500 Init \u2500\u2500 *\/\nupdateHijosDetalle();\nupdateAviso();\nrender(53000);\n\n\/* \u2500\u2500 Copy logo to modal \u2500\u2500 *\/\nwindow.addEventListener('load', function(){\n  var src = document.getElementById('logo-img').src;\n  document.getElementById('modal-logo').src = src;\n});\n\n\/* \u2500\u2500 Email modal \u2500\u2500 *\/\nfunction openEmailModal(){\n  document.getElementById('email-overlay').style.display = 'flex';\n  document.getElementById('email-status').textContent = '';\n  document.getElementById('email-input').value = '';\n}\nfunction closeEmailModal(){\n  document.getElementById('email-overlay').style.display = 'none';\n}\n\nfunction buildResumenHTML(){\n  var tipo = currentTipo === 'asalariado' ? 'Asalariado (R\u00e9gimen General)'\n           : currentTipo === 'autonomo'   ? 'Aut\u00f3nomo Societario'\n           : 'Aut\u00f3nomo con Actividad';\n  var civil = {soltero:'Soltero\/a', casado:'Casado\/a', separado:'Separado\/a', mono:'Monoparental'}[currentCivil] || currentCivil;\n  var hijosDesc = currentNHijos === 0 ? 'Sin hijos' : currentNHijos + ' hijo\/s';\n  var minFam = calcMinFamiliar();\n  var bruto = +document.getElementById('slider').value;\n\n  var cuotaEl  = document.getElementById('r-cuota').textContent;\n  var tefEl    = document.getElementById('r-tef').textContent;\n  var netoEl   = document.getElementById('r-neto').textContent;\n  var mesEl    = document.getElementById('r-mes').textContent;\n\n  var extra = '';\n  if(currentTipo === 'actividad'){\n    var reg = document.getElementById('ac-total').textContent;\n    extra = '<tr><td style=\"padding:8px 12px;color:#6b7fa8\">Regularizaci\u00f3n en renta<\/td>'\n          + '<td style=\"padding:8px 12px;font-weight:700;color:#c0392b;text-align:right\">' + reg + '<\/td><\/tr>';\n  }\n  if(currentTipo === 'autonomo'){\n    var neto2 = document.getElementById('d-neto').textContent;\n    extra = '<tr><td style=\"padding:8px 12px;color:#6b7fa8\">Neto final (tras SS)<\/td>'\n          + '<td style=\"padding:8px 12px;font-weight:700;color:#0e7a5a;text-align:right\">' + neto2 + '<\/td><\/tr>';\n  }\n\n  return '<div style=\"font-family:Arial,sans-serif;max-width:600px;margin:0 auto\">'\n    + '<div style=\"background:#1a3fa0;padding:24px 28px;border-radius:10px 10px 0 0\">'\n    + '<h1 style=\"color:#fff;font-size:20px;margin:0\">Simulaci\u00f3n IRPF 2026<\/h1>'\n    + '<p style=\"color:#a0b8f0;font-size:13px;margin:4px 0 0\">GR International Advisors \u00b7 Uso orientativo<\/p>'\n    + '<\/div>'\n    + '<div style=\"background:#f4f6fb;padding:20px 28px;border-radius:0 0 10px 10px\">'\n    + '<table style=\"width:100%;border-collapse:collapse;background:#fff;border-radius:8px;overflow:hidden\">'\n    + '<tr style=\"background:#eef2fc\"><td colspan=\"2\" style=\"padding:10px 12px;font-weight:700;color:#1a3fa0;font-size:13px;text-transform:uppercase;letter-spacing:.05em\">Datos del contribuyente<\/td><\/tr>'\n    + '<tr><td style=\"padding:8px 12px;color:#6b7fa8\">Tipo<\/td><td style=\"padding:8px 12px;font-weight:600;text-align:right\">' + tipo + '<\/td><\/tr>'\n    + '<tr style=\"background:#f8f9fd\"><td style=\"padding:8px 12px;color:#6b7fa8\">Estado civil<\/td><td style=\"padding:8px 12px;font-weight:600;text-align:right\">' + civil + '<\/td><\/tr>'\n    + '<tr><td style=\"padding:8px 12px;color:#6b7fa8\">Hijos<\/td><td style=\"padding:8px 12px;font-weight:600;text-align:right\">' + hijosDesc + '<\/td><\/tr>'\n    + '<tr style=\"background:#f8f9fd\"><td style=\"padding:8px 12px;color:#6b7fa8\">M\u00ednimo personal + familiar<\/td><td style=\"padding:8px 12px;font-weight:600;text-align:right\">' + minFam.toLocaleString('es-ES') + ' \u20ac<\/td><\/tr>'\n    + '<tr><td style=\"padding:8px 12px;color:#6b7fa8\">Bruto \/ Facturaci\u00f3n<\/td><td style=\"padding:8px 12px;font-weight:600;text-align:right\">' + bruto.toLocaleString('es-ES') + ' \u20ac<\/td><\/tr>'\n    + '<tr style=\"background:#eef2fc\"><td colspan=\"2\" style=\"padding:10px 12px;font-weight:700;color:#1a3fa0;font-size:13px;text-transform:uppercase;letter-spacing:.05em\">Resultado<\/td><\/tr>'\n    + '<tr><td style=\"padding:8px 12px;color:#6b7fa8\">Cuota IRPF<\/td><td style=\"padding:8px 12px;font-weight:700;color:#c0392b;text-align:right\">' + cuotaEl + '<\/td><\/tr>'\n    + '<tr style=\"background:#f8f9fd\"><td style=\"padding:8px 12px;color:#6b7fa8\">Tipo efectivo \/ marginal<\/td><td style=\"padding:8px 12px;text-align:right\">' + tefEl + '<\/td><\/tr>'\n    + '<tr><td style=\"padding:8px 12px;color:#6b7fa8\">Neto estimado<\/td><td style=\"padding:8px 12px;font-weight:700;color:#0e7a5a;text-align:right\">' + netoEl + '<\/td><\/tr>'\n    + '<tr style=\"background:#f8f9fd\"><td style=\"padding:8px 12px;color:#6b7fa8\">Neto mensual<\/td><td style=\"padding:8px 12px;font-weight:600;text-align:right\">' + mesEl + '<\/td><\/tr>'\n    + extra\n    + '<\/table>'\n    + '<p style=\"font-size:11px;color:#aabace;margin-top:16px;line-height:1.6\">C\u00e1lculo orientativo basado en escala agregada estatal + auton\u00f3mica media 2026. No incluye deducciones auton\u00f3micas ni circunstancias individuales. Para planificaci\u00f3n fiscal personalizada contacte con GR International Advisors.<\/p>'\n    + '<\/div><\/div>';\n}\n\nfunction enviarEmail(){\n  var email = document.getElementById('email-input').value.trim();\n  var statusEl = document.getElementById('email-status');\n  var sendBtn  = document.getElementById('email-send-btn');\n\n  if(!email || !\/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$\/.test(email)){\n    statusEl.style.color = '#c0392b';\n    statusEl.textContent = 'Por favor introduce un correo v\u00e1lido.';\n    return;\n  }\n\n  sendBtn.disabled = true;\n  sendBtn.textContent = 'Enviando...';\n  statusEl.textContent = '';\n\n  var params = {\n    to_email:     email,\n    email:        email,\n    resumen_html: buildResumenHTML(),\n    name:         email,\n    message:      'Simulaci\u00f3n IRPF 2026 adjunta.'\n  };\n\n  emailjs.send('service_42018cx', 'template_f6gw5u9', params)\n    .then(function(){\n      statusEl.style.color = '#0e7a5a';\n      statusEl.innerHTML = '\u2714 Email enviado correctamente a <strong>' + email + '<\/strong>';\n      sendBtn.textContent = '\u2714 Enviado';\n      sendBtn.style.background = '#0e7a5a';\n      setTimeout(function(){ closeEmailModal(); sendBtn.disabled=false; sendBtn.textContent='\ud83d\udce7 Enviar simulaci\u00f3n'; sendBtn.style.background='#1a3fa0'; }, 3000);\n    }, function(err){\n      statusEl.style.color = '#c0392b';\n      statusEl.textContent = 'Error al enviar: ' + (err.text || JSON.stringify(err));\n      sendBtn.disabled = false;\n      sendBtn.textContent = '\ud83d\udce7 Enviar simulaci\u00f3n';\n    });\n}\n\n\/* Close modal clicking outside *\/\ndocument.getElementById('email-overlay').addEventListener('click', function(e){\n  if(e.target === this) closeEmailModal();\n});\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\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>Tipo de contribuyente \ud83d\udc54 Employee \ud83c\udfe2 Self-employed (company) \ud83e\uddfe Self-employed (active) Personal and family circumstances Marital status \ud83d\udc64 Single \ud83d\udc6b Married \u2696\ufe0f Separated \ud83c\udfe0 Single parent Number of children 0 1 2 3 4+ Dependent ascendants (parents\/grandparents) 0 1 2+ Deductible expenses \u20ac Gross annual salary \u20ac Result \u2014 Employee Income tax liability \u2014 \u2014 [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"inline_featured_image":false,"footnotes":""},"class_list":["post-6337","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/grinternationaladvisors.com\/en\/wp-json\/wp\/v2\/pages\/6337","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/grinternationaladvisors.com\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/grinternationaladvisors.com\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/grinternationaladvisors.com\/en\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/grinternationaladvisors.com\/en\/wp-json\/wp\/v2\/comments?post=6337"}],"version-history":[{"count":1,"href":"https:\/\/grinternationaladvisors.com\/en\/wp-json\/wp\/v2\/pages\/6337\/revisions"}],"predecessor-version":[{"id":6338,"href":"https:\/\/grinternationaladvisors.com\/en\/wp-json\/wp\/v2\/pages\/6337\/revisions\/6338"}],"wp:attachment":[{"href":"https:\/\/grinternationaladvisors.com\/en\/wp-json\/wp\/v2\/media?parent=6337"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}