{"id":984,"date":"2026-04-01T15:59:05","date_gmt":"2026-04-01T13:59:05","guid":{"rendered":"https:\/\/torreshospitalityconsulting.com\/?page_id=984"},"modified":"2026-04-23T13:36:24","modified_gmt":"2026-04-23T11:36:24","slug":"calculator","status":"publish","type":"page","link":"https:\/\/torreshospitalityconsulting.com\/en\/calculator\/","title":{"rendered":"Hotel Ancillary Calculator"},"content":{"rendered":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\"\/>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"\/>\n  <title>Front Desk Upsell Calculator | Torres Hospitality Consulting<\/title>\n  <style>\n    *,*::before,*::after{box-sizing:border-box;margin:0;padding:0}\n    :root{\n      --red:#c0392b;--red-light:#fdf1f0;--red-mid:#f0c4c0;\n      --black:#1a1a1a;--dark:#2c2c2c;--muted:#888;\n      --border:#e8e8e8;--border-mid:#d0d0d0;--bg:#f7f7f7;--white:#fff;\n      --font:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif;\n    }\n    html{font-size:16px}\n    body{font-family:var(--font);color:var(--black);background:#f4f4f2;min-height:100vh;padding:3rem 1rem}\n    .wrap{max-width:900px;margin:0 auto;background:var(--white);border-radius:12px;padding:2.5rem 2.5rem 3rem;box-shadow:0 2px 24px rgba(0,0,0,.07)}\n    @media(max-width:600px){body{padding:1rem .5rem}.wrap{padding:1.25rem 1rem 2rem;border-radius:8px}}\n\n    \/* HEADER *\/\n    .hdr{margin-bottom:1.75rem}\n    .hdr-eye{display:flex;align-items:center;gap:10px;margin-bottom:.75rem}\n    .hdr-line{width:28px;height:2px;background:var(--red)}\n    .hdr-brand{font-size:10px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:var(--muted)}\n    .hdr-title{font-size:26px;font-weight:700;line-height:1.2;margin-bottom:.5rem}\n    .hdr-title span{color:var(--red)}\n    .hdr-sub{font-size:13px;color:var(--muted);line-height:1.7;max-width:560px}\n\n    \/* PILL *\/\n    .pill-group{display:flex;gap:5px;flex-wrap:wrap}\n    .pill{padding:5px 12px;font-size:12px;font-family:var(--font);border:1px solid var(--border-mid);border-radius:20px;background:transparent;color:var(--muted);cursor:pointer;transition:all .15s;white-space:nowrap}\n    .pill:hover{border-color:var(--black);color:var(--black)}\n    .pill.active{background:var(--black);color:#fff;border-color:var(--black);font-weight:500}\n\n    \/* TOP CONTROLS *\/\n    .top-ctrl{display:flex;align-items:flex-start;justify-content:space-between;flex-wrap:wrap;gap:12px;margin-bottom:1.25rem}\n\n    \/* HOTEL TYPE TABS *\/\n    .type-tabs{display:flex;border:1px solid var(--border-mid);border-radius:8px;overflow:hidden;margin-bottom:1.5rem}\n    .type-tab{flex:1;padding:10px 16px;font-size:13px;font-weight:600;font-family:var(--font);border:none;background:transparent;color:var(--muted);cursor:pointer;transition:all .15s;display:flex;align-items:center;justify-content:center;gap:7px}\n    .type-tab:not(:last-child){border-right:1px solid var(--border-mid)}\n    .type-tab:hover{background:var(--bg);color:var(--black)}\n    .type-tab.active{background:var(--black);color:#fff}\n    .tab-icon{font-size:16px}\n\n    \/* SECTION EYE *\/\n    .sec-eye{display:flex;align-items:center;gap:8px;margin-bottom:.85rem;margin-top:.25rem}\n    .sec-line{width:18px;height:2px;background:var(--red);flex-shrink:0}\n    .sec-lbl{font-size:10px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}\n\n    \/* HOTEL DATA *\/\n    .inp-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px;margin-bottom:1.75rem}\n    @media(max-width:580px){.inp-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}\n    .inp-card{background:var(--bg);border:1px solid var(--border);border-radius:8px;padding:.85rem 1rem}\n    .inp-card label{font-size:10px;text-transform:uppercase;letter-spacing:.08em;color:var(--muted);display:block;margin-bottom:8px;font-weight:500}\n    .inp-wrap{display:flex;align-items:baseline;justify-content:space-between;border-bottom:1.5px solid var(--border-mid);padding-bottom:4px}\n    .inp-wrap input[type=number]{font-size:20px;font-weight:700;color:var(--black);background:transparent;border:none;outline:none;width:100%;font-family:var(--font)}\n    .inp-wrap:focus-within{border-bottom-color:var(--red)}\n    .inp-unit{font-size:12px;color:var(--muted);white-space:nowrap;flex-shrink:0;padding-left:4px}\n    .inp-hint{font-size:10px;color:var(--muted);margin-top:5px}\n\n    .divider{height:1px;background:var(--border);margin:1.75rem 0}\n\n    \/* OFFERS *\/\n    .off-intro{font-size:12px;color:var(--muted);margin-bottom:1rem;line-height:1.7}\n    .off-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:8px;margin-bottom:.75rem}\n\n    .off-card{border:1px solid var(--border);border-radius:8px;background:var(--white);overflow:hidden;transition:border-color .15s}\n    .off-card.on{border-color:var(--red)}\n    .off-hdr{display:flex;align-items:center;justify-content:space-between;padding:10px 12px;cursor:pointer;user-select:none}\n    .off-name{font-size:13px;font-weight:500;color:var(--dark)}\n    .off-card.on .off-name{color:var(--red)}\n\n\n\n    .off-tog{width:30px;height:17px;border-radius:9px;background:var(--border-mid);position:relative;transition:background .2s;flex-shrink:0;pointer-events:none}\n    .off-tog::after{content:'';position:absolute;width:13px;height:13px;border-radius:50%;background:#fff;top:2px;left:2px;transition:left .2s;box-shadow:0 1px 3px rgba(0,0,0,.2)}\n    .off-card.on .off-tog{background:var(--red)}\n    .off-card.on .off-tog::after{left:15px}\n\n    .off-flds{display:none;padding:0 12px 12px;border-top:1px solid var(--border)}\n    .off-card.on .off-flds{display:block}\n\n    .freq-row{display:flex;gap:4px;margin-top:10px}\n    .freq-btn{flex:1;padding:5px 4px;font-size:10px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;font-family:var(--font);border:1px solid var(--border-mid);border-radius:4px;background:transparent;color:var(--muted);cursor:pointer;transition:all .15s;text-align:center}\n    .freq-btn:hover{border-color:var(--black);color:var(--black)}\n    .freq-btn.active{background:var(--red);color:#fff;border-color:var(--red)}\n\n    .fld-row{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:8px}\n    .fld-wrap label{font-size:10px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted);display:block;margin-bottom:4px;font-weight:500}\n\n    .inp-prefix-wrap{display:flex;align-items:center;background:var(--bg);border:1px solid var(--border);border-radius:5px;transition:border-color .15s;overflow:hidden}\n    .inp-prefix-wrap:focus-within{border-color:var(--red);background:var(--white)}\n    .inp-prefix{font-size:13px;font-weight:600;color:var(--muted);padding:0 4px 0 8px;flex-shrink:0;line-height:1;align-self:center}\n    .inp-prefix-wrap input{flex:1;font-size:16px;font-weight:700;color:var(--black);background:transparent;border:none;outline:none;padding:7px 6px 7px 0;font-family:var(--font);width:100%;min-width:0;-webkit-appearance:none}\n\n    .plain-inp{width:100%;font-size:16px;font-weight:700;color:var(--black);background:var(--bg);border:1px solid var(--border);border-radius:5px;outline:none;padding:6px 8px;font-family:var(--font);transition:border-color .15s;-webkit-appearance:none}\n    .plain-inp:focus{border-color:var(--red);background:var(--white)}\n\n\n    .off-contrib{margin-top:8px;font-size:11px;color:var(--muted);text-align:right}\n    .off-contrib strong{color:var(--black)}\n\n    \/* FORMULA *\/\n    .formula{font-size:11px;color:var(--muted);margin-bottom:1.5rem;background:var(--red-light);border-left:3px solid var(--red);border-radius:0 6px 6px 0;padding:8px 14px;line-height:1.7}\n    .formula strong{color:var(--black)}\n\n    \/* EMPTY *\/\n    .empty{text-align:center;padding:2.5rem;color:var(--muted);font-size:13px;background:var(--bg);border-radius:8px;border:1px dashed var(--border-mid);margin-bottom:1rem}\n\n    \/* RESULTS *\/\n    .big-m{background:var(--black);border-radius:10px;padding:1.5rem 1.75rem;margin-bottom:12px}\n    .big-eye{display:flex;align-items:center;gap:8px;margin-bottom:8px}\n    .big-line{width:18px;height:2px;background:var(--red)}\n    .big-lbl{font-size:10px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:rgba(255,255,255,.45)}\n    .big-val{font-size:42px;font-weight:700;color:#fff;line-height:1}\n    .big-sub{font-size:12px;color:rgba(255,255,255,.4);margin-top:6px}\n\n    .mets{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;margin-bottom:12px}\n    @media(max-width:480px){.mets{grid-template-columns:1fr 1fr}}\n    .met{background:var(--white);border:1px solid var(--border);border-radius:8px;padding:1rem 1.1rem}\n    .met-eye{display:flex;align-items:center;gap:6px;margin-bottom:6px}\n    .met-line{width:12px;height:2px;background:var(--red)}\n    .met-lbl{font-size:10px;text-transform:uppercase;letter-spacing:.07em;color:var(--muted);font-weight:500}\n    .met-val{font-size:20px;font-weight:700;color:var(--black)}\n    .met-sub{font-size:10px;color:var(--muted);margin-top:3px}\n\n    .brkdown{background:var(--white);border:1px solid var(--border);border-radius:8px;padding:1rem 1.25rem;margin-bottom:12px}\n    .brow{display:flex;justify-content:space-between;align-items:center;padding:7px 0;border-bottom:1px solid var(--border);font-size:13px}\n    .brow:last-child{border-bottom:none}\n    .brow .bl{color:var(--muted)}\n    .brow.total .bl{color:var(--black);font-weight:600}\n    .brow .bv{font-weight:600;color:var(--black)}\n    .brow.total .bv{color:var(--red)}\n    .ftag{font-size:10px;color:var(--muted);margin-left:4px;opacity:.7}\n    .ltag{font-size:10px;color:var(--red);margin-left:4px;font-weight:600;opacity:.8}\n\n    .revpar-pill{display:inline-flex;align-items:center;gap:8px;background:var(--red-light);color:var(--red);font-size:13px;font-weight:600;padding:8px 16px;border-radius:6px;border:1px solid var(--red-mid);margin-bottom:1.5rem}\n\n    \/* CTA *\/\n    .cta{background:var(--black);border-radius:12px;padding:2rem 2.25rem;margin-top:2rem;display:flex;align-items:center;justify-content:space-between;gap:1.5rem;flex-wrap:wrap}\n    .cta-eye{display:flex;align-items:center;gap:8px;margin-bottom:.5rem}\n    .cta-line{width:18px;height:2px;background:var(--red);flex-shrink:0}\n    .cta-lbl{font-size:10px;font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:rgba(255,255,255,.4)}\n    .cta-title{font-size:20px;font-weight:700;color:#fff;line-height:1.25;margin-bottom:.4rem}\n    .cta-title span{color:var(--red)}\n    .cta-sub{font-size:13px;color:rgba(255,255,255,.45);line-height:1.6;max-width:400px}\n    .cta-btn{display:inline-flex;align-items:center;gap:8px;background:var(--red);color:#fff;font-family:var(--font);font-size:14px;font-weight:600;padding:13px 24px;border-radius:8px;border:none;cursor:pointer;text-decoration:none;white-space:nowrap;transition:background .15s,transform .1s;flex-shrink:0}\n    .cta-btn:hover{background:#a93224;transform:translateY(-1px)}\n    .cta-btn svg{width:16px;height:16px}\n\n    .foot{font-size:11px;color:var(--muted);margin-top:2rem;padding-top:1.25rem;border-top:1px solid var(--border);display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:8px}\n    .foot a{color:var(--red);text-decoration:none}\n    .foot a:hover{text-decoration:underline}\n\n    \/* RTL *\/\n    body.rtl{direction:rtl}\n    body.rtl .hdr-eye,body.rtl .sec-eye,body.rtl .big-eye,body.rtl .met-eye,body.rtl .cta-eye{flex-direction:row-reverse}\n    body.rtl .freq-row{flex-direction:row-reverse}\n    body.rtl .inp-prefix{padding:6px 8px 6px 0}\n    body.rtl .inp-prefix-wrap input{padding:6px 3px 6px 6px}\n    body.rtl .off-contrib{text-align:left}\n    body.rtl .brow{flex-direction:row-reverse}\n    body.rtl .foot{flex-direction:row-reverse}\n\n    input[type=number]::-webkit-inner-spin-button,\n    input[type=number]::-webkit-outer-spin-button{opacity:.4}\n  <\/style>\n<\/head>\n<body>\n<div class=\"wrap\">\n\n  <div class=\"hdr\">\n    <div class=\"hdr-eye\"><div class=\"hdr-line\"><\/div><span class=\"hdr-brand\">Torres Hospitality Consulting<\/span><\/div>\n    <div class=\"hdr-title\" id=\"t-title\">What can you sell at the front desk<br>&amp; <span>how much revenue<\/span> Can you generate?<\/div>\n    <p class=\"hdr-sub\" id=\"t-sub\">Activate the offers your hotel sells, set the selling frequency, enter the supplement and units.<\/p>\n  <\/div>\n\n  <!-- LANG + CURRENCY -->\n  <div class=\"top-ctrl\">\n    <div class=\"pill-group\" id=\"lang-group\">\n      <button class=\"pill active\" onclick=\"setLang('en',this)\">English<\/button>\n      <button class=\"pill\" onclick=\"setLang('es',this)\">Spanish<\/button>\n      <button class=\"pill\" onclick=\"setLang('fr',this)\">French<\/button>\n      <button class=\"pill\" onclick=\"setLang('de',this)\">German<\/button>\n      <button class=\"pill\" onclick=\"setLang('ar',this)\">\u0627\u0644\u0639\u0631\u0628\u064a\u0629<\/button>\n    <\/div>\n    <div class=\"pill-group\" id=\"cur-group\">\n      <button class=\"pill active\" onclick=\"setCur('\u20ac',this)\">\u20ac EUR<\/button>\n      <button class=\"pill\" onclick=\"setCur('$',this)\">$ USD<\/button>\n      <button class=\"pill\" onclick=\"setCur('\u00a3',this)\">\u00a3 GBP<\/button>\n      <button class=\"pill\" onclick=\"setCur('kr',this)\">kr SEK<\/button>\n      <button class=\"pill\" onclick=\"setCur('kr',this)\">kr NOK<\/button>\n      <button class=\"pill\" onclick=\"setCur('AED',this)\">AED<\/button>\n    <\/div>\n  <\/div>\n\n  <!-- HOTEL TYPE -->\n  <div class=\"type-tabs\">\n    <button class=\"type-tab active\" onclick=\"setType('urban',this)\">\n      <span class=\"tab-icon\">\ud83c\udfd9\ufe0f<\/span>\n      <span id=\"t-type-urban\">Urban Hotel<\/span>\n    <\/button>\n    <button class=\"type-tab\" onclick=\"setType('resort',this)\">\n      <span class=\"tab-icon\">\ud83c\udfd6\ufe0f<\/span>\n      <span id=\"t-type-resort\">Resort<\/span>\n    <\/button>\n  <\/div>\n\n  <!-- HOTEL DATA -->\n  <div class=\"sec-eye\"><div class=\"sec-line\"><\/div><span class=\"sec-lbl\" id=\"t-s1\">Your hotel data<\/span><\/div>\n  <div class=\"inp-grid\">\n    <div class=\"inp-card\">\n      <label id=\"t-rooms\">Rooms<\/label>\n      <div class=\"inp-wrap\"><input type=\"number\" id=\"rooms\" value=\"150\" min=\"1\" oninput=\"calc()\"\/><span class=\"inp-unit\" id=\"t-rooms-u\">rooms<\/span><\/div>\n      <div class=\"inp-hint\" id=\"t-rooms-h\">Total inventory<\/div>\n    <\/div>\n    <div class=\"inp-card\">\n      <label id=\"t-adr\">ADR<\/label>\n      <div class=\"inp-wrap\"><input type=\"number\" id=\"adr\" value=\"200\" min=\"1\" step=\"1\" oninput=\"calc()\"\/><span class=\"inp-unit\" id=\"t-adr-u\">\u20ac<\/span><\/div>\n      <div class=\"inp-hint\" id=\"t-adr-h\">Average daily rate<\/div>\n    <\/div>\n    <div class=\"inp-card\">\n      <label id=\"t-occ\">Occupancy<\/label>\n      <div class=\"inp-wrap\"><input type=\"number\" id=\"occ\" value=\"90\" min=\"1\" max=\"100\" step=\"0.1\" oninput=\"calc()\"\/><span class=\"inp-unit\">%<\/span><\/div>\n      <div class=\"inp-hint\" id=\"t-occ-h\">Monthly average<\/div>\n    <\/div>\n    <div class=\"inp-card\">\n      <label id=\"t-los\">Avg. LOS<\/label>\n      <div class=\"inp-wrap\"><input type=\"number\" id=\"los\" value=\"2.3\" min=\"0.5\" step=\"0.1\" oninput=\"calc()\"\/><span class=\"inp-unit\" id=\"t-los-u\">days<\/span><\/div>\n      <div class=\"inp-hint\" id=\"t-los-h\">Days per booking<\/div>\n    <\/div>\n  <\/div>\n\n  <div class=\"divider\"><\/div>\n\n  <!-- OFFERS -->\n  <div class=\"sec-eye\"><div class=\"sec-line\"><\/div><span class=\"sec-lbl\" id=\"t-s2\">Offers at the front desk<\/span><\/div>\n  <p class=\"off-intro\" id=\"t-intro\">Activate each offer, choose how often it&#039;s sold, then enter the supplement per stay and units sold in that period.<\/p>\n  <div class=\"off-grid\" id=\"offersGrid\"><\/div>\n\n  <div class=\"formula\">\n    <strong id=\"t-formula-title\">How it&#039;s calculated:<\/strong>\n    <span id=\"t-formula-body\"> Room Upgrade, Breakfast, Meals &amp; Parking multiply by LOS \u00d7 hotel factor (Urban \u00d71.15 \/ Resort \u00d70.85). All other offers are simple unit charges. Daily \u00d7365, Weekly \u00d752.<\/span>\n  <\/div>\n\n  <div class=\"divider\"><\/div>\n\n  <!-- RESULTS -->\n  <div class=\"sec-eye\"><div class=\"sec-line\"><\/div><span class=\"sec-lbl\" id=\"t-s3\">Your upsell potential<\/span><\/div>\n  <div id=\"resultsArea\"><\/div>\n\n  <!-- CTA -->\n  <div class=\"cta\">\n    <div>\n      <div class=\"cta-eye\"><div class=\"cta-line\"><\/div><span class=\"cta-lbl\" id=\"t-cta-label\">Torres Hospitality Consulting<\/span><\/div>\n      <div class=\"cta-title\" id=\"t-cta-title\">Want to <span>unlock this revenue<\/span><br>in your hotel?<\/div>\n      <p class=\"cta-sub\" id=\"t-cta-sub\">Pablo Torres helps hotel teams build real upselling systems \u2014 from script to conversion. Let&#039;s talk about what&#039;s possible for your property.<\/p>\n    <\/div>\n    <a href=\"https:\/\/torreshospitalityconsulting.com\/en\/\" target=\"_blank\" class=\"cta-btn\">\n      <svg viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M5 12h14M12 5l7 7-7 7\"\/><\/svg>\n      <span id=\"t-cta-btn\">Book a free call<\/span>\n    <\/a>\n  <\/div>\n\n  <div class=\"foot\">\n    <span>Torres Hospitality Consulting<\/span>\n    <a href=\"https:\/\/torreshospitalityconsulting.com\/en\/\" target=\"_blank\">torreshospitalityconsulting.com<\/a>\n  <\/div>\n<\/div>\n\n<script>\nlet lang='en', cur='\u20ac', hotelType='urban';\n\n\/\/ Only these 4 use LOS \u00d7 hotel factor\nconst LOS_KEYS = new Set(['upgrade','breakfast','meals','parking']);\n\nconst offers=[\n  {key:'upgrade',   en:'Room upgrade',   es:'Upgrade habitaci\u00f3n',fr:'Surclassement',     de:'Zimmer-Upgrade',   ar:'\u062a\u0631\u0642\u064a\u0629 \u0627\u0644\u063a\u0631\u0641\u0629',     supp:'',units:'',freq:'daily' },\n  {key:'earlyin',   en:'Early check-in', es:'Early check-in',    fr:'Early check-in',    de:'Fr\u00fch-Check-in',    ar:'\u062a\u0633\u062c\u064a\u0644 \u062f\u062e\u0648\u0644 \u0645\u0628\u0643\u0631',  supp:'',units:'',freq:'daily' },\n  {key:'lateout',   en:'Late check-out', es:'Late check-out',    fr:'Late check-out',    de:'Sp\u00e4ter Check-out', ar:'\u062a\u0633\u062c\u064a\u0644 \u062e\u0631\u0648\u062c \u0645\u062a\u0623\u062e\u0631', supp:'',units:'',freq:'daily' },\n  {key:'breakfast', en:'Breakfast',      es:'Desayuno',          fr:'Petit-d\u00e9jeuner',    de:'Fr\u00fchst\u00fcck',        ar:'\u0625\u0641\u0637\u0627\u0631',             supp:'',units:'',freq:'daily' },\n  {key:'meals',     en:'Meals',          es:'Comidas',           fr:'Repas',             de:'Mahlzeiten',       ar:'\u0648\u062c\u0628\u0627\u062a',             supp:'',units:'',freq:'daily' },\n  {key:'parking',   en:'Parking',        es:'Parking',           fr:'Parking',           de:'Parken',           ar:'\u0645\u0648\u0642\u0641 \u0633\u064a\u0627\u0631\u0627\u062a',       supp:'',units:'',freq:'daily' },\n  {key:'spa',       en:'Spa package',    es:'Pack spa',          fr:'Forfait spa',       de:'Spa-Paket',        ar:'\u0628\u0627\u0642\u0629 \u0633\u0628\u0627',          supp:'',units:'',freq:'weekly'},\n  {key:'welcome',   en:'Welcome pack',   es:'Pack bienvenida',   fr:'Pack bienvenue',    de:'Willkommenspaket', ar:'\u062d\u0632\u0645\u0629 \u0627\u0644\u062a\u0631\u062d\u064a\u0628',      supp:'',units:'',freq:'weekly'},\n  {key:'transfer',  en:'Transfer',       es:'Transfer',          fr:'Transfert',         de:'Transfer',         ar:'\u0646\u0642\u0644',               supp:'',units:'',freq:'weekly'},\n  {key:'extras',    en:'Other extras',   es:'Otros extras',      fr:'Autres extras',     de:'Weitere Extras',   ar:'\u0625\u0636\u0627\u0641\u0627\u062a \u0623\u062e\u0631\u0649',       supp:'',units:'',freq:'daily' },\n];\n\nconst active=new Set();\n\nconst T={\n  en:{\n    title:'What can you sell at the front desk<br>& <span style=\"color:var(--red)\">how much revenue<\/span> can you generate?',\n    sub:'Activate the offers your hotel sells, set the selling frequency, enter the supplement and units. Revenue is calculated independently for each offer.',\n    typeUrban:'Urban Hotel',typeResort:'Resort',\n    s1:'Your hotel data',s2:'Offers at the front desk',s3:'Your upsell potential',\n    rooms:'Rooms',roomsH:'Total inventory',roomsU:'rooms',\n    adr:'ADR',adrH:'Average daily rate',\n    occ:'Occupancy',occH:'Monthly average',\n    los:'Avg. LOS',losH:'Days per booking',losU:'days',\n    intro:'Activate each offer, choose how often it\\'s sold, then enter the supplement per stay and units sold in that period.',\n    formulaTitle:'How it\\'s calculated:',\n    formulaBody:' Room Upgrade, Breakfast, Meals & Parking multiply by LOS \u00d7 hotel factor (Urban \u00d71.15 \/ Resort \u00d70.85). All other offers are simple unit charges. Daily \u00d7365, Weekly \u00d752.',\n    freqD:'Daily',freqW:'Weekly',\n    suppLbl:'Supplement',unitsDLbl:'Units \/ day',unitsWLbl:'Units \/ week',\n    losNote:'\u00d7 LOS \u00d7 hotel factor',\n    annRev:'Projected annual revenue',dayRev:'Daily revenue',monRev:'Monthly revenue',\n    revpar:'Current RevPAR',revparLift:'RevPAR uplift',arrivals:'Daily arrivals',\n    empty:'Activate at least one offer and fill in supplement and units to see your results.',\n    brkTitle:'Revenue by offer (annual)',\n    totalAnn:'Total annual upsell',contrib:'annual',active:'offers active',\n    fTagD:'daily',fTagW:'weekly',losTag:'\u00d7LOS',\n    ctaLbl:'Torres Hospitality Consulting',\n    ctaTitle:'Want to <span>unlock this revenue<\/span><br>in your hotel?',\n    ctaSub:'Pablo Torres helps hotel teams build real upselling systems \u2014 from script to conversion. Let\\'s talk about what\\'s possible for your property.',\n    ctaBtn:'Book a free call',\n  },\n  es:{\n    title:'\u00bfQu\u00e9 puedes vender en recepci\u00f3n<br>y <span style=\"color:var(--red)\">cu\u00e1nto revenue<\/span> puedes generar?',\n    sub:'Activa las ofertas que vende tu hotel, selecciona la frecuencia, introduce el suplemento y las unidades.',\n    typeUrban:'Hotel Urbano',typeResort:'Resort',\n    s1:'Datos de tu hotel',s2:'Ofertas en recepci\u00f3n',s3:'Tu potencial de upsell',\n    rooms:'Habitaciones',roomsH:'Inventario total',roomsU:'hab.',\n    adr:'ADR',adrH:'Precio medio diario',\n    occ:'Ocupaci\u00f3n',occH:'Media mensual',\n    los:'Estancia media',losH:'D\u00edas por reserva',losU:'d\u00edas',\n    intro:'Activa cada oferta, elige con qu\u00e9 frecuencia se vende e introduce el suplemento y las unidades en ese periodo.',\n    formulaTitle:'C\u00f3mo se calcula:',\n    formulaBody:' Upgrade, Desayuno, Comidas y Parking se multiplican por la estancia media \u00d7 factor de hotel (Urbano \u00d71.15 \/ Resort \u00d70.85). El resto son cargos unitarios. Diaria \u00d7365, Semanal \u00d752.',\n    freqD:'Diaria',freqW:'Semanal',\n    suppLbl:'Suplemento',unitsDLbl:'Unidades \/ d\u00eda',unitsWLbl:'Unidades \/ semana',\n    losNote:'\u00d7 estancia \u00d7 factor hotel',\n    annRev:'Revenue anual proyectado',dayRev:'Revenue diario',monRev:'Revenue mensual',\n    revpar:'RevPAR actual',revparLift:'Incremento RevPAR',arrivals:'Llegadas diarias',\n    empty:'Activa al menos una oferta e introduce suplemento y unidades para ver tus resultados.',\n    brkTitle:'Revenue por oferta (anual)',\n    totalAnn:'Upsell total anual',contrib:'anual',active:'ofertas activas',\n    fTagD:'diaria',fTagW:'semanal',losTag:'\u00d7LOS',\n    ctaLbl:'Torres Hospitality Consulting',\n    ctaTitle:'\u00bfQuieres <span>activar este revenue<\/span><br>en tu hotel?',\n    ctaSub:'Pablo Torres ayuda a equipos hoteleros a construir sistemas reales de upselling \u2014 del script a la conversi\u00f3n.',\n    ctaBtn:'Reserva una llamada gratuita',\n  },\n  fr:{\n    title:'Que pouvez-vous vendre \u00e0 la r\u00e9ception<br>& <span style=\"color:var(--red)\">combien de revenus<\/span> g\u00e9n\u00e9rer?',\n    sub:'Activez les offres de votre h\u00f4tel, d\u00e9finissez la fr\u00e9quence, saisissez le suppl\u00e9ment et les unit\u00e9s.',\n    typeUrban:'H\u00f4tel Urbain',typeResort:'Resort',\n    s1:'Donn\u00e9es de votre h\u00f4tel',s2:'Offres \u00e0 la r\u00e9ception',s3:'Votre potentiel d\\'upsell',\n    rooms:'Chambres',roomsH:'Inventaire total',roomsU:'ch.',\n    adr:'ADR',adrH:'Tarif journalier moyen',\n    occ:'Occupation',occH:'Moyenne mensuelle',\n    los:'Dur\u00e9e moy. s\u00e9jour',losH:'Jours par r\u00e9servation',losU:'jours',\n    intro:'Activez chaque offre, choisissez la fr\u00e9quence de vente, saisissez le suppl\u00e9ment et les unit\u00e9s vendues.',\n    formulaTitle:'Comment c\\'est calcul\u00e9:',\n    formulaBody:' Surclassement, Petit-d\u00e9jeuner, Repas et Parking sont multipli\u00e9s par la dur\u00e9e de s\u00e9jour \u00d7 facteur h\u00f4tel (Urbain \u00d71.15 \/ Resort \u00d70.85). Les autres offres sont des charges unitaires. Quotidien \u00d7365, Hebdo \u00d752.',\n    freqD:'Quotidien',freqW:'Hebdo',\n    suppLbl:'Suppl\u00e9ment',unitsDLbl:'Unit\u00e9s \/ jour',unitsWLbl:'Unit\u00e9s \/ semaine',\n    losNote:'\u00d7 s\u00e9jour \u00d7 facteur h\u00f4tel',\n    annRev:'Revenu annuel projet\u00e9',dayRev:'Revenu journalier',monRev:'Revenu mensuel',\n    revpar:'RevPAR actuel',revparLift:'Hausse RevPAR',arrivals:'Arriv\u00e9es journali\u00e8res',\n    empty:'Activez au moins une offre et renseignez le suppl\u00e9ment et les unit\u00e9s.',\n    brkTitle:'Revenu par offre (annuel)',\n    totalAnn:'Upsell annuel total',contrib:'annuel',active:'offres actives',\n    fTagD:'quotidien',fTagW:'hebdo',losTag:'\u00d7LOS',\n    ctaLbl:'Torres Hospitality Consulting',\n    ctaTitle:'Vous voulez <span>d\u00e9bloquer ce revenu<\/span><br>dans votre h\u00f4tel?',\n    ctaSub:'Pablo Torres aide les \u00e9quipes h\u00f4teli\u00e8res \u00e0 construire de vrais syst\u00e8mes d\\'upselling.',\n    ctaBtn:'R\u00e9server un appel gratuit',\n  },\n  de:{\n    title:'Was k\u00f6nnen Sie an der Rezeption verkaufen<br>& <span style=\"color:var(--red)\">wie viel Umsatz<\/span> generieren?',\n    sub:'Aktivieren Sie die Angebote Ihres Hotels, legen Sie die H\u00e4ufigkeit fest, geben Sie den Aufpreis und die Einheiten ein.',\n    typeUrban:'Stadthotel',typeResort:'Resort',\n    s1:'Ihre Hoteldaten',s2:'Angebote an der Rezeption',s3:'Ihr Upsell-Potenzial',\n    rooms:'Zimmer',roomsH:'Gesamtbestand',roomsU:'Zim.',\n    adr:'ADR',adrH:'Durchschn. Tagespreis',\n    occ:'Auslastung',occH:'Monatsdurchschnitt',\n    los:'\u00d8 Aufenthaltsdauer',losH:'Tage pro Buchung',losU:'Tage',\n    intro:'Aktivieren Sie jedes Angebot, w\u00e4hlen Sie die H\u00e4ufigkeit und geben Sie den Aufpreis sowie die Einheiten ein.',\n    formulaTitle:'Berechnungsmethode:',\n    formulaBody:' Upgrade, Fr\u00fchst\u00fcck, Mahlzeiten und Parken werden mit der Aufenthaltsdauer \u00d7 Hotelfaktor (Stadt \u00d71.15 \/ Resort \u00d70.85) multipliziert. Andere Angebote sind Einzelgeb\u00fchren. T\u00e4glich \u00d7365, W\u00f6chentlich \u00d752.',\n    freqD:'T\u00e4glich',freqW:'W\u00f6chentlich',\n    suppLbl:'Aufpreis',unitsDLbl:'Einheiten \/ Tag',unitsWLbl:'Einheiten \/ Woche',\n    losNote:'\u00d7 Aufenthalt \u00d7 Hotelfaktor',\n    annRev:'Progn. Jahresumsatz',dayRev:'Tagesumsatz',monRev:'Monatsumsatz',\n    revpar:'Aktueller RevPAR',revparLift:'RevPAR-Steigerung',arrivals:'T\u00e4gliche Ank\u00fcnfte',\n    empty:'Aktivieren Sie mindestens ein Angebot und f\u00fcllen Sie Aufpreis und Einheiten aus.',\n    brkTitle:'Umsatz nach Angebot (j\u00e4hrlich)',\n    totalAnn:'Gesamt-Jahres-Upsell',contrib:'j\u00e4hrlich',active:'Angebote aktiv',\n    fTagD:'t\u00e4glich',fTagW:'w\u00f6chentlich',losTag:'\u00d7LOS',\n    ctaLbl:'Torres Hospitality Consulting',\n    ctaTitle:'M\u00f6chten Sie <span>diesen Umsatz erschlie\u00dfen<\/span><br>in Ihrem Hotel?',\n    ctaSub:'Pablo Torres hilft Hotelteams, echte Upselling-Systeme aufzubauen.',\n    ctaBtn:'Kostenloses Gespr\u00e4ch buchen',\n  },\n  ar:{\n    title:'\u0645\u0627\u0630\u0627 \u064a\u0645\u0643\u0646\u0643 \u0628\u064a\u0639\u0647 \u0641\u064a \u0627\u0644\u0627\u0633\u062a\u0642\u0628\u0627\u0644<br>\u0648<span style=\"color:var(--red)\">\u0643\u0645 \u0645\u0646 \u0627\u0644\u0625\u064a\u0631\u0627\u062f\u0627\u062a<\/span> \u064a\u0645\u0643\u0646\u0643 \u062a\u062d\u0642\u064a\u0642\u0647\u0627\u061f',\n    sub:'\u0641\u0639\u0651\u0644 \u0627\u0644\u0639\u0631\u0648\u0636 \u0627\u0644\u062a\u064a \u064a\u0642\u062f\u0645\u0647\u0627 \u0641\u0646\u062f\u0642\u0643\u060c \u062d\u062f\u062f \u062a\u0643\u0631\u0627\u0631 \u0627\u0644\u0628\u064a\u0639\u060c \u0623\u062f\u062e\u0644 \u0627\u0644\u0631\u0633\u0648\u0645 \u0627\u0644\u0625\u0636\u0627\u0641\u064a\u0629 \u0648\u0627\u0644\u0648\u062d\u062f\u0627\u062a.',\n    typeUrban:'\u0641\u0646\u062f\u0642 \u062d\u0636\u0631\u064a',typeResort:'\u0645\u0646\u062a\u062c\u0639',\n    s1:'\u0628\u064a\u0627\u0646\u0627\u062a \u0641\u0646\u062f\u0642\u0643',s2:'\u0627\u0644\u0639\u0631\u0648\u0636 \u0641\u064a \u0627\u0644\u0627\u0633\u062a\u0642\u0628\u0627\u0644',s3:'\u0625\u0645\u0643\u0627\u0646\u0627\u062a \u0627\u0644\u0628\u064a\u0639 \u0627\u0644\u0625\u0636\u0627\u0641\u064a',\n    rooms:'\u063a\u0631\u0641',roomsH:'\u0625\u062c\u0645\u0627\u0644\u064a \u0627\u0644\u0645\u062e\u0632\u0648\u0646',roomsU:'\u063a\u0631\u0641\u0629',\n    adr:'ADR',adrH:'\u0645\u062a\u0648\u0633\u0637 \u0627\u0644\u0633\u0639\u0631 \u0627\u0644\u064a\u0648\u0645\u064a',\n    occ:'\u0627\u0644\u0625\u0634\u063a\u0627\u0644',occH:'\u0627\u0644\u0645\u062a\u0648\u0633\u0637 \u0627\u0644\u0634\u0647\u0631\u064a',\n    los:'\u0645\u062a\u0648\u0633\u0637 \u0627\u0644\u0625\u0642\u0627\u0645\u0629',losH:'\u0623\u064a\u0627\u0645 \u0644\u0643\u0644 \u062d\u062c\u0632',losU:'\u0623\u064a\u0627\u0645',\n    intro:'\u0641\u0639\u0651\u0644 \u0643\u0644 \u0639\u0631\u0636\u060c \u0627\u062e\u062a\u0631 \u062a\u0643\u0631\u0627\u0631 \u0627\u0644\u0628\u064a\u0639\u060c \u062b\u0645 \u0623\u062f\u062e\u0644 \u0627\u0644\u0631\u0633\u0645 \u0627\u0644\u0625\u0636\u0627\u0641\u064a \u0648\u0627\u0644\u0648\u062d\u062f\u0627\u062a.',\n    formulaTitle:'\u0637\u0631\u064a\u0642\u0629 \u0627\u0644\u062d\u0633\u0627\u0628:',\n    formulaBody:' \u062a\u0631\u0642\u064a\u0629 \u0627\u0644\u063a\u0631\u0641\u0629\u060c \u0627\u0644\u0625\u0641\u0637\u0627\u0631\u060c \u0627\u0644\u0648\u062c\u0628\u0627\u062a \u0648\u0627\u0644\u0645\u0648\u0642\u0641 \u062a\u064f\u0636\u0631\u0628 \u0641\u064a \u0645\u062f\u0629 \u0627\u0644\u0625\u0642\u0627\u0645\u0629 \u00d7 \u0639\u0627\u0645\u0644 \u0646\u0648\u0639 \u0627\u0644\u0641\u0646\u062f\u0642 (\u062d\u0636\u0631\u064a \u00d71.15 \/ \u0645\u0646\u062a\u062c\u0639 \u00d70.85). \u0628\u0627\u0642\u064a \u0627\u0644\u0639\u0631\u0648\u0636 \u0631\u0633\u0648\u0645 \u0641\u0631\u062f\u064a\u0629. \u064a\u0648\u0645\u064a \u00d7365\u060c \u0623\u0633\u0628\u0648\u0639\u064a \u00d752.',\n    freqD:'\u064a\u0648\u0645\u064a',freqW:'\u0623\u0633\u0628\u0648\u0639\u064a',\n    suppLbl:'\u0627\u0644\u0631\u0633\u0645 \u0627\u0644\u0625\u0636\u0627\u0641\u064a',unitsDLbl:'\u0648\u062d\u062f\u0627\u062a \/ \u064a\u0648\u0645',unitsWLbl:'\u0648\u062d\u062f\u0627\u062a \/ \u0623\u0633\u0628\u0648\u0639',\n    losNote:'\u00d7 \u0627\u0644\u0625\u0642\u0627\u0645\u0629 \u00d7 \u0639\u0627\u0645\u0644 \u0627\u0644\u0641\u0646\u062f\u0642',\n    annRev:'\u0627\u0644\u0625\u064a\u0631\u0627\u062f\u0627\u062a \u0627\u0644\u0633\u0646\u0648\u064a\u0629 \u0627\u0644\u0645\u062a\u0648\u0642\u0639\u0629',dayRev:'\u0627\u0644\u0625\u064a\u0631\u0627\u062f\u0627\u062a \u0627\u0644\u064a\u0648\u0645\u064a\u0629',monRev:'\u0627\u0644\u0625\u064a\u0631\u0627\u062f\u0627\u062a \u0627\u0644\u0634\u0647\u0631\u064a\u0629',\n    revpar:'RevPAR \u0627\u0644\u062d\u0627\u0644\u064a',revparLift:'\u0627\u0631\u062a\u0641\u0627\u0639 RevPAR',arrivals:'\u0627\u0644\u0648\u0635\u0648\u0644 \u0627\u0644\u064a\u0648\u0645\u064a',\n    empty:'\u0641\u0639\u0651\u0644 \u0639\u0631\u0636\u0627\u064b \u0648\u0627\u062d\u062f\u0627\u064b \u0639\u0644\u0649 \u0627\u0644\u0623\u0642\u0644 \u0648\u0623\u062f\u062e\u0644 \u0627\u0644\u0631\u0633\u0645 \u0627\u0644\u0625\u0636\u0627\u0641\u064a \u0648\u0627\u0644\u0648\u062d\u062f\u0627\u062a \u0644\u0631\u0624\u064a\u0629 \u0627\u0644\u0646\u062a\u0627\u0626\u062c.',\n    brkTitle:'\u0627\u0644\u0625\u064a\u0631\u0627\u062f\u0627\u062a \u062d\u0633\u0628 \u0627\u0644\u0639\u0631\u0636 (\u0633\u0646\u0648\u064a\u0627\u064b)',\n    totalAnn:'\u0625\u062c\u0645\u0627\u0644\u064a \u0627\u0644\u0628\u064a\u0639 \u0627\u0644\u0625\u0636\u0627\u0641\u064a \u0627\u0644\u0633\u0646\u0648\u064a',contrib:'\u0633\u0646\u0648\u064a\u0627\u064b',active:'\u0639\u0631\u0648\u0636 \u0646\u0634\u0637\u0629',\n    fTagD:'\u064a\u0648\u0645\u064a',fTagW:'\u0623\u0633\u0628\u0648\u0639\u064a',losTag:'\u00d7LOS',\n    ctaLbl:'Torres Hospitality Consulting',\n    ctaTitle:'\u0647\u0644 \u062a\u0631\u064a\u062f <span>\u062a\u062d\u0642\u064a\u0642 \u0647\u0630\u0647 \u0627\u0644\u0625\u064a\u0631\u0627\u062f\u0627\u062a<\/span><br>\u0641\u064a \u0641\u0646\u062f\u0642\u0643\u061f',\n    ctaSub:'\u064a\u0633\u0627\u0639\u062f \u0628\u0627\u0628\u0644\u0648 \u062a\u0648\u0631\u064a\u0633 \u0641\u0631\u0642 \u0627\u0644\u0641\u0646\u0627\u062f\u0642 \u0639\u0644\u0649 \u0628\u0646\u0627\u0621 \u0623\u0646\u0638\u0645\u0629 \u0628\u064a\u0639 \u0625\u0636\u0627\u0641\u064a \u062d\u0642\u064a\u0642\u064a\u0629.',\n    ctaBtn:'\u0627\u062d\u062c\u0632 \u0645\u0643\u0627\u0644\u0645\u0629 \u0645\u062c\u0627\u0646\u064a\u0629',\n  }\n};\n\nfunction hotelFactor(){ return hotelType==='urban' ? 1.15 : 0.85; }\nfunction annMult(freq){ return freq==='weekly' ? 52 : 365; }\n\n\/\/ Annual revenue for one offer\nfunction offerAnnual(o){\n  const supp=parseFloat(o.supp)||0;\n  const units=parseFloat(o.units)||0;\n  const los=parseFloat(document.getElementById('los').value)||1;\n  if(supp===0||units===0) return 0;\n  const base = units * supp * annMult(o.freq);\n  if(LOS_KEYS.has(o.key)){\n    return base * los * hotelFactor();\n  }\n  return base;\n}\n\n\/\/ Daily equivalent for RevPAR\nfunction offerDailyEquiv(o){\n  const ann=offerAnnual(o);\n  return ann\/365;\n}\n\nfunction setLang(l,btn){\n  lang=l;\n  document.querySelectorAll('#lang-group .pill').forEach(b=>b.classList.remove('active'));\n  btn.classList.add('active');\n  document.body.classList.toggle('rtl',l==='ar');\n  applyLang(); renderOffers(); calc();\n}\n\nfunction setCur(c,btn){\n  cur=c;\n  document.querySelectorAll('#cur-group .pill').forEach(b=>b.classList.remove('active'));\n  btn.classList.add('active');\n  document.getElementById('t-adr-u').textContent=c;\n  document.querySelectorAll('.inp-prefix').forEach(el=>el.textContent=c);\n  calc();\n}\n\nfunction setType(type,btn){\n  hotelType=type;\n  document.querySelectorAll('.type-tab').forEach(b=>b.classList.remove('active'));\n  btn.classList.add('active');\n  calc();\n  \/\/ Update contrib labels\n  offers.forEach(o=>{ if(active.has(o.key)) updateContrib(o); });\n}\n\nfunction applyLang(){\n  const t=T[lang];\n  document.getElementById('t-title').innerHTML=t.title;\n  document.getElementById('t-sub').textContent=t.sub;\n  document.getElementById('t-type-urban').textContent=t.typeUrban;\n  document.getElementById('t-type-resort').textContent=t.typeResort;\n  document.getElementById('t-s1').textContent=t.s1;\n  document.getElementById('t-s2').textContent=t.s2;\n  document.getElementById('t-s3').textContent=t.s3;\n  document.getElementById('t-rooms').textContent=t.rooms;\n  document.getElementById('t-rooms-h').textContent=t.roomsH;\n  document.getElementById('t-rooms-u').textContent=t.roomsU;\n  document.getElementById('t-adr').textContent=t.adr;\n  document.getElementById('t-adr-h').textContent=t.adrH;\n  document.getElementById('t-occ').textContent=t.occ;\n  document.getElementById('t-occ-h').textContent=t.occH;\n  document.getElementById('t-los').textContent=t.los;\n  document.getElementById('t-los-h').textContent=t.losH;\n  document.getElementById('t-los-u').textContent=t.losU;\n  document.getElementById('t-intro').textContent=t.intro;\n  document.getElementById('t-formula-title').textContent=t.formulaTitle;\n  document.getElementById('t-formula-body').textContent=t.formulaBody;\n  document.getElementById('t-cta-label').textContent=t.ctaLbl;\n  document.getElementById('t-cta-title').innerHTML=t.ctaTitle;\n  document.getElementById('t-cta-sub').textContent=t.ctaSub;\n  document.getElementById('t-cta-btn').textContent=t.ctaBtn;\n}\n\nfunction fmt(n){ return cur+' '+Math.round(n).toLocaleString('en-US'); }\nfunction fmtD(n,d=2){ return cur+' '+n.toFixed(d); }\n\nfunction renderOffers(){\n  const grid=document.getElementById('offersGrid');\n  grid.innerHTML='';\n  const t=T[lang];\n  offers.forEach(o=>{\n    const isOn=active.has(o.key);\n    const isLOS=LOS_KEYS.has(o.key);\n    const ann=isOn ? offerAnnual(o) : 0;\n\n    const card=document.createElement('div');\n    card.className='off-card'+(isOn?' on':'');\n    card.setAttribute('data-key',o.key);\n\n    \/\/ Header\n    const hdr=document.createElement('div');\n    hdr.className='off-hdr';\n    hdr.innerHTML=`<span class=\"off-name\">${o[lang]}<\/span><div class=\"off-tog\"><\/div>`;\n    hdr.addEventListener('click',()=>toggleOffer(o.key));\n\n    \/\/ Fields\n    const flds=document.createElement('div');\n    flds.className='off-flds';\n    const uLbl=o.freq==='weekly'?t.unitsWLbl:t.unitsDLbl;\n    flds.innerHTML=`\n      <div class=\"freq-row\">\n        <button class=\"freq-btn${o.freq==='daily'?' active':''}\" data-freq=\"daily\">${t.freqD}<\/button>\n        <button class=\"freq-btn${o.freq==='weekly'?' active':''}\" data-freq=\"weekly\">${t.freqW}<\/button>\n      <\/div>\n      <div class=\"fld-row\">\n        <div class=\"fld-wrap\">\n          <label>${t.suppLbl}<\/label>\n          <div class=\"inp-prefix-wrap\"><span class=\"inp-prefix\">${cur}<\/span><input type=\"number\" inputmode=\"numeric\" value=\"${o.supp}\" min=\"0\" step=\"1\" placeholder=\"0\" data-field=\"supp\"\/><\/div>\n        <\/div>\n        <div class=\"fld-wrap\">\n          <label class=\"units-lbl\">${uLbl}<\/label>\n          <input type=\"number\" inputmode=\"decimal\" class=\"plain-inp\" value=\"${o.units}\" min=\"0\" step=\"0.1\" placeholder=\"0\" data-field=\"units\"\/>\n        <\/div>\n      <\/div>\n      ${isOn&&ann>0?`<div class=\"off-contrib\">= <strong>${fmt(ann)}<\/strong> ${t.contrib}<\/div>`:''}\n    `;\n\n    flds.querySelectorAll('.freq-btn').forEach(btn=>{\n      btn.addEventListener('click',e=>{\n        e.stopPropagation();\n        o.freq=btn.getAttribute('data-freq');\n        flds.querySelectorAll('.freq-btn').forEach(b=>b.classList.toggle('active',b===btn));\n        flds.querySelector('.units-lbl').textContent=o.freq==='weekly'?T[lang].unitsWLbl:T[lang].unitsDLbl;\n        calc(); updateContrib(o);\n      });\n    });\n\n    flds.querySelectorAll('input').forEach(inp=>{\n      inp.addEventListener('input',e=>{\n        o[e.target.getAttribute('data-field')]=e.target.value;\n        calc(); updateContrib(o);\n      });\n    });\n\n    flds.addEventListener('click',e=>e.stopPropagation());\n    flds.addEventListener('mousedown',e=>e.stopPropagation());\n    flds.addEventListener('touchstart',e=>e.stopPropagation(),{passive:true});\n\n    card.appendChild(hdr);\n    card.appendChild(flds);\n    grid.appendChild(card);\n  });\n}\n\nfunction toggleOffer(key){\n  if(active.has(key)) active.delete(key); else active.add(key);\n  renderOffers(); calc();\n}\n\nfunction updateContrib(o){\n  const t=T[lang];\n  const card=document.querySelector(`.off-card[data-key=\"${o.key}\"]`);\n  if(!card) return;\n  const ann=offerAnnual(o);\n  let contrib=card.querySelector('.off-contrib');\n  if(ann>0&&active.has(o.key)){\n    if(!contrib){ contrib=document.createElement('div'); contrib.className='off-contrib'; card.querySelector('.off-flds').appendChild(contrib); }\n    contrib.innerHTML=`= <strong>${fmt(ann)}<\/strong> ${t.contrib}`;\n  } else if(contrib){ contrib.remove(); }\n}\n\nfunction calc(){\n  const t=T[lang];\n  const rooms=parseFloat(document.getElementById('rooms').value)||0;\n  const adr=parseFloat(document.getElementById('adr').value)||0;\n  const occ=parseFloat(document.getElementById('occ').value)\/100||0;\n  const los=parseFloat(document.getElementById('los').value)||1;\n\n  const occRooms=rooms*occ;\n  const arrivals=occRooms\/los;\n  const revpar=adr*occ;\n\n  let totalAnnual=0, totalDailyEquiv=0;\n  const lines=[];\n\n  offers.forEach(o=>{\n    if(!active.has(o.key)) return;\n    const ann=offerAnnual(o);\n    if(ann>0){\n      totalAnnual+=ann;\n      totalDailyEquiv+=offerDailyEquiv(o);\n      lines.push({\n        name:o[lang],annual:ann,\n        fTag:o.freq==='weekly'?t.fTagW:t.fTagD,\n        isLOS:LOS_KEYS.has(o.key)\n      });\n    }\n  });\n\n  const totalMonthly=totalAnnual\/12;\n  const revparLift=rooms>0&&revpar>0?(totalDailyEquiv\/rooms\/revpar*100):0;\n  const ra=document.getElementById('resultsArea');\n\n  if(active.size===0||totalAnnual===0){\n    ra.innerHTML=`<div class=\"empty\">${t.empty}<\/div>`;\n    return;\n  }\n\n  const breakdown=lines.length>1?`\n    <div class=\"brkdown\">\n      <div class=\"sec-eye\" style=\"margin-bottom:.75rem\"><div class=\"sec-line\"><\/div><span class=\"sec-lbl\">${t.brkTitle}<\/span><\/div>\n      ${lines.map(l=>`\n        <div class=\"brow\">\n          <span class=\"bl\">${l.name}<span class=\"ftag\">(${l.fTag})<\/span><\/span>\n          <span class=\"bv\">${fmt(l.annual)}<\/span>\n        <\/div>`).join('')}\n      <div class=\"brow total\"><span class=\"bl\">${t.totalAnn}<\/span><span class=\"bv\">${fmt(totalAnnual)}<\/span><\/div>\n    <\/div>`:'';;\n\n  ra.innerHTML=`\n    <div class=\"big-m\">\n      <div class=\"big-eye\"><div class=\"big-line\"><\/div><span class=\"big-lbl\">${t.annRev}<\/span><\/div>\n      <div class=\"big-val\">${fmt(totalAnnual)}<\/div>\n      <div class=\"big-sub\">${t.arrivals}: ${arrivals.toFixed(1)} \u00b7 ${t.revpar}: ${fmtD(revpar)}<\/div>\n    <\/div>\n    <div class=\"mets\">\n      <div class=\"met\"><div class=\"met-eye\"><div class=\"met-line\"><\/div><span class=\"met-lbl\">${t.dayRev}<\/span><\/div><div class=\"met-val\">${fmt(totalDailyEquiv)}<\/div><div class=\"met-sub\">${lines.length} ${t.active}<\/div><\/div>\n      <div class=\"met\"><div class=\"met-eye\"><div class=\"met-line\"><\/div><span class=\"met-lbl\">${t.monRev}<\/span><\/div><div class=\"met-val\">${fmt(totalMonthly)}<\/div><div class=\"met-sub\">\u00f7 12 months<\/div><\/div>\n      <div class=\"met\"><div class=\"met-eye\"><div class=\"met-line\"><\/div><span class=\"met-lbl\">${t.revparLift}<\/span><\/div><div class=\"met-val\" style=\"color:var(--red)\">+${revparLift.toFixed(2)}%<\/div><div class=\"met-sub\">${t.revpar}: ${fmtD(revpar)}<\/div><\/div>\n    <\/div>\n    ${breakdown}\n    <div class=\"revpar-pill\">+ ${revparLift.toFixed(2)}% ${t.revparLift} \u00b7 ${fmt(totalAnnual)} ${t.annRev.toLowerCase()}<\/div>\n  `;\n}\n\nfunction init(){ applyLang(); renderOffers(); calc(); }\nif(document.readyState==='loading'){ document.addEventListener('DOMContentLoaded',init); } else { init(); }\n<\/script>\n<\/body>\n<\/html>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>","protected":false},"excerpt":{"rendered":"<p>Front Desk Upsell Calculator | Torres Hospitality Consulting Torres Hospitality Consulting What can you sell at the front desk&amp; how much revenue can you generate? Activate<span class=\"excerpt-hellip\"> [\u2026]<\/span><\/p>","protected":false},"author":5,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-984","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/torreshospitalityconsulting.com\/en\/wp-json\/wp\/v2\/pages\/984","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/torreshospitalityconsulting.com\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/torreshospitalityconsulting.com\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/torreshospitalityconsulting.com\/en\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/torreshospitalityconsulting.com\/en\/wp-json\/wp\/v2\/comments?post=984"}],"version-history":[{"count":5,"href":"https:\/\/torreshospitalityconsulting.com\/en\/wp-json\/wp\/v2\/pages\/984\/revisions"}],"predecessor-version":[{"id":997,"href":"https:\/\/torreshospitalityconsulting.com\/en\/wp-json\/wp\/v2\/pages\/984\/revisions\/997"}],"wp:attachment":[{"href":"https:\/\/torreshospitalityconsulting.com\/en\/wp-json\/wp\/v2\/media?parent=984"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}