@magicfeedback/popup-sdk 1.4.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -182,7 +182,1775 @@ var init_font = __esm({
182
182
  var style_default;
183
183
  var init_style = __esm({
184
184
  "src/assets/style.css"() {
185
- style_default = '.magicfeedback-container {\n width: 100%;\n}\n\n\n.magicfeedback-success-message,\n.magicfeedback-info-message,\n.magicfeedback-start-message,\n.magicfeedback-container{\n animation-duration: 0.5s;\n animation-name: animate-fade;\n animation-delay: 0.25s;\n animation-fill-mode: backwards;\n\n font-style: normal;\n text-align: justify;\n font-weight: 400;\n font-size: 1.2rem;\n color: #475569;\n line-height: 1.5;\n}\n\n@keyframes animate-fade {\n 0% { opacity: 0; }\n 100% { opacity: 1; }\n}\n\n.magicfeedback-form {\n display: flex;\n flex-direction: column;\n justify-content: flex-start;\n align-items: center;\n width: 100%;\n}\n.magicfeedback-questions {\n display: flex;\n flex-direction: column;\n justify-content: flex-start;\n align-items: flex-start;\n width: 100%;\n}\n\n.magicfeedback-div {\n display: flex;\n flex-direction: column;\n justify-content: flex-start;\n align-items: flex-start;\n margin-bottom: 10px;\n width: 100%;\n}\n\n.magicfeedback-label {\n margin-bottom: 25px;\n margin-top: 20px;\n font-weight: 400;\n font-family: inherit;\n font-size: 1.2rem;\n color: #212529;\n text-align: start;\n word-wrap: break-word;\n white-space: normal;\n\n}\n\n.magicfeedback-checkbox {\n display: flex;\n flex-direction: column;\n flex-wrap: wrap;\n width: 100%;\n}\n\n.magicfeedback-checkbox-container {\n display: flex;\n flex-direction: row;\n justify-content: flex-start;\n align-items: center;\n margin-bottom: 5px;\n margin-top: 5px;\n}\n\n/* Cualificado con `div`: @magicfeedback/native reutiliza la clase "magicfeedback-radio"\n tambi\xE9n en el <input> de cada opci\xF3n (rating), y sin el tag este selector lo capturaba\n tambi\xE9n, rompiendo su tama\xF1o (el input pasaba a display:flex; width:100%). */\ndiv.magicfeedback-radio {\n display: flex;\n flex-direction: column;\n justify-content: flex-start;\n flex-wrap: wrap;\n width: 100%;\n margin-right: 5px;\n padding: 5px;\n box-sizing: border-box;\n}\n\n.magicfeedback-checkbox-container,\n.magicfeedback-radio-container {\n display: flex;\n flex-direction: row;\n justify-content: flex-start;\n align-items: center;\n margin: 5px;\n padding: 5px 0;\n background-color: #fff;\n border-radius: 5px;\n box-shadow: 0 0 3px #ccc;\n}\n\n.deepdots-popup input::-webkit-outer-spin-button,\n.deepdots-popup input::-webkit-inner-spin-button {\n -webkit-appearance: none;\n -moz-appearance: textfield;\n}\n\n.magicfeedback-checkbox input[type="checkbox"] {\n margin-right: 5px;\n margin-left: 5px;\n width: 20px;\n height: 20px;\n cursor: pointer;\n}\n\n\n.magicfeedback-checkbox label,\n.magicfeedback-radio-container label {\n margin-left: 5px;\n font-weight: 400;\n font-family: inherit;\n font-size: 16px;\n color: #212529;\n text-align: start;\n width: 100%;\n}\n\n.deepdots-popup p {\n margin-bottom: 0px;\n font-size: 12px;\n}\n\n.deepdots-popup h2 {\n line-height: 1.66;\n margin: 0;\n padding: 0;\n font-weight: 900;\n color: #222;\n font-family: var(--deepdots-font, \'Montserrat\');\n font-size: 18px;\n text-transform: uppercase;\n text-align: center;\n margin-bottom: 40px;\n}\n\n/* Los controles de formulario no heredan font-family por defecto: cuando hay\n fuente custom (clase deepdots-has-font), los forzamos a usar la del contenedor. */\n.deepdots-popup.deepdots-has-font button,\n.deepdots-popup.deepdots-has-font input,\n.deepdots-popup.deepdots-has-font textarea,\n.deepdots-popup.deepdots-has-font select {\n font-family: var(--deepdots-font, inherit);\n}\n\n.deepdots-popup h6 {\n margin-bottom: 1rem;\n}\n\n.deepdots-popup input[type="date"],\n.deepdots-popup input[type="text"],\n.deepdots-popup input[type="number"],\n.deepdots-popup input[type="email"],\n.deepdots-popup input[type="password"],\n.deepdots-popup textarea,\n.deepdots-popup select {\n box-sizing: border-box;\n padding: 10px;\n margin: 10px 0;\n width: 100%;\n border: 2px solid #ccc; /* Default border color - you can customize this */\n border-radius: 5px;\n font-size: 18px;\n outline: none;\n transition: border-color 0.3s ease;\n min-height: 50px;\n font-family: inherit;\n -webkit-appearance: none;\n}\n\n.deepdots-popup select {\n background-image: linear-gradient(45deg, transparent 50%, gray 50%),\n linear-gradient(135deg, gray 50%, transparent 50%),\n linear-gradient(to right, #ccc, #ccc);\n background-position: calc(100% - 20px) calc(1em + 2px),\n calc(100% - 15px) calc(1em + 2px),\n calc(100% - 2.5em) 0.5em;\n background-size: 5px 5px,\n 5px 5px,\n 1px 1.5em;\n background-repeat: no-repeat;\n}\n\n.magicfeedback-boolean-container {\n display: flex;\n flex-direction: row;\n justify-content: flex-start;\n align-items: center;\n margin: 10px 0;\n width: 100%;\n}\n\n.magicfeedback-boolean-container label {\n margin-left: 10px;\n font-weight: 400;\n font-size: 16px;\n width: 100%;\n padding-top: 5px;\n}\n\n.magicfeedback-boolean-option {\n margin-right: 10px;\n margin-left: 10px;\n width: 100%;\n height: 38px;\n border-radius: 8px;\n font-size: 16px;\n cursor: pointer;\n border: 1px solid #ced4da !important;\n}\n\n.magicfeedback-boolean-option label {\n font-weight: 400;\n font-size: 16px;\n color: #475569;\n cursor: pointer;\n width: 100%;\n height: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n border-radius: inherit;\n}\n\n.magicfeedback-boolean-option input[type=radio] + label:hover {\n color: #007bff;\n}\n\n.magicfeedback-boolean-option input[type=radio]:checked + label {\n color: #007bff;\n background-color: #cadff8;\n}\n\n.deepdots-popup input[type="radio"] {\n padding: 20px;\n margin: 10px 0 10px 15px;\n width: 40px;\n background-color: #fff;\n box-shadow: none;\n}\n\n/* Style for focused input/select */\n.deepdots-popup input:focus, .deepdots-popup select:focus {\n border-color: #4CAF50; /* Highlight color when focused - you can customize this */\n}\n\n/* Style for invalid input (example: validation error) */\n.deepdots-popup input.error, .deepdots-popup select.error {\n border-color: #ff3333; /* Red color for error state - you can customize this */\n}\n\n.magicfeedback-action-container {\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n margin-top: 10px;\n width: 100%;\n}\n\n.magicfeedback-action-container .magicfeedback-submit {\n cursor: pointer;\n padding: 10px;\n margin: 10px 0;\n width: 100px;\n border-radius: 8px;\n font-size: 16px;\n outline: none;\n transition: border-color 0.3s ease;\n background-color: #1E293B;\n color: white;\n}\n\n.magicfeedback-action-container .magicfeedback-back {\n cursor: pointer;\n padding: 10px;\n margin: 10px 0;\n width: 100px;\n border: 0;\n border-radius: 8px;\n font-size: 16px;\n outline: none;\n transition: border-color 0.3s ease;\n background-color: transparent;\n color: #212529;\n}\n\n\n\n/* Rating styles */\n.magicfeedback-rating {\n width: 100%;\n}\n\n.magicfeedback-rating-container {\n display: flex;\n flex-direction: row;\n justify-content: space-around;\n flex-wrap: wrap;\n align-items: center;\n\n margin: 15px 5px;\n padding: 0;\n\n list-style: none;\n font-size: 1.5rem;\n cursor: pointer;\n user-select: none;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n}\n\n.magicfeedback-rating-placeholder-value,\n.magicfeedback-rating-placeholder{\n text-align: center;\n align-content: center;\n justify-content: center;\n text-wrap: wrap;\n}\n\n.magicfeedback-rating-option {\n margin: 0 0.5rem;\n padding: 0;\n}\n\n@media (max-width: 1024px) {\n .magicfeedback-rating-option {\n margin: 10px 0;\n padding: 0;\n width: 20%;\n display: flex;\n justify-content: center;\n }\n\n .magicfeedback-rating-placeholder-value {\n font-size: 0.75rem;\n margin-bottom: 1px;\n }\n .magicfeedback-rating-placeholder{\n justify-content: center;\n }\n\n .magicfeedback-rating-container {\n flex-wrap: wrap;\n justify-content: flex-start;\n }\n}\n\n\n.magicfeedback-rating-option-label-container {\n display: flex;\n flex-direction: column;\n}\n\n\n.magicfeedback-rating-option-label-container label {\n display: inline-block;\n text-align: center;\n margin-bottom: 0;\n font-weight: 600;\n font-size: 18px;\n color: #475569;\n}\n\n.magicfeedback-rating-option-label-container input[type=radio] {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n}\n\n/* IMAGE STYLES */\n.magicfeedback-rating-option-label-container input[type=radio] + img {\n cursor: pointer;\n height: 48px;\n width: 48px;\n}\n\n/* LABEL STYLES */\n.magicfeedback-rating-option-label-container input[type=radio] + label {\n cursor: pointer;\n}\n\n/* CHECKED STYLES */\n.magicfeedback-rating-option-label-container input[type=radio]:checked + img {\n box-shadow: #007bff 0px 1px 4px, #007BFFA0 0px 0px 0px 2px;\n border-radius: 50%;\n}\n\n.magicfeedback-rating-number {\n width: 100%;\n}\n.magicfeedback-rating-container,\n.magicfeedback-rating-number-container {\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n\n margin: 15px 0;\n padding: 0;\n\n list-style: none;\n font-size: 1.5rem;\n cursor: pointer;\n user-select: none;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n}\n\n/* Cuando hay placeholders (Very bad / Very good), el placeholder ocupa\n el 100% de la primera l\xEDnea y los boxes bajan a la siguiente */\n.magicfeedback-rating-number-container--with-placeholder {\n flex-wrap: wrap;\n align-items: flex-start;\n}\n\n.magicfeedback-rating-number-container--with-placeholder .magicfeedback-rating-placeholder {\n width: 100%;\n margin-bottom: 8px;\n}\n\n.magicfeedback-rating-number-container--with-placeholder .magicfeedback-rating-number-option {\n width: auto;\n flex: 1;\n}\n\n.magicfeedback-rating-number-option {\n display: flex;\n flex-direction: row;\n justify-content: flex-start;\n align-items: center;\n margin: 5px;\n padding: 0;\n list-style: none;\n font-size: 1.5rem;\n cursor: pointer;\n user-select: none;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n width: 100%;\n}\n\n.magicfeedback-rating-number-option-row{\n max-width: 100% !important;\n}\n\n.magicfeedback-rating-number-top-placeholder,\n.magicfeedback-rating-number-bottom-placeholder{\n text-align: center !important;\n align-content: center;\n justify-content: center;\n text-wrap: wrap;\n\n font-size: 15px;\n color: #475569;\n\n width: 100%;\n margin: auto;\n}\n\n@media (min-width: 650px) {\n .magicfeedback-rating-number-option-row +.magicfeedback-rating-number-container-ltr:first-child,\n .magicfeedback-rating-number-option-row + +.magicfeedback-rating-number-container-rtl:last-child {\n margin-left: 0;\n width: calc(100% - 10px);\n }\n\n .magicfeedback-rating-number-option-row +.magicfeedback-rating-number-container-rtl:first-child,\n .magicfeedback-rating-number-option-row + +.magicfeedback-rating-number-container-ltr:last-child {\n margin-right: 0;\n width: calc(100% - 10px);\n }\n}\n\n\n.magicfeedback-rating-number-option-label-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n}\n\n.magicfeedback-rating-number-option-label-container label {\n display: flex;\n align-items: center;\n justify-content: center;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n margin: 0 10px;\n font-weight: 600;\n font-size: 14px;\n color: #475569;\n cursor: pointer;\n width: 100%;\n height: 100%;\n min-height: 50px;\n text-align: center;\n padding: 0;\n border-radius: 4px;\n border: 1px solid #ced4da;\n background-color: rgba(246, 246, 246, 0.3);\n transition: background-color 0.15s ease-in-out;\n}\n\n.magicfeedback-rating-number-option-label-container input[type=radio] {\n position: absolute;\n opacity: 0;\n width: 0;\n height: 0;\n}\n\n.magicfeedback-rating-number-option-label-container input[type=radio] + label {\n cursor: pointer;\n}\n\n.magicfeedback-rating-number-option-label-container input[type=radio] + label:hover,\n.magicfeedback-rating-number-option-label-container input[type=radio]:checked + label {\n color: #007bff;\n border: 1px solid #007bff;\n background-color: rgba(86, 168, 253, 0.29);\n}\n\n.magicfeedback-rating-number-container-column{\n align-items: flex-start !important;\n}\n\n@media (max-width: 650px) {\n .magicfeedback-rating-number-container-ltr {\n justify-content: center;\n flex-wrap: wrap;\n }\n\n .magicfeedback-rating-number-container-rtl {\n justify-content: center;\n flex-wrap: wrap-reverse;\n }\n\n .magicfeedback-rating-number-option {\n max-width: 100%;\n height: 55px;\n margin: 5px 0;\n }\n}\n\n.magicfeedback-rating-star {\n width: 100%;\n}\n\n.magicfeedback-rating-star-container {\n display: flex !important;\n flex-direction: row !important;\n justify-content: center !important;\n align-items: center !important;\n flex-wrap: wrap;\n margin: 15px 5px;\n padding: 0;\n list-style: none;\n font-size: 1.5rem;\n cursor: pointer;\n user-select: none;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n}\n\n.magicfeedback-rating-star-option:not(:checked) > .rating__star {\n float: right;\n width: 1em;\n overflow: hidden;\n white-space: nowrap;\n cursor: pointer;\n font-size: 30px;\n color: #ccc;\n margin: 0 10px;\n}\n\n.magicfeedback-rating-star-option:not(:checked) > .rating__star:hover,\n.magicfeedback-rating-star-option:not(:checked) > .rating__star:hover ~ span {\n color: #deb217 !important;\n}\n\n.magicfeedback-rating-star-selected {\n color: #ffc700 !important;\n}\n\n\n/* Style for multiple choice image */\n.magicfeedback-image-option-label-container:hover {\n cursor: pointer;\n border: 0 !important;\n}\n\n.magicfeedback-image-option-label-container input[type=radio]:checked + img,\n.magicfeedback-image-option-label-container input[type=checkbox]:checked + img {\n border: 1px solid #007bff !important;\n box-shadow: 0 0 3px #007bff !important;\n}\n\n.magicfeedback-image-option-label-container input[type=radio] + img,\n.magicfeedback-image-option-label-container input[type=checkbox] + img {\n border: 1px solid transparent !important;\n}\n\n.magicfeedback-image-option-label-container{\n margin: 10px !important;\n height: calc(100% - 20px) !important;\n width: calc(100% - 20px) !important;\n}\n\n.magicfeedback-multiple-choice-image-option {\n display: flex;\n height: auto !important;\n box-shadow: 0 0 3px #ccc;\n}\n\n.magicfeedback-multiple-choice-image-label {\n font-size: 1rem;\n}\n\n.magicfeedback-consent-container {\n display: flex;\n flex-direction: row;\n justify-content: flex-start;\n align-items: center;\n margin: 10px 0;\n width: 100%;\n}\n\n.magicfeedback-consent-container label {\n margin-left: 10px;\n}\n\n.magicfeedback-start-message-container {\n /* ... add your start message container styles here ... */\n}\n\n.magicfeedback-success-message,\n.magicfeedback-info-message,\n.magicfeedback-start-message {\n margin: 35px 5px;\n}\n\n.magicfeedback-success-message p,\n.magicfeedback-info-message p,\n.magicfeedback-start-message p {\n font-style: normal;\n text-align: start;\n font-weight: 400;\n font-size: 16px;\n color: #475569;\n line-height: 1.5;\n}\n\n.magicfeedback-success-message img,\n.magicfeedback-info-message img,\n.magicfeedback-start-message img {\n width: 400px;\n max-width: 80%;\n height: auto;\n margin: 10px auto;\n}\n\n.magicfeedback-counter,\n.magicfeedback-point-system-total {\n margin: 10px 0 0 0 !important;\n display: flex !important;\n justify-content: right !important;\n align-items: center !important;\n width: 100%;\n}\n\n.magicfeedback-skip-container {\n background-color: transparent !important;\n border: 0 !important;\n color: #999999FF !important;\n padding: 0 !important;\n margin: 0 !important;\n cursor: pointer !important;\n font-size: 0.5em !important;\n font-weight: 400 !important;\n box-shadow: 0 0 0 !important;\n\n &:hover {\n color: #0066ff;\n }\n}\n\n.magicfeedback-skip-container input[type=checkbox] {\n border-color: #999999FF !important;\n border: 0 !important;\n cursor: pointer !important;\n\n}\n\n.magicfeedback-multi-question-matrix,\n.magicfeedback-point-system,\n.magicfeedback-priority-list {\n width: 100% !important;\n}\n\n.magicfeedback-multi-question-matrix-container,\n.magicfeedback-point-system-container,\n.magicfeedback-priority-list-container {\n width: 100% !important;\n overflow-x: auto;\n}\n\n.magicfeedback-point-system-list,\n.magicfeedback-priority-list-list,\n.magicfeedback-multi-question-matrix-table {\n width: 100% !important;\n padding: 0 !important;\n overflow-x: auto;\n}\n\n.magicfeedback-multi-question-matrix {\n position: relative !important;\n}\n\n.magicfeedback-multi-question-matrix-container {\n overflow: auto !important;\n padding-bottom: 10px;\n}\n\n.magicfeedback-multi-question-matrix-label{\n text-align: left !important;\n}\n.magicfeedback-priority-list-item {\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n padding: 10px 0 10px 10px;\n\n border: 1px solid #ced4da;\n border-radius: 5px;\n margin: 10px 0 !important;\n}\n\n.magicfeedback-point-system-item {\n height: 45px;\n margin: 5px 0 !important;\n}\n\n.magicfeedback-point-system-item label,\n.magicfeedback-priority-list-item-label {\n font-family: inherit;\n font-size: 18px !important;\n color: #212529;\n text-align: start;\n word-wrap: break-word;\n white-space: normal;\n padding: 0 10px 0 0;\n}\n\n.magicfeedback-point-system-input-container {\n padding: 0 10px 0 0;\n border-radius: 5px;\n font-size: 14px;\n border: 1px solid #ced4da;\n height: 42px;\n margin: auto 0;\n}\n\n.magicfeedback-multi-question-matrix-table thead {\n margin-bottom: 20px;\n}\n\n.magicfeedback-multi-question-matrix-table th{\n text-align: center;\n font-weight: 400 !important;\n font-size: 1rem !important;\n padding: 0 10px !important;\n}\n\n.magicfeedback-multi-question-matrix-table th,\n.magicfeedback-multi-question-matrix-table td label,\n.magicfeedback-priority-list-arrow-up,\n.magicfeedback-priority-list-arrow-down {\n font-style: normal !important;\n font-weight: 400 !important;\n font-size: 1rem !important;\n color: #475569 !important;\n cursor: pointer !important;\n margin: 0 !important;\n line-height: inherit;\n}\n\n.magicfeedback-multi-question-matrix-table tr {\n align-items: center;\n margin: 5px 0;\n}\n\n.magicfeedback-multi-question-matrix-row-tr{\n border-radius: 5px;\n margin: 10px 0 !important;\n}\n\n.magicfeedback-multi-question-matrix-row-tr:nth-child(odd) {\n background-color: #f1f6f6; /* Light gray background for odd rows */\n}\n\n.magicfeedback-multi-question-matrix-row-tr:nth-child(even) {\n background-color: #ffffff; /* White background for even rows */\n}\n\n.magicfeedback-multi-question-matrix-row-label {\n text-align: left !important;\n}\n\n.magicfeedback-point-system-item span {\n color: #475569 !important;\n}\n\n.magicfeedback-point-system-item input {\n padding: 0;\n margin: 0 !important;\n width: auto !important;\n min-width: 100px !important;\n height: auto !important;\n min-height: 42px;\n cursor: pointer;\n font-size: 14px;\n text-align: center !important;\n}\n\n.magicfeedback-multi-question-matrix-table input {\n margin: auto !important;\n padding: 20px !important;\n width: 100% !important;\n height: 15px;\n border: 1px solid #ced4da;\n cursor: pointer;\n}\n\n.magicfeedback-image{\n max-height: 400px !important;\n height: auto !important;\n max-width: 100% !important;\n margin: 10px auto !important;\n}\n\n.magicfeedback-error{\n margin-top: 5px;\n}';
185
+ style_default = `/**
186
+ * NO EDITAR A MANO \u2014 generado por scripts/vendor-survey-css.mjs
187
+ *
188
+ * Copia de @magicfeedback/native@2.2.8 \u2192 dist/styles/magicfeedback-default.css
189
+ * (la hoja can\xF3nica del paquete, la que apunta su campo "style"), con estos cambios locales:
190
+ *
191
+ * 1. Sin el @import de Google Fonts (Nunito): no queremos una petici\xF3n externa desde la
192
+ * p\xE1gina del host, y la tipograf\xEDa la decide el popup.
193
+ * 2. .magicfeedback-container hereda la fuente del popup (var(--deepdots-font, inherit)).
194
+ * 3. Los selectores desnudos (h2, p, input, textarea, select, ::placeholder, .error) van
195
+ * acotados a .deepdots-popup: este CSS se inyecta en el <head> del host y sin acotar
196
+ * repintar\xEDa su web.
197
+ * 4. El grupo .magicfeedback-radio se cualifica como div.magicfeedback-radio (la clase acaba
198
+ * tambi\xE9n en el <input> del boolean).
199
+ * 5. Al final, un bloque de reglas propias del popup (fuente en los controles y padding del
200
+ * radio nativo).
201
+ *
202
+ * Las variables --mf-* se dejan en :root a prop\xF3sito: el modal del priority-list se portea a
203
+ * <body>, fuera de .deepdots-popup, y ah\xED las necesita.
204
+ *
205
+ * Para subir de versi\xF3n: npm i @magicfeedback/native@<v> && node scripts/vendor-survey-css.mjs
206
+ */
207
+
208
+ /**
209
+ * @magicfeedback/native - Default Styles
210
+ * Clean, minimal, and elegant survey rendering
211
+ */
212
+
213
+ /* @import de Google Fonts (Nunito) eliminado al vendorizar: la fuente la pone el popup. */
214
+
215
+ /* ========================================
216
+ CSS VARIABLES - Design SYSTEM
217
+ ======================================== */
218
+ :root {
219
+ /* Colors - Minimal Pastel */
220
+ /* --mf-primary is the one source of truth for brand/accent color \u2014
221
+ every token below derives from it via color-mix() (or references
222
+ it directly) so changing this single value, here or via a
223
+ per-integration override, keeps hover/light/border states in
224
+ sync automatically instead of going stale independently. Scoped
225
+ to genuinely interactive/accent surfaces (buttons, selected
226
+ chips, focus rings) \u2014 general body text stays on its own neutral
227
+ scale below, not tied to the brand color. */
228
+ --mf-primary: #5d7bad;
229
+ --mf-primary-hover: color-mix(in srgb, var(--mf-primary) 85%, black);
230
+ --mf-primary-light: color-mix(in srgb, var(--mf-primary) 15%, white);
231
+ /* a translucent tint \u2014 mixed with transparent (opacity), not white,
232
+ so it reads as a soft shadow of the brand color rather than a
233
+ pastel of it. */
234
+ --mf-primary-border: color-mix(in srgb, var(--mf-primary) 35%, transparent);
235
+
236
+ --mf-text-primary: #1E293B;
237
+ --mf-text-secondary: #475569;
238
+ --mf-text-muted: #94A3B8;
239
+
240
+ --mf-bg-primary: #F8FAFC;
241
+ --mf-bg-secondary: #FFFFFF;
242
+ --mf-bg-hover: #EEF2F6;
243
+
244
+ --mf-border: #E2E8F0;
245
+ --mf-border-focus: var(--mf-primary);
246
+
247
+ --mf-success: #16A34A;
248
+ --mf-error: #EF4444;
249
+ --mf-warning: #F59E0B;
250
+
251
+ --mf-surface: #FFFFFF;
252
+ --mf-surface-alt: #F1F5F9;
253
+ --mf-accent: #38BDF8;
254
+
255
+ /* Spacing */
256
+ --mf-space-xs: 0.25rem;
257
+ --mf-space-sm: 0.5rem;
258
+ --mf-space-md: 0.75rem;
259
+ --mf-space-lg: 1rem;
260
+ --mf-space-xl: 1.5rem;
261
+
262
+ /* Border Radius */
263
+ --mf-radius-sm: 0.5rem;
264
+ --mf-radius-md: 0.75rem;
265
+ --mf-radius-lg: 1.25rem;
266
+ --mf-radius-full: 9999px;
267
+
268
+ /* Shadows */
269
+ --mf-shadow-sm: 0 1px 2px 0 rgba(15, 23, 42, 0.06);
270
+ --mf-shadow-md: 0 8px 20px rgba(15, 23, 42, 0.08);
271
+ --mf-shadow-lg: 0 16px 30px rgba(15, 23, 42, 0.12);
272
+ --mf-shadow-focus: 0 0 0 3px rgba(30, 41, 59, 0.15);
273
+ --mf-shadow-card: 0 18px 40px rgba(15, 23, 42, 0.08);
274
+
275
+ /* Typography */
276
+ --mf-font-sans: "Nunito", "Quicksand", "Avenir Next", "Trebuchet MS", sans-serif;
277
+ --mf-font-size-sm: 0.875rem;
278
+ --mf-font-size-base: 1rem;
279
+ --mf-font-size-lg: 1.125rem;
280
+ --mf-font-size-xl: 1.25rem;
281
+ --mf-line-height: 1.6;
282
+
283
+ /* Font Weights */
284
+ --mf-font-weight-normal: 400;
285
+ --mf-font-weight-medium: 500;
286
+ --mf-font-weight-semibold: 600;
287
+ --mf-font-weight-bold: 700;
288
+ --mf-font-weight-extrabold: 800;
289
+
290
+ /* Transitions */
291
+ --mf-transition: all 0.2s ease;
292
+ --mf-transition-fast: all 0.15s ease;
293
+ }
294
+
295
+ /* ========================================
296
+ ANIMATIONS
297
+ ======================================== */
298
+ @keyframes mf-fade-in {
299
+ from {
300
+ opacity: 0;
301
+ transform: translateY(8px);
302
+ }
303
+ to {
304
+ opacity: 1;
305
+ transform: translateY(0);
306
+ }
307
+ }
308
+
309
+ @keyframes mf-slide-in {
310
+ from {
311
+ opacity: 0;
312
+ transform: translateX(-16px);
313
+ }
314
+ to {
315
+ opacity: 1;
316
+ transform: translateX(0);
317
+ }
318
+ }
319
+
320
+ @keyframes mf-scale-in {
321
+ from {
322
+ opacity: 0;
323
+ transform: scale(0.95);
324
+ }
325
+ to {
326
+ opacity: 1;
327
+ transform: scale(1);
328
+ }
329
+ }
330
+
331
+ @keyframes mf-pulse {
332
+ 0%,
333
+ 100% {
334
+ opacity: 1;
335
+ }
336
+ 50% {
337
+ opacity: 0.8;
338
+ }
339
+ }
340
+
341
+ /* ========================================
342
+ BASE CONTAINER
343
+ ======================================== */
344
+ .magicfeedback-container {
345
+ /* Local: hereda la fuente del popup; --deepdots-font viene de PopupStyle.font. */
346
+ font-family: var(--deepdots-font, inherit);
347
+ color: var(--mf-text-primary);
348
+ line-height: var(--mf-line-height);
349
+ animation: mf-fade-in 0.4s ease-out;
350
+ border-radius: var(--mf-radius-lg);
351
+ }
352
+
353
+ /* ========================================
354
+ MESSAGES
355
+ ======================================== */
356
+ .magicfeedback-success-message,
357
+ .magicfeedback-info-message,
358
+ .magicfeedback-start-message {
359
+ padding: var(--mf-space-lg);
360
+ margin: var(--mf-space-lg) 0;
361
+ animation: mf-scale-in 0.3s ease-out;
362
+ }
363
+
364
+ /* .magicfeedback-info-message/-start-message are set via innerHTML (see
365
+ renderInfoPage.ts / questions.service.ts's renderStartMessage) \u2014 whatever
366
+ rich text a survey author writes lands here as real HTML, not just the
367
+ <p>/<img> pair this used to style. Covering the rest of what a rich-text
368
+ editor commonly outputs (headings, lists, links, emphasis, quotes, code,
369
+ rules) keeps that content on the same type scale and palette as the rest
370
+ of the widget instead of falling back to unstyled browser defaults. */
371
+ .magicfeedback-success-message > :first-child,
372
+ .magicfeedback-info-message > :first-child,
373
+ .magicfeedback-start-message > :first-child {
374
+ margin-top: 0;
375
+ }
376
+
377
+ .magicfeedback-success-message > :last-child,
378
+ .magicfeedback-info-message > :last-child,
379
+ .magicfeedback-start-message > :last-child {
380
+ margin-bottom: 0;
381
+ }
382
+
383
+ .magicfeedback-success-message p,
384
+ .magicfeedback-info-message p,
385
+ .magicfeedback-start-message p {
386
+ font-size: var(--mf-font-size-base);
387
+ color: var(--mf-text-secondary);
388
+ margin: 0 0 var(--mf-space-md);
389
+ line-height: var(--mf-line-height);
390
+ }
391
+
392
+ .magicfeedback-info-message h1,
393
+ .magicfeedback-info-message h2,
394
+ .magicfeedback-info-message h3,
395
+ .magicfeedback-info-message h4,
396
+ .magicfeedback-info-message h5,
397
+ .magicfeedback-info-message h6,
398
+ .magicfeedback-start-message h1,
399
+ .magicfeedback-start-message h2,
400
+ .magicfeedback-start-message h3,
401
+ .magicfeedback-start-message h4,
402
+ .magicfeedback-start-message h5,
403
+ .magicfeedback-start-message h6 {
404
+ color: var(--mf-text-primary);
405
+ font-weight: var(--mf-font-weight-bold);
406
+ line-height: 1.3;
407
+ margin: var(--mf-space-lg) 0 var(--mf-space-sm);
408
+ text-align: left;
409
+ }
410
+
411
+ .magicfeedback-info-message h1, .magicfeedback-start-message h1 { font-size: var(--mf-font-size-xl); }
412
+ .magicfeedback-info-message h2, .magicfeedback-start-message h2 { font-size: var(--mf-font-size-lg); }
413
+ .magicfeedback-info-message h3,
414
+ .magicfeedback-info-message h4,
415
+ .magicfeedback-info-message h5,
416
+ .magicfeedback-info-message h6,
417
+ .magicfeedback-start-message h3,
418
+ .magicfeedback-start-message h4,
419
+ .magicfeedback-start-message h5,
420
+ .magicfeedback-start-message h6 { font-size: var(--mf-font-size-base); }
421
+
422
+ .magicfeedback-info-message strong,
423
+ .magicfeedback-info-message b,
424
+ .magicfeedback-start-message strong,
425
+ .magicfeedback-start-message b {
426
+ font-weight: var(--mf-font-weight-bold);
427
+ color: var(--mf-text-primary);
428
+ }
429
+
430
+ .magicfeedback-info-message a,
431
+ .magicfeedback-start-message a {
432
+ color: var(--mf-primary);
433
+ text-decoration: underline;
434
+ text-underline-offset: 2px;
435
+ }
436
+
437
+ .magicfeedback-info-message a:hover,
438
+ .magicfeedback-start-message a:hover {
439
+ color: var(--mf-primary-hover);
440
+ }
441
+
442
+ .magicfeedback-info-message ul,
443
+ .magicfeedback-info-message ol,
444
+ .magicfeedback-start-message ul,
445
+ .magicfeedback-start-message ol {
446
+ margin: 0 0 var(--mf-space-md);
447
+ padding-left: var(--mf-space-xl);
448
+ color: var(--mf-text-secondary);
449
+ line-height: var(--mf-line-height);
450
+ }
451
+
452
+ .magicfeedback-info-message li + li,
453
+ .magicfeedback-start-message li + li {
454
+ margin-top: var(--mf-space-xs);
455
+ }
456
+
457
+ .magicfeedback-info-message blockquote,
458
+ .magicfeedback-start-message blockquote {
459
+ margin: 0 0 var(--mf-space-md);
460
+ padding: var(--mf-space-sm) var(--mf-space-md);
461
+ border-left: 3px solid var(--mf-primary-border);
462
+ color: var(--mf-text-secondary);
463
+ font-style: italic;
464
+ }
465
+
466
+ .magicfeedback-info-message code,
467
+ .magicfeedback-start-message code {
468
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
469
+ font-size: 0.9em;
470
+ background: var(--mf-bg-hover);
471
+ padding: 0.15em 0.4em;
472
+ border-radius: var(--mf-radius-sm);
473
+ }
474
+
475
+ .magicfeedback-info-message pre,
476
+ .magicfeedback-start-message pre {
477
+ margin: 0 0 var(--mf-space-md);
478
+ padding: var(--mf-space-md);
479
+ background: var(--mf-bg-hover);
480
+ border-radius: var(--mf-radius-md);
481
+ overflow-x: auto;
482
+ }
483
+
484
+ .magicfeedback-info-message pre code,
485
+ .magicfeedback-start-message pre code {
486
+ background: none;
487
+ padding: 0;
488
+ }
489
+
490
+ .magicfeedback-info-message hr,
491
+ .magicfeedback-start-message hr {
492
+ border: none;
493
+ border-top: 1px solid var(--mf-border);
494
+ margin: var(--mf-space-lg) 0;
495
+ }
496
+
497
+ .magicfeedback-success-message img,
498
+ .magicfeedback-info-message img,
499
+ .magicfeedback-start-message img {
500
+ max-width: 100%;
501
+ height: auto;
502
+ margin: var(--mf-space-lg) auto;
503
+ display: block;
504
+ border-radius: var(--mf-radius-md);
505
+ }
506
+
507
+ .magicfeedback-image {
508
+ max-height: 400px;
509
+ height: auto;
510
+ max-width: 100%;
511
+ margin: var(--mf-space-lg) auto;
512
+ display: block;
513
+ border-radius: var(--mf-radius-md);
514
+ }
515
+
516
+ /* ========================================
517
+ FORM STRUCTURE
518
+ ======================================== */
519
+ .magicfeedback-form {
520
+ display: flex;
521
+ flex-direction: column;
522
+ gap: var(--mf-space-lg);
523
+ padding: clamp(16px, 2.5vw, 28px);
524
+ }
525
+
526
+ .magicfeedback-questions {
527
+ display: flex;
528
+ flex-direction: column;
529
+ gap: var(--mf-space-xl);
530
+ width: 100%;
531
+ }
532
+
533
+ .magicfeedback-div {
534
+ display: flex;
535
+ flex-direction: column;
536
+ gap: var(--mf-space-sm);
537
+ animation: mf-slide-in 0.3s ease-out;
538
+ background: var(--mf-bg-secondary);
539
+ border-radius: var(--mf-radius-md);
540
+ }
541
+
542
+ /* ========================================
543
+ LABELS & TYPOGRAPHY
544
+ ======================================== */
545
+ .magicfeedback-label {
546
+ font-size: var(--mf-font-size-lg);
547
+ font-weight: var(--mf-font-weight-bold);
548
+ color: var(--mf-text-primary);
549
+ line-height: var(--mf-line-height);
550
+ text-align: left;
551
+ letter-spacing: -0.01em;
552
+ }
553
+
554
+ .magicfeedback-sublabel {
555
+ font-size: var(--mf-font-size-base);
556
+ font-weight: var(--mf-font-weight-normal);
557
+ color: var(--mf-text-secondary);
558
+ margin-bottom: var(--mf-space-sm);
559
+ }
560
+
561
+ .deepdots-popup h2 {
562
+ font-size: var(--mf-font-size-xl);
563
+ font-weight: 600;
564
+ color: var(--mf-text-primary);
565
+ margin: 0 0 var(--mf-space-xl) 0;
566
+ text-align: center;
567
+ letter-spacing: -0.01em;
568
+ }
569
+
570
+ .deepdots-popup p {
571
+ margin: 0;
572
+ font-size: var(--mf-font-size-sm);
573
+ color: var(--mf-text-secondary);
574
+ }
575
+
576
+ /* ========================================
577
+ FORM INPUTS
578
+ ======================================== */
579
+ .deepdots-popup input[type="date"],
580
+ .deepdots-popup input[type="text"],
581
+ .deepdots-popup input[type="number"],
582
+ .deepdots-popup input[type="email"],
583
+ .deepdots-popup input[type="password"],
584
+ .deepdots-popup textarea,
585
+ .deepdots-popup select {
586
+ padding: 0.75rem 0.9rem;
587
+ font-size: var(--mf-font-size-base);
588
+ font-family: inherit;
589
+ color: var(--mf-text-primary);
590
+ background-color: var(--mf-surface);
591
+ border: 2px solid var(--mf-border);
592
+ border-radius: var(--mf-radius-md);
593
+ outline: none;
594
+ transition: var(--mf-transition);
595
+ -webkit-appearance: none;
596
+ appearance: none;
597
+ box-shadow: var(--mf-shadow-sm);
598
+ }
599
+
600
+ .deepdots-popup textarea {
601
+ min-height: 100px;
602
+ resize: vertical;
603
+ }
604
+
605
+ .deepdots-popup input::placeholder,
606
+ .deepdots-popup textarea::placeholder {
607
+ color: var(--mf-text-muted);
608
+ }
609
+
610
+ /* Remove number input spinners */
611
+ .deepdots-popup input::-webkit-outer-spin-button,
612
+ .deepdots-popup input::-webkit-inner-spin-button {
613
+ -webkit-appearance: none;
614
+ margin: 0;
615
+ }
616
+
617
+ .deepdots-popup input[type="number"] {
618
+ /* -moz-appearance: textfield; removed for lint compatibility */
619
+ }
620
+
621
+ /* Custom Select Arrow */
622
+ .deepdots-popup select {
623
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%2364748b' d='M6 9L1 4h10z'/%3E%3C/svg%3E");
624
+ background-repeat: no-repeat;
625
+ background-position: right var(--mf-space-md) center;
626
+ padding-right: var(--mf-space-xl);
627
+ }
628
+
629
+ /* Error State */
630
+ .deepdots-popup input.error,
631
+ .deepdots-popup select.error,
632
+ .deepdots-popup textarea.error {
633
+ border-color: var(--mf-error);
634
+ }
635
+
636
+ .magicfeedback-error {
637
+ margin-top: var(--mf-space-xs);
638
+ font-size: var(--mf-font-size-sm);
639
+ color: var(--mf-error);
640
+ }
641
+
642
+ /* ========================================
643
+ CHECKBOX & RADIO OPTIONS
644
+ ======================================== */
645
+ .magicfeedback-checkbox,
646
+ div.magicfeedback-radio {
647
+ display: flex;
648
+ flex-direction: column;
649
+ gap: var(--mf-space-sm);
650
+ width: 100%;
651
+ }
652
+
653
+ .magicfeedback-checkbox-container,
654
+ .magicfeedback-radio-container {
655
+ display: flex;
656
+ align-items: center;
657
+ gap: var(--mf-space-sm);
658
+ padding: var(--mf-space-md);
659
+ border: 1.5px solid var(--mf-border);
660
+ border-radius: var(--mf-radius-md);
661
+ cursor: pointer;
662
+ transition: var(--mf-transition-fast);
663
+ }
664
+
665
+ .magicfeedback-checkbox-container:hover,
666
+ .magicfeedback-radio-container:hover {
667
+ background-color: var(--mf-bg-hover);
668
+ border-color: var(--mf-primary);
669
+ }
670
+
671
+ .magicfeedback-checkbox-container:has(input:checked),
672
+ .magicfeedback-radio-container:has(input:checked) {
673
+ background-color: var(--mf-primary-light);
674
+ border-color: var(--mf-primary);
675
+ }
676
+
677
+ .magicfeedback-checkbox input[type="checkbox"],
678
+ .magicfeedback-radio-container input[type="radio"] {
679
+ width: 18px;
680
+ height: 18px;
681
+ margin: 0;
682
+ cursor: pointer;
683
+ flex-shrink: 0;
684
+ accent-color: var(--mf-primary);
685
+ }
686
+
687
+ .magicfeedback-checkbox label,
688
+ .magicfeedback-radio-container label {
689
+ font-size: var(--mf-font-size-base);
690
+ text-align: left;
691
+ color: var(--mf-text-primary);
692
+ cursor: pointer;
693
+ margin: 0;
694
+ flex: 1;
695
+ }
696
+
697
+ /* ========================================
698
+ BOOLEAN OPTIONS
699
+ ======================================== */
700
+ .magicfeedback-boolean-container {
701
+ display: flex;
702
+ gap: var(--mf-space-md);
703
+ width: 100%;
704
+ }
705
+
706
+ .magicfeedback-boolean-option {
707
+ flex: 1;
708
+ position: relative;
709
+ }
710
+
711
+ .magicfeedback-boolean-option input[type="radio"] {
712
+ position: absolute;
713
+ opacity: 0;
714
+ width: 0;
715
+ height: 0;
716
+ }
717
+
718
+ .magicfeedback-boolean-option label {
719
+ display: flex;
720
+ align-items: center;
721
+ justify-content: center;
722
+ padding: var(--mf-space-md);
723
+ font-size: var(--mf-font-size-base);
724
+ font-weight: 500;
725
+ color: var(--mf-text-secondary);
726
+ border: 1.5px solid var(--mf-border);
727
+ border-radius: var(--mf-radius-md);
728
+ cursor: pointer;
729
+ transition: var(--mf-transition-fast);
730
+ margin: 0;
731
+ width: -webkit-fill-available;
732
+ height: inherit;
733
+ }
734
+
735
+ .magicfeedback-boolean-option label:hover {
736
+ background-color: var(--mf-bg-hover);
737
+ border-color: var(--mf-primary);
738
+ }
739
+
740
+ .magicfeedback-boolean-option input[type="radio"]:checked + label {
741
+ color: var(--mf-primary);
742
+ background-color: var(--mf-primary-light);
743
+ border-color: var(--mf-primary);
744
+ font-weight: 600;
745
+ }
746
+
747
+ /* ========================================
748
+ RATING SYSTEMS
749
+ ======================================== */
750
+ .magicfeedback-rating,
751
+ .magicfeedback-rating-number,
752
+ .magicfeedback-rating-star {
753
+ width: 100%;
754
+ }
755
+
756
+ .magicfeedback-rating-container,
757
+ .magicfeedback-rating-number-container,
758
+ .magicfeedback-rating-star-container {
759
+ display: flex;
760
+ flex-wrap: wrap;
761
+ gap: var(--mf-space-sm);
762
+ justify-content: center;
763
+ align-items: center;
764
+ padding: var(--mf-space-md) 0;
765
+ list-style: none;
766
+ margin: 0;
767
+ }
768
+
769
+ /* Caption line below the row \u2014 min on one side, max on the other (swapped
770
+ for order: "rtl") \u2014 same simple, non-responsive pattern as the
771
+ rating-number row caption. Used by rating-star and rating-emoji. */
772
+ .magicfeedback-rating-placeholder {
773
+ display: flex;
774
+ justify-content: space-between;
775
+ gap: var(--mf-space-md);
776
+ width: 100%;
777
+ margin-top: var(--mf-space-sm);
778
+ font-size: var(--mf-font-size-sm);
779
+ font-weight: var(--mf-font-weight-semibold);
780
+ color: var(--mf-text-secondary);
781
+ }
782
+
783
+ .magicfeedback-rating-placeholder-value {
784
+ overflow-wrap: anywhere;
785
+ }
786
+
787
+ .magicfeedback-rating-placeholder-value:last-child {
788
+ text-align: right;
789
+ }
790
+
791
+ /* Rating with Images */
792
+ .magicfeedback-rating-option-label-container input[type="radio"] {
793
+ position: absolute;
794
+ opacity: 0;
795
+ width: 0;
796
+ height: 0;
797
+ }
798
+
799
+ .magicfeedback-rating-option-label-container img {
800
+ width: 56px;
801
+ height: 56px;
802
+ cursor: pointer;
803
+ transition: var(--mf-transition-fast);
804
+ border-radius: var(--mf-radius-full);
805
+ border: 2px solid transparent;
806
+ }
807
+
808
+ .magicfeedback-rating-option-label-container img:hover {
809
+ transform: scale(1.1);
810
+ border-color: var(--mf-primary);
811
+ }
812
+
813
+ .magicfeedback-rating-option-label-container input[type="radio"]:checked + img {
814
+ border-color: var(--mf-primary);
815
+ box-shadow: 0 0 0 3px var(--mf-primary-light);
816
+ }
817
+
818
+ .magicfeedback-rating-option-label-container label {
819
+ display: block;
820
+ text-align: center;
821
+ font-size: var(--mf-font-size-sm);
822
+ color: var(--mf-text-secondary);
823
+ margin-top: var(--mf-space-xs);
824
+ cursor: pointer;
825
+ }
826
+
827
+ /* Rating Numbers \u2014 each option is its own outlined chip in the survey's
828
+ primary color, with a gap between them. Row and column use the same
829
+ chip; column additionally has room to show each option's own text
830
+ plainly next to its number. */
831
+
832
+ /* Every size here is width:100%/flex:1 combined with the chip's own
833
+ padding and border. Without border-box, the browser's default
834
+ content-box adds that padding/border on TOP of the declared size, so
835
+ the chip quietly overflows past its flex slot \u2014 reading as "not quite
836
+ full width" or, worse, pushing into the next chip. */
837
+ .magicfeedback-rating-number-container,
838
+ .magicfeedback-rating-number-option,
839
+ .magicfeedback-rating-number-option-label-container,
840
+ .magicfeedback-rating-number-value {
841
+ box-sizing: border-box;
842
+ }
843
+
844
+ /* The shared rating-container rule (above, reused by star rating) sets
845
+ align-items:center for its row-of-chips layout \u2014 in a stacked column
846
+ that still nudges a 100%-wide chip inward instead of a true 0 offset.
847
+ Force stretch so every chip fills the exact same width, flush on
848
+ both sides. */
849
+ .magicfeedback-rating-number-container-column,
850
+ .magicfeedback-rating-number-container-column-reverse {
851
+ align-items: stretch;
852
+ }
853
+
854
+ /* Caption line below the row \u2014 the single place min/max labels live
855
+ for row mode, shared by mobile and desktop. */
856
+ .magicfeedback-rating-number-scale-labels {
857
+ display: flex;
858
+ justify-content: space-between;
859
+ gap: var(--mf-space-md);
860
+ margin-top: var(--mf-space-sm);
861
+ font-size: var(--mf-font-size-sm);
862
+ font-weight: var(--mf-font-weight-semibold);
863
+ color: var(--mf-text-secondary);
864
+ }
865
+
866
+ .magicfeedback-rating-number-scale-label {
867
+ overflow-wrap: anywhere;
868
+ }
869
+
870
+ .magicfeedback-rating-number-scale-label:last-child {
871
+ text-align: right;
872
+ }
873
+
874
+ /* Column, no per-option text: each row is its own separated chip, so
875
+ the min/max labels bookend the stack from outside it \u2014 one line
876
+ above the first chip, one below the last. Margin goes on whichever
877
+ side actually faces the list \u2014 the "before" label (always the first
878
+ child) gets space below it, the "after" one (always right after the
879
+ container, extra option row or not) gets space above it \u2014 so both
880
+ sit the same distance from the chips regardless of which one it is. */
881
+ .magicfeedback-rating-number-scale-label-block {
882
+ font-size: var(--mf-font-size-sm);
883
+ font-weight: var(--mf-font-weight-semibold);
884
+ color: var(--mf-text-secondary);
885
+ text-align: center;
886
+ }
887
+
888
+ .magicfeedback-rating-number-scale-label-block:first-child {
889
+ margin-bottom: var(--mf-space-sm);
890
+ }
891
+
892
+ .magicfeedback-rating-number-container + .magicfeedback-rating-number-scale-label-block {
893
+ margin-top: var(--mf-space-sm);
894
+ }
895
+
896
+ .magicfeedback-rating-number-option {
897
+ display: flex;
898
+ }
899
+
900
+ .magicfeedback-rating-number-option-label-container {
901
+ position: relative;
902
+ width: 100%;
903
+ display: flex;
904
+ cursor: pointer;
905
+ }
906
+
907
+ .magicfeedback-rating-number-option-label-container input[type="radio"] {
908
+ position: absolute;
909
+ opacity: 0;
910
+ width: 0;
911
+ height: 0;
912
+ }
913
+
914
+ .magicfeedback-rating-number-value {
915
+ display: flex;
916
+ align-items: center;
917
+ justify-content: center;
918
+ width: 100%;
919
+ transition: var(--mf-transition-fast);
920
+ color: var(--mf-text-secondary);
921
+ font-weight: var(--mf-font-weight-semibold);
922
+ }
923
+
924
+ /* Row: individual outlined chips in the survey's own primary color \u2014
925
+ var(--mf-primary) so whatever brand color a given survey sets carries
926
+ through automatically, no color hardcoded here. */
927
+ .magicfeedback-rating-number-container-row,
928
+ .magicfeedback-rating-number-container-row-reverse {
929
+ flex-wrap: nowrap;
930
+ gap: var(--mf-space-sm);
931
+ }
932
+
933
+ .magicfeedback-rating-number-option-row,
934
+ .magicfeedback-rating-number-option-row-reverse {
935
+ flex: 1 1 0;
936
+ min-width: 0;
937
+ }
938
+
939
+ .magicfeedback-rating-number-option-row .magicfeedback-rating-number-value,
940
+ .magicfeedback-rating-number-option-row-reverse .magicfeedback-rating-number-value {
941
+ min-height: 56px;
942
+ padding: var(--mf-space-sm);
943
+ border: 2px solid var(--mf-primary-border);
944
+ border-radius: var(--mf-radius-md);
945
+ background: var(--mf-bg-secondary);
946
+ color: var(--mf-primary);
947
+ font-size: var(--mf-font-size-lg);
948
+ font-weight: var(--mf-font-weight-bold);
949
+ }
950
+
951
+ /* More than 6 options (e.g. a 0-10 NPS scale): still one row, never
952
+ wraps \u2014 but scaled down on purpose, so it reads as a compact chip
953
+ rather than the same 56px button stretched thin. */
954
+ .magicfeedback-rating-number-container-row--dense .magicfeedback-rating-number-option-row .magicfeedback-rating-number-value,
955
+ .magicfeedback-rating-number-container-row--dense .magicfeedback-rating-number-option-row-reverse .magicfeedback-rating-number-value {
956
+ min-height: 36px;
957
+ padding: var(--mf-space-xs);
958
+ border-radius: var(--mf-radius-sm);
959
+ font-size: 0.8rem;
960
+ }
961
+
962
+ .magicfeedback-rating-number-option-row .magicfeedback-rating-number-option-label-container:hover .magicfeedback-rating-number-value,
963
+ .magicfeedback-rating-number-option-row-reverse .magicfeedback-rating-number-option-label-container:hover .magicfeedback-rating-number-value {
964
+ background: var(--mf-primary-light);
965
+ }
966
+
967
+ .magicfeedback-rating-number-option-row .magicfeedback-rating-number-option-label-container input[type="radio"]:checked + .magicfeedback-rating-number-value,
968
+ .magicfeedback-rating-number-option-row-reverse .magicfeedback-rating-number-option-label-container input[type="radio"]:checked + .magicfeedback-rating-number-value {
969
+ color: #fff;
970
+ background-color: var(--mf-primary);
971
+ box-shadow: var(--mf-shadow-md);
972
+ }
973
+
974
+ /* Extra option: always its own row below the scale, and styled like every
975
+ other chip now \u2014 "doesn't apply" is still not a point on the 1..N
976
+ continuum, but it no longer needs a different border style to say so. */
977
+ .magicfeedback-rating-number-extra-row {
978
+ display: flex;
979
+ justify-content: center;
980
+ margin-top: var(--mf-space-sm);
981
+ }
982
+
983
+ .magicfeedback-rating-number-option--extra {
984
+ flex: 0 1 auto;
985
+ }
986
+
987
+ .magicfeedback-rating-number-option--extra .magicfeedback-rating-number-option-label-container {
988
+ width: auto;
989
+ }
990
+
991
+ .magicfeedback-rating-number-option--extra .magicfeedback-rating-number-value {
992
+ min-height: 36px;
993
+ padding: 0 var(--mf-space-md);
994
+ border: 2px solid var(--mf-primary-border);
995
+ border-radius: var(--mf-radius-md);
996
+ background: var(--mf-bg-secondary);
997
+ color: var(--mf-primary);
998
+ font-size: var(--mf-font-size-sm);
999
+ }
1000
+
1001
+ .magicfeedback-rating-number-option--extra .magicfeedback-rating-number-option-label-container:hover .magicfeedback-rating-number-value {
1002
+ background: var(--mf-primary-light);
1003
+ }
1004
+
1005
+ .magicfeedback-rating-number-option--extra .magicfeedback-rating-number-option-label-container input[type="radio"]:checked + .magicfeedback-rating-number-value {
1006
+ color: #fff;
1007
+ background-color: var(--mf-primary);
1008
+ box-shadow: var(--mf-shadow-md);
1009
+ }
1010
+
1011
+ /* Column: the same separated chips as row, just stacked \u2014 each option is
1012
+ its own outlined chip with a gap between them, not one shared box. */
1013
+ .magicfeedback-rating-number-container-column,
1014
+ .magicfeedback-rating-number-container-column-reverse {
1015
+ gap: var(--mf-space-sm);
1016
+ }
1017
+
1018
+ .magicfeedback-rating-number-option-column,
1019
+ .magicfeedback-rating-number-option-column-reverse {
1020
+ width: 100%;
1021
+ }
1022
+
1023
+ .magicfeedback-rating-number-option-column .magicfeedback-rating-number-value,
1024
+ .magicfeedback-rating-number-option-column-reverse .magicfeedback-rating-number-value {
1025
+ justify-content: flex-start;
1026
+ gap: var(--mf-space-sm);
1027
+ min-height: 48px;
1028
+ padding: var(--mf-space-sm) var(--mf-space-md);
1029
+ border: 2px solid var(--mf-primary-border);
1030
+ border-radius: var(--mf-radius-md);
1031
+ background: var(--mf-bg-secondary);
1032
+ color: var(--mf-primary);
1033
+ }
1034
+
1035
+ .magicfeedback-rating-number-option-column .magicfeedback-rating-number-option-label-container:hover .magicfeedback-rating-number-value,
1036
+ .magicfeedback-rating-number-option-column-reverse .magicfeedback-rating-number-option-label-container:hover .magicfeedback-rating-number-value {
1037
+ background: var(--mf-primary-light);
1038
+ }
1039
+
1040
+ .magicfeedback-rating-number-option-column .magicfeedback-rating-number-option-label-container input[type="radio"]:checked + .magicfeedback-rating-number-value,
1041
+ .magicfeedback-rating-number-option-column-reverse .magicfeedback-rating-number-option-label-container input[type="radio"]:checked + .magicfeedback-rating-number-value {
1042
+ color: #fff;
1043
+ background-color: var(--mf-primary);
1044
+ box-shadow: var(--mf-shadow-md);
1045
+ }
1046
+
1047
+ .magicfeedback-rating-number-value-num {
1048
+ font-weight: var(--mf-font-weight-bold);
1049
+ }
1050
+
1051
+ /* Column with per-option text: a min-width so "1".."9" and "10" line up,
1052
+ with the label text starting at the same x. Skipped entirely when the
1053
+ column has no per-option text at all (--bare below) \u2014 with nothing to
1054
+ align against, the same left-shift bug from row mode would resurface. */
1055
+ .magicfeedback-rating-number-container-column:not(.magicfeedback-rating-number-container-column--bare) .magicfeedback-rating-number-value-num,
1056
+ .magicfeedback-rating-number-container-column-reverse:not(.magicfeedback-rating-number-container-column--bare) .magicfeedback-rating-number-value-num {
1057
+ flex: none;
1058
+ min-width: 1.4em;
1059
+ }
1060
+
1061
+ /* Column, no per-option text at all (only min/max, or nothing): a bare
1062
+ numbered list has nothing to left-align against, so center each
1063
+ number instead of stranding it on the left with blank space beside it. */
1064
+ .magicfeedback-rating-number-container-column--bare .magicfeedback-rating-number-value {
1065
+ justify-content: center;
1066
+ }
1067
+
1068
+ .magicfeedback-rating-number-value-label {
1069
+ font-weight: var(--mf-font-weight-medium);
1070
+ }
1071
+
1072
+ .magicfeedback-rating-number-option-column .magicfeedback-rating-number-option-label-container input[type="radio"]:checked + .magicfeedback-rating-number-value,
1073
+ .magicfeedback-rating-number-option-column-reverse .magicfeedback-rating-number-option-label-container input[type="radio"]:checked + .magicfeedback-rating-number-value {
1074
+ color: #fff;
1075
+ background-color: var(--mf-primary);
1076
+ }
1077
+
1078
+ /* Star Rating */
1079
+ .magicfeedback-rating-star-container {
1080
+ justify-content: center;
1081
+ }
1082
+
1083
+ .magicfeedback-rating-star-option:not(:checked) > .rating__star {
1084
+ font-size: 40px;
1085
+ color: var(--mf-border);
1086
+ cursor: pointer;
1087
+ margin: 0 var(--mf-space-xs);
1088
+ transition: var(--mf-transition-fast);
1089
+ }
1090
+
1091
+ .magicfeedback-rating-star-option:not(:checked) > .rating__star:hover,
1092
+ .magicfeedback-rating-star-option:not(:checked) > .rating__star:hover ~ span {
1093
+ color: #fbbf24;
1094
+ transform: scale(1.1);
1095
+ }
1096
+
1097
+ .magicfeedback-rating-star-selected {
1098
+ color: #fbbf24 !important;
1099
+ }
1100
+
1101
+ /* ========================================
1102
+ MULTIPLE CHOICE WITH IMAGES
1103
+ ======================================== */
1104
+ .magicfeedback-multiple-choice-image-option {
1105
+ display: flex;
1106
+ border-radius: var(--mf-radius-md);
1107
+ overflow: hidden;
1108
+ transition: var(--mf-transition-fast);
1109
+ }
1110
+
1111
+ .magicfeedback-image-option-label-container {
1112
+ cursor: pointer;
1113
+ border-radius: var(--mf-radius-md);
1114
+ overflow: hidden;
1115
+ transition: var(--mf-transition-fast);
1116
+ }
1117
+
1118
+ .magicfeedback-image-option-label-container input[type="radio"],
1119
+ .magicfeedback-image-option-label-container input[type="checkbox"] {
1120
+ position: absolute;
1121
+ opacity: 0;
1122
+ width: 0;
1123
+ height: 0;
1124
+ }
1125
+
1126
+ .magicfeedback-image-option-label-container img {
1127
+ width: 100%;
1128
+ height: auto;
1129
+ display: block;
1130
+ border: 2px solid var(--mf-border);
1131
+ border-radius: var(--mf-radius-md);
1132
+ transition: var(--mf-transition-fast);
1133
+ }
1134
+
1135
+ .magicfeedback-image-option-label-container:hover img {
1136
+ border-color: var(--mf-primary);
1137
+ box-shadow: var(--mf-shadow-md);
1138
+ }
1139
+
1140
+ .magicfeedback-image-option-label-container input:checked + img {
1141
+ border-color: var(--mf-primary);
1142
+ box-shadow: 0 0 0 3px var(--mf-primary-light);
1143
+ }
1144
+
1145
+ /* ========================================
1146
+ MATRIX QUESTIONS
1147
+ ======================================== */
1148
+ .magicfeedback-multi-question-matrix-container {
1149
+ width: 100%;
1150
+ overflow-x: auto;
1151
+ border-radius: var(--mf-radius-md);
1152
+ }
1153
+
1154
+ .magicfeedback-multi-question-matrix-table {
1155
+ width: 100%;
1156
+ border-collapse: separate;
1157
+ border-spacing: 0 var(--mf-space-xs);
1158
+ }
1159
+
1160
+ .magicfeedback-multi-question-matrix-table th {
1161
+ padding: var(--mf-space-md);
1162
+ text-align: center;
1163
+ font-size: var(--mf-font-size-sm);
1164
+ font-weight: 500;
1165
+ color: var(--mf-text-secondary);
1166
+ }
1167
+
1168
+ .magicfeedback-multi-question-matrix-row-tr {
1169
+ background-color: var(--mf-bg-primary);
1170
+ border-radius: var(--mf-radius-md);
1171
+ transition: var(--mf-transition-fast);
1172
+ }
1173
+
1174
+ .magicfeedback-multi-question-matrix-row-tr:nth-child(even) {
1175
+ background-color: var(--mf-bg-secondary);
1176
+ }
1177
+
1178
+ .magicfeedback-multi-question-matrix-row-tr:hover {
1179
+ background-color: var(--mf-bg-hover);
1180
+ box-shadow: var(--mf-shadow-sm);
1181
+ }
1182
+
1183
+ .magicfeedback-multi-question-matrix-table td {
1184
+ padding: var(--mf-space-md);
1185
+ text-align: center;
1186
+ }
1187
+
1188
+ .magicfeedback-multi-question-matrix-label {
1189
+ text-align: left;
1190
+ font-size: var(--mf-font-size-base);
1191
+ color: var(--mf-text-primary);
1192
+ }
1193
+
1194
+ .magicfeedback-multi-question-matrix-table input[type="radio"] {
1195
+ width: 20px;
1196
+ height: 20px;
1197
+ cursor: pointer;
1198
+ accent-color: var(--mf-primary);
1199
+ }
1200
+
1201
+ /* ========================================
1202
+ PRIORITY LIST
1203
+ ======================================== */
1204
+ .magicfeedback-priority-list-item {
1205
+ display: flex;
1206
+ align-items: center;
1207
+ justify-content: space-between;
1208
+ padding: var(--mf-space-md);
1209
+ margin: var(--mf-space-sm) 0;
1210
+ background-color: var(--mf-bg-primary);
1211
+ border: 1.5px solid var(--mf-border);
1212
+ border-radius: var(--mf-radius-md);
1213
+ transition: var(--mf-transition-fast);
1214
+ }
1215
+
1216
+ .magicfeedback-priority-list-item:hover {
1217
+ box-shadow: var(--mf-shadow-sm);
1218
+ border-color: var(--mf-primary);
1219
+ }
1220
+
1221
+ .magicfeedback-priority-list-item-label {
1222
+ flex: 1;
1223
+ font-size: var(--mf-font-size-base);
1224
+ text-align: left;
1225
+ color: var(--mf-text-primary);
1226
+ margin: 0;
1227
+ }
1228
+
1229
+ .magicfeedback-priority-list-arrow-up,
1230
+ .magicfeedback-priority-list-arrow-down {
1231
+ padding: var(--mf-space-xs);
1232
+ font-size: var(--mf-font-size-lg);
1233
+ color: var(--mf-text-secondary);
1234
+ cursor: pointer;
1235
+ transition: var(--mf-transition-fast);
1236
+ user-select: none;
1237
+ }
1238
+
1239
+ .magicfeedback-priority-list-arrow-up:hover,
1240
+ .magicfeedback-priority-list-arrow-down:hover {
1241
+ color: var(--mf-primary);
1242
+ transform: scale(1.2);
1243
+ }
1244
+
1245
+ /* ========================================
1246
+ POINT SYSTEM
1247
+ ======================================== */
1248
+ .magicfeedback-point-system-item {
1249
+ display: flex;
1250
+ align-items: center;
1251
+ justify-content: space-between;
1252
+ padding: var(--mf-space-md);
1253
+ margin: var(--mf-space-sm) 0;
1254
+ background-color: var(--mf-bg-primary);
1255
+ border: 1.5px solid var(--mf-border);
1256
+ border-radius: var(--mf-radius-md);
1257
+ min-height: 45px;
1258
+ }
1259
+
1260
+ .magicfeedback-point-system-item label {
1261
+ flex: 1;
1262
+ font-size: var(--mf-font-size-base);
1263
+ color: var(--mf-text-primary);
1264
+ margin: 0;
1265
+ }
1266
+
1267
+ .magicfeedback-point-system-input-container {
1268
+ display: flex;
1269
+ align-items: center;
1270
+ gap: var(--mf-space-sm);
1271
+ }
1272
+
1273
+ .magicfeedback-point-system-item input {
1274
+ width: 80px;
1275
+ min-width: 80px;
1276
+ padding: var(--mf-space-sm);
1277
+ text-align: center;
1278
+ font-size: var(--mf-font-size-base);
1279
+ border: 1.5px solid var(--mf-border);
1280
+ border-radius: var(--mf-radius-md);
1281
+ margin: 0;
1282
+ }
1283
+
1284
+ .magicfeedback-point-system-total {
1285
+ display: flex;
1286
+ justify-content: flex-end;
1287
+ margin-top: var(--mf-space-md);
1288
+ font-size: var(--mf-font-size-base);
1289
+ font-weight: 600;
1290
+ color: var(--mf-text-primary);
1291
+ }
1292
+
1293
+ /* ========================================
1294
+ CONSENT
1295
+ ======================================== */
1296
+ .magicfeedback-consent-container {
1297
+ display: flex;
1298
+ flex-direction: row;
1299
+ align-items: center;
1300
+ gap: var(--mf-space-sm);
1301
+ padding: var(--mf-space-md);
1302
+ background-color: var(--mf-bg-secondary);
1303
+ border-radius: var(--mf-radius-md);
1304
+ margin: var(--mf-space-md) 0;
1305
+ }
1306
+
1307
+ .magicfeedback-consent-container input[type="checkbox"] {
1308
+ margin-top: 2px;
1309
+ flex-shrink: 0;
1310
+ accent-color: var(--mf-primary);
1311
+ }
1312
+
1313
+ .magicfeedback-consent-container label {
1314
+ flex: 1;
1315
+ font-size: var(--mf-font-size-sm);
1316
+ text-align: left;
1317
+ color: var(--mf-text-secondary);
1318
+ line-height: var(--mf-line-height);
1319
+ cursor: pointer;
1320
+ margin-bottom: 0;
1321
+ }
1322
+
1323
+ /* ========================================
1324
+ ACTION BUTTONS
1325
+ ======================================== */
1326
+ .magicfeedback-action-container {
1327
+ display: flex;
1328
+ align-items: center;
1329
+ justify-content: space-between;
1330
+ gap: var(--mf-space-md);
1331
+ margin-top: var(--mf-space-xl);
1332
+ padding-top: var(--mf-space-lg);
1333
+ border-top: 1px solid var(--mf-border);
1334
+ }
1335
+
1336
+ .magicfeedback-submit {
1337
+ padding: 0.8rem 1.6rem;
1338
+ font-size: var(--mf-font-size-base);
1339
+ font-weight: 800;
1340
+ color: #FFFFFF;
1341
+ background-color: var(--mf-primary);
1342
+ border: 2px solid var(--mf-primary);
1343
+ border-radius: var(--mf-radius-full);
1344
+ cursor: pointer;
1345
+ transition: var(--mf-transition-fast);
1346
+ box-shadow: var(--mf-shadow-md);
1347
+ }
1348
+
1349
+ .magicfeedback-submit:hover {
1350
+ background-color: var(--mf-primary-hover);
1351
+ box-shadow: var(--mf-shadow-lg);
1352
+ transform: translateY(-2px);
1353
+ }
1354
+
1355
+ .magicfeedback-submit:active {
1356
+ transform: translateY(0);
1357
+ box-shadow: var(--mf-shadow-sm);
1358
+ }
1359
+
1360
+ .magicfeedback-submit:disabled {
1361
+ opacity: 0.5;
1362
+ cursor: not-allowed;
1363
+ transform: none;
1364
+ }
1365
+
1366
+ .magicfeedback-back {
1367
+ padding: 0.65rem 1rem;
1368
+ font-size: var(--mf-font-size-base);
1369
+ font-weight: 700;
1370
+ color: var(--mf-primary);
1371
+ background-color: var(--mf-bg-secondary);
1372
+ border: 2px solid var(--mf-border);
1373
+ border-radius: var(--mf-radius-full);
1374
+ cursor: pointer;
1375
+ transition: var(--mf-transition-fast);
1376
+ }
1377
+
1378
+ .magicfeedback-back:hover {
1379
+ border-color: var(--mf-primary);
1380
+ background-color: var(--mf-bg-hover);
1381
+ }
1382
+
1383
+ /* ========================================
1384
+ SKIP & COUNTER
1385
+ ======================================== */
1386
+ .magicfeedback-skip-container {
1387
+ display: flex;
1388
+ align-items: center;
1389
+ gap: var(--mf-space-xs);
1390
+ padding: 0;
1391
+ margin: 0;
1392
+ font-size: var(--mf-font-size-sm);
1393
+ color: var(--mf-text-muted);
1394
+ background: transparent;
1395
+ border: none;
1396
+ cursor: pointer;
1397
+ transition: var(--mf-transition-fast);
1398
+ }
1399
+
1400
+ .magicfeedback-skip-container:hover {
1401
+ color: var(--mf-primary);
1402
+ }
1403
+
1404
+ .magicfeedback-skip-container input[type="checkbox"] {
1405
+ margin: 0;
1406
+ cursor: pointer;
1407
+ accent-color: var(--mf-primary);
1408
+ }
1409
+
1410
+ .magicfeedback-counter {
1411
+ display: flex;
1412
+ justify-content: flex-end;
1413
+ margin-top: var(--mf-space-md);
1414
+ font-size: var(--mf-font-size-sm);
1415
+ color: var(--mf-text-muted);
1416
+ }
1417
+
1418
+ /* ========================================
1419
+ MODAL STYLES
1420
+ ======================================== */
1421
+ /* Modal backdrop */
1422
+ .magicfeedback-modal-backdrop {
1423
+ position: fixed;
1424
+ top: 0;
1425
+ left: 0;
1426
+ width: 100vw;
1427
+ height: 100vh;
1428
+ background: rgba(0,0,0,0.4);
1429
+ display: none; /* toggled to flex when open */
1430
+ align-items: center;
1431
+ justify-content: center;
1432
+ z-index: 9999;
1433
+ }
1434
+
1435
+ /* Modal container */
1436
+ .magicfeedback-modal {
1437
+ background: #fff;
1438
+ border-radius: 8px;
1439
+ box-shadow: 0 8px 24px rgba(0,0,0,0.2);
1440
+ max-width: 520px;
1441
+ width: 90%;
1442
+ max-height: 80vh;
1443
+ /* Flex column so the options list scrolls while the actions footer
1444
+ (counter + confirm button) stays pinned and always visible. */
1445
+ display: flex;
1446
+ flex-direction: column;
1447
+ overflow: hidden;
1448
+ padding: 16px;
1449
+ position: relative;
1450
+ /* Portalled to document.body (see renderPriorityList.ts) to escape the
1451
+ host page's overflow/z-index \u2014 so it never inherits
1452
+ .magicfeedback-container's neutral text color and instead inherits
1453
+ whatever color the host page's own <body> happens to set. Needs its
1454
+ own explicit baseline rather than relying on that inheritance. */
1455
+ color: var(--mf-text-primary);
1456
+ }
1457
+
1458
+ /* Modal actions */
1459
+ .magicfeedback-modal-actions {
1460
+ display: flex;
1461
+ justify-content: flex-end;
1462
+ gap: 8px;
1463
+ margin-top: 12px;
1464
+ flex-shrink: 0;
1465
+ }
1466
+
1467
+ .magicfeedback-modal-counter {
1468
+ margin-right: auto;
1469
+ display: flex;
1470
+ align-items: center;
1471
+ font-size: 14px;
1472
+ color: var(--mf-text-secondary);
1473
+ }
1474
+
1475
+ /* Modal list */
1476
+ .magicfeedback-modal-list {
1477
+ display: flex;
1478
+ flex-direction: column;
1479
+ gap: 8px;
1480
+ /* Scrollable area; footer stays fixed below it. */
1481
+ flex: 1 1 auto;
1482
+ overflow-y: auto;
1483
+ min-height: 0;
1484
+ }
1485
+
1486
+ .magicfeedback-modal-row {
1487
+ display: flex;
1488
+ align-items: center;
1489
+ gap: 10px;
1490
+ cursor: pointer;
1491
+ }
1492
+
1493
+ /* Priority list header */
1494
+ .magicfeedback-priority-list-header {
1495
+ display: flex;
1496
+ align-items: center;
1497
+ justify-content: space-between;
1498
+ gap: 12px;
1499
+ margin-bottom: 8px;
1500
+ }
1501
+
1502
+ .magicfeedback-priority-list-reorder {
1503
+ margin-top: 8px;
1504
+ }
1505
+
1506
+ .magicfeedback-priority-list-list {
1507
+ padding: 0;
1508
+ list-style: none;
1509
+ }
1510
+
1511
+ .magicfeedback-priority-list-item {
1512
+ display: flex;
1513
+ justify-content: space-between;
1514
+ align-items: center;
1515
+ margin: 5px 0;
1516
+ }
1517
+
1518
+ .magicfeedback-priority-list-item-label {
1519
+ font-size: 15px;
1520
+ }
1521
+
1522
+ .magicfeedback-priority-list-arrows {
1523
+ display: flex;
1524
+ align-items: center;
1525
+ gap: 6px;
1526
+ }
1527
+
1528
+ /* Buttons */
1529
+ .magicfeedback-button {
1530
+ appearance: none;
1531
+ border: 2px solid var(--mf-border);
1532
+ border-radius: var(--mf-radius-full);
1533
+ background: var(--mf-bg-secondary);
1534
+ color: var(--mf-text-primary);
1535
+ padding: 0.6rem 1rem;
1536
+ font-size: 14px;
1537
+ font-weight: 700;
1538
+ cursor: pointer;
1539
+ box-shadow: var(--mf-shadow-sm);
1540
+ }
1541
+
1542
+ .magicfeedback-button:hover {
1543
+ background: var(--mf-bg-hover);
1544
+ border-color: var(--mf-primary);
1545
+ }
1546
+
1547
+ .magicfeedback-button:active {
1548
+ transform: translateY(1px);
1549
+ }
1550
+
1551
+ .magicfeedback-button-primary {
1552
+ border-color: var(--mf-primary);
1553
+ background: var(--mf-primary);
1554
+ color: #fff;
1555
+ box-shadow: var(--mf-shadow-md);
1556
+ }
1557
+
1558
+ .magicfeedback-button-primary:hover {
1559
+ background: var(--mf-primary-hover);
1560
+ }
1561
+
1562
+ .magicfeedback-button-primary:active {
1563
+ background: var(--mf-primary-hover);
1564
+ }
1565
+
1566
+ /* Warning flash */
1567
+ .magicfeedback-warning {
1568
+ color: #C70039;
1569
+ }
1570
+
1571
+ /* Start message button */
1572
+ .magicfeedback-start-message-button {
1573
+ appearance: none;
1574
+ border: 2px solid var(--mf-primary);
1575
+ border-radius: var(--mf-radius-full);
1576
+ background: var(--mf-primary);
1577
+ color: #fff;
1578
+ padding: 0.8rem 1.4rem;
1579
+ font-size: 15px;
1580
+ font-weight: 800;
1581
+ cursor: pointer;
1582
+ box-shadow: var(--mf-shadow-md);
1583
+ }
1584
+
1585
+ .magicfeedback-start-message-button:hover {
1586
+ background: var(--mf-primary-hover);
1587
+ }
1588
+
1589
+ /* ========================================
1590
+ RESPONSIVE DESIGN
1591
+ ======================================== */
1592
+ @media (max-width: 768px) {
1593
+ :root {
1594
+ --mf-space-lg: 1.25rem;
1595
+ --mf-space-xl: 1.5rem;
1596
+ }
1597
+
1598
+ .magicfeedback-container {
1599
+ padding: 12px;
1600
+ border-radius: var(--mf-radius-md);
1601
+ }
1602
+
1603
+ .magicfeedback-form {
1604
+ padding: 14px;
1605
+ border-radius: var(--mf-radius-md);
1606
+ }
1607
+
1608
+ .magicfeedback-div {
1609
+ padding: 12px;
1610
+ gap: var(--mf-space-lg)
1611
+ }
1612
+
1613
+ .magicfeedback-label {
1614
+ font-size: var(--mf-font-size-base);
1615
+ }
1616
+
1617
+ .deepdots-popup input[type="date"],
1618
+ .deepdots-popup input[type="text"],
1619
+ .deepdots-popup input[type="number"],
1620
+ .deepdots-popup input[type="email"],
1621
+ .deepdots-popup input[type="password"],
1622
+ .deepdots-popup textarea,
1623
+ .deepdots-popup select {
1624
+ padding: 0.85rem 0.95rem;
1625
+ font-size: 1rem;
1626
+ min-height: 46px;
1627
+ }
1628
+
1629
+ /*
1630
+ .magicfeedback-radio-container,
1631
+ .magicfeedback-checkbox-container,
1632
+ .magicfeedback-boolean-container,
1633
+ .magicfeedback-consent-container {
1634
+ width: 100%;
1635
+ }
1636
+ */
1637
+
1638
+ .magicfeedback-radio-container,
1639
+ .magicfeedback-checkbox-container {
1640
+ padding: 10px 12px;
1641
+ border-radius: var(--mf-radius-md);
1642
+ border: 1px solid var(--mf-border);
1643
+ gap: 10px;
1644
+ }
1645
+
1646
+ .magicfeedback-rating-container,
1647
+ .magicfeedback-rating-number-container,
1648
+ .magicfeedback-rating-star-container {
1649
+ gap: 10px;
1650
+ }
1651
+
1652
+ .magicfeedback-boolean-container {
1653
+ flex-direction: column;
1654
+ gap: 10px;
1655
+ }
1656
+
1657
+ .magicfeedback-rating-number-container-row,
1658
+ .magicfeedback-rating-number-container-row-reverse {
1659
+ gap: 6px;
1660
+ }
1661
+
1662
+ .magicfeedback-rating-number-option-row .magicfeedback-rating-number-value,
1663
+ .magicfeedback-rating-number-option-row-reverse .magicfeedback-rating-number-value {
1664
+ min-height: 44px;
1665
+ padding: var(--mf-space-xs);
1666
+ font-size: 0.9rem;
1667
+ }
1668
+
1669
+ .magicfeedback-action-container {
1670
+ flex-direction: column-reverse;
1671
+ }
1672
+
1673
+ .magicfeedback-submit,
1674
+ .magicfeedback-back {
1675
+ width: 100%;
1676
+ text-align: center;
1677
+ min-height: 48px;
1678
+ }
1679
+ }
1680
+
1681
+ /* ========================================
1682
+ ACCESSIBILITY
1683
+ ======================================== */
1684
+ @media (prefers-reduced-motion: reduce) {
1685
+ *,
1686
+ *::before,
1687
+ *::after {
1688
+ animation-duration: 0.01ms !important;
1689
+ animation-iteration-count: 1 !important;
1690
+ transition-duration: 0.01ms !important;
1691
+ }
1692
+ }
1693
+
1694
+
1695
+ /* ========================================
1696
+ UTILITY CLASSES
1697
+ ======================================== */
1698
+ .magicfeedback-visually-hidden {
1699
+ position: absolute;
1700
+ width: 1px;
1701
+ height: 1px;
1702
+ padding: 0;
1703
+ margin: -1px;
1704
+ overflow: hidden;
1705
+ clip: rect(0, 0, 0, 0);
1706
+ white-space: nowrap;
1707
+ border-width: 0;
1708
+ }
1709
+
1710
+ .magicfeedback-modal-close {
1711
+ position: absolute;
1712
+ top: 8px;
1713
+ right: 8px;
1714
+ background: transparent;
1715
+ border: none;
1716
+ font-size: 20px;
1717
+ line-height: 1;
1718
+ cursor: pointer;
1719
+ color: #666;
1720
+ }
1721
+
1722
+ .magicfeedback-modal-close:hover,
1723
+ .magicfeedback-modal-close:focus {
1724
+ color: #000;
1725
+ outline: none;
1726
+ }
1727
+
1728
+ /* ========================================
1729
+ FILE / IMAGE UPLOAD
1730
+ ======================================== */
1731
+ .magicfeedback-upload {
1732
+ display: flex;
1733
+ flex-direction: column;
1734
+ gap: var(--mf-space-md);
1735
+ width: 100%;
1736
+ margin: 10px 0;
1737
+ }
1738
+
1739
+ /* The native input is an invisible, focusable overlay covering the dropzone. */
1740
+ .magicfeedback-upload-native {
1741
+ position: absolute;
1742
+ inset: 0;
1743
+ width: 100%;
1744
+ height: 100%;
1745
+ margin: 0;
1746
+ padding: 0;
1747
+ opacity: 0;
1748
+ cursor: pointer;
1749
+ z-index: 2;
1750
+ }
1751
+
1752
+ .magicfeedback-upload-dropzone {
1753
+ position: relative;
1754
+ display: flex;
1755
+ flex-direction: column;
1756
+ align-items: center;
1757
+ justify-content: center;
1758
+ gap: var(--mf-space-sm);
1759
+ box-sizing: border-box;
1760
+ width: 100%;
1761
+ min-height: 150px;
1762
+ padding: var(--mf-space-xl);
1763
+ text-align: center;
1764
+ border: 2px dashed var(--mf-border);
1765
+ border-radius: var(--mf-radius-md);
1766
+ background-color: var(--mf-surface-alt);
1767
+ cursor: pointer;
1768
+ transition: var(--mf-transition);
1769
+ }
1770
+
1771
+ .magicfeedback-upload-dropzone:hover {
1772
+ border-color: var(--mf-primary);
1773
+ background-color: var(--mf-bg-hover);
1774
+ }
1775
+
1776
+ .magicfeedback-upload-dropzone:focus-within {
1777
+ border-color: var(--mf-primary);
1778
+ box-shadow: var(--mf-shadow-focus);
1779
+ }
1780
+
1781
+ .magicfeedback-upload-dropzone.is-dragover {
1782
+ border-color: var(--mf-primary);
1783
+ border-style: solid;
1784
+ background-color: var(--mf-primary-light);
1785
+ box-shadow: var(--mf-shadow-focus);
1786
+ }
1787
+
1788
+ .magicfeedback-upload-icon {
1789
+ display: inline-flex;
1790
+ align-items: center;
1791
+ justify-content: center;
1792
+ width: 46px;
1793
+ height: 46px;
1794
+ color: var(--mf-primary);
1795
+ background-color: var(--mf-surface);
1796
+ border-radius: var(--mf-radius-full);
1797
+ box-shadow: var(--mf-shadow-sm);
1798
+ pointer-events: none;
1799
+ }
1800
+
1801
+ .magicfeedback-upload-icon svg {
1802
+ width: 24px;
1803
+ height: 24px;
1804
+ }
1805
+
1806
+ .magicfeedback-upload-cta {
1807
+ font-family: inherit;
1808
+ font-weight: var(--mf-font-weight-semibold);
1809
+ font-size: var(--mf-font-size-base);
1810
+ color: var(--mf-text-primary);
1811
+ pointer-events: none;
1812
+ }
1813
+
1814
+ .magicfeedback-upload-hint {
1815
+ font-family: inherit;
1816
+ font-size: var(--mf-font-size-sm);
1817
+ color: var(--mf-text-muted);
1818
+ pointer-events: none;
1819
+ }
1820
+
1821
+ .magicfeedback-upload-list {
1822
+ display: flex;
1823
+ flex-direction: column;
1824
+ gap: var(--mf-space-sm);
1825
+ width: 100%;
1826
+ margin: 0;
1827
+ padding: 0;
1828
+ list-style: none;
1829
+ }
1830
+
1831
+ .magicfeedback-upload-list:empty {
1832
+ display: none;
1833
+ }
1834
+
1835
+ .magicfeedback-upload-file-item {
1836
+ display: flex;
1837
+ align-items: center;
1838
+ gap: var(--mf-space-md);
1839
+ padding: var(--mf-space-sm) var(--mf-space-md);
1840
+ background-color: var(--mf-surface);
1841
+ border: 1px solid var(--mf-border);
1842
+ border-radius: var(--mf-radius-sm);
1843
+ box-shadow: var(--mf-shadow-sm);
1844
+ animation: mf-scale-in 0.2s ease-out;
1845
+ }
1846
+
1847
+ .magicfeedback-upload-thumb {
1848
+ flex: 0 0 auto;
1849
+ display: inline-flex;
1850
+ align-items: center;
1851
+ justify-content: center;
1852
+ width: 40px;
1853
+ height: 40px;
1854
+ overflow: hidden;
1855
+ color: var(--mf-text-secondary);
1856
+ background-color: var(--mf-surface-alt);
1857
+ border-radius: var(--mf-radius-sm);
1858
+ }
1859
+
1860
+ .magicfeedback-upload-thumb img {
1861
+ width: 100%;
1862
+ height: 100%;
1863
+ object-fit: cover;
1864
+ }
1865
+
1866
+ .magicfeedback-upload-thumb svg {
1867
+ width: 20px;
1868
+ height: 20px;
1869
+ }
1870
+
1871
+ .magicfeedback-upload-file-info {
1872
+ display: flex;
1873
+ flex-direction: column;
1874
+ flex: 1 1 auto;
1875
+ min-width: 0;
1876
+ text-align: start;
1877
+ }
1878
+
1879
+ .magicfeedback-upload-file-name {
1880
+ font-family: inherit;
1881
+ font-size: var(--mf-font-size-sm);
1882
+ font-weight: var(--mf-font-weight-semibold);
1883
+ color: var(--mf-text-primary);
1884
+ white-space: nowrap;
1885
+ overflow: hidden;
1886
+ text-overflow: ellipsis;
1887
+ }
1888
+
1889
+ .magicfeedback-upload-file-size {
1890
+ font-family: inherit;
1891
+ font-size: 0.75rem;
1892
+ color: var(--mf-text-muted);
1893
+ }
1894
+
1895
+ .magicfeedback-upload-remove {
1896
+ flex: 0 0 auto;
1897
+ display: inline-flex;
1898
+ align-items: center;
1899
+ justify-content: center;
1900
+ width: 30px;
1901
+ height: 30px;
1902
+ padding: 0;
1903
+ color: var(--mf-text-muted);
1904
+ background-color: transparent;
1905
+ border: none;
1906
+ border-radius: var(--mf-radius-full);
1907
+ cursor: pointer;
1908
+ transition: var(--mf-transition-fast);
1909
+ }
1910
+
1911
+ .magicfeedback-upload-remove:hover,
1912
+ .magicfeedback-upload-remove:focus-visible {
1913
+ color: var(--mf-error);
1914
+ background-color: var(--mf-primary-light);
1915
+ outline: none;
1916
+ }
1917
+
1918
+ .magicfeedback-upload-remove svg {
1919
+ width: 16px;
1920
+ height: 16px;
1921
+ }
1922
+
1923
+ .magicfeedback-upload-error {
1924
+ display: none;
1925
+ font-family: inherit;
1926
+ font-size: var(--mf-font-size-sm);
1927
+ color: var(--mf-error);
1928
+ }
1929
+
1930
+ .magicfeedback-upload-error.is-visible {
1931
+ display: block;
1932
+ }
1933
+
1934
+ /* ========================================
1935
+ LOCAL \u2014 reglas del popup, no vienen del paquete
1936
+ ======================================== */
1937
+
1938
+ /* Los controles de formulario no heredan font-family: cuando el popup trae fuente propia
1939
+ (clase deepdots-has-font), se les fuerza la del contenedor. */
1940
+ .deepdots-popup.deepdots-has-font button,
1941
+ .deepdots-popup.deepdots-has-font input,
1942
+ .deepdots-popup.deepdots-has-font textarea,
1943
+ .deepdots-popup.deepdots-has-font select {
1944
+ font-family: var(--deepdots-font, inherit);
1945
+ }
1946
+
1947
+ /* WebKit s\xED aplica el padding al radio nativo: con padding el control se dibuja enorme (se vio
1948
+ en iOS, WebView de RN y Safari, no en Chrome). El paquete ya no lo pone, pero la regla es
1949
+ barata y evita que vuelva. */
1950
+ .deepdots-popup input[type="radio"] {
1951
+ padding: 0;
1952
+ }
1953
+ `;
186
1954
  }
187
1955
  });
188
1956
 
@@ -207,6 +1975,47 @@ var init_logger = __esm({
207
1975
  }
208
1976
  });
209
1977
 
1978
+ // src/ui/logo.ts
1979
+ function insertPopupLogo(parent, anchor, style, id) {
1980
+ if (!style?.logo) return null;
1981
+ if (parent.ownerDocument.getElementById(id)) return null;
1982
+ const img = parent.ownerDocument.createElement("img");
1983
+ img.id = id;
1984
+ img.src = style.logo;
1985
+ img.alt = "Logo";
1986
+ img.style.cssText = BASE_CSS;
1987
+ if (style.logoSize && MAX_HEIGHT[style.logoSize]) {
1988
+ img.style.maxHeight = MAX_HEIGHT[style.logoSize];
1989
+ }
1990
+ switch (style.logoPosition) {
1991
+ case "left":
1992
+ img.style.margin = "12px 16px 0 0";
1993
+ img.style.marginLeft = "0";
1994
+ break;
1995
+ case "right":
1996
+ img.style.margin = "12px 0 0 16px";
1997
+ img.style.marginLeft = "auto";
1998
+ break;
1999
+ case "center":
2000
+ img.style.margin = "12px auto 0 auto";
2001
+ break;
2002
+ }
2003
+ parent.insertBefore(img, anchor);
2004
+ return img;
2005
+ }
2006
+ var BASE_CSS, MAX_HEIGHT;
2007
+ var init_logo = __esm({
2008
+ "src/ui/logo.ts"() {
2009
+ "use strict";
2010
+ BASE_CSS = "max-height:40px; max-width:100%; object-fit:contain; display:block; margin:12px 0 0 0;";
2011
+ MAX_HEIGHT = {
2012
+ small: "30px",
2013
+ medium: "50px",
2014
+ large: "70px"
2015
+ };
2016
+ }
2017
+ });
2018
+
210
2019
  // src/ui/renderPopup.ts
211
2020
  var renderPopup_exports = {};
212
2021
  __export(renderPopup_exports, {
@@ -225,6 +2034,10 @@ function ensureSpinnerStyles(_popup) {
225
2034
  const style = document.createElement("style");
226
2035
  style.id = "deepdots-spinner-styles";
227
2036
  style.textContent = `
2037
+ /* El enunciado trae margin-top:20px del CSS de surveys, que sumaba al hueco de la barra
2038
+ de progreso y descompensaba la simetr\xEDa. Solo se anula en el primero: entre preguntas
2039
+ de la misma p\xE1gina sigue separando. */
2040
+ .deepdots-popup .magicfeedback-questions .magicfeedback-div:first-child .magicfeedback-label { margin-top: 0; }
228
2041
  @keyframes ddspin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
229
2042
  .mf-spinner { display:flex; justify-content:center; align-items:center; padding:8px 0; }
230
2043
  .mf-spinner-circle { width:28px; height:28px; border:3px solid #e0e6ed; border-top-color:#1E293B; border-radius:50%; animation: ddspin 0.9s linear infinite; }
@@ -251,7 +2064,9 @@ function ensureResponsiveStyles(_popup) {
251
2064
  .deepdots-popup button { font-size: 16px !important; }
252
2065
  .deepdots-popup-header button { width:48px; height:48px; }
253
2066
  .deepdots-popup-header button svg { width:26px; height:26px; }
254
- .deepdots-popup-footer { flex-direction: column-reverse !important; gap: 12px !important; }
2067
+ /* Apilados en el orden del DOM: la acci\xF3n principal (Send/Start/Complete) arriba y
2068
+ Back debajo. */
2069
+ .deepdots-popup-footer { flex-direction: column !important; gap: 4px !important; }
255
2070
  .deepdots-popup-footer button { width: 100%; }
256
2071
  }
257
2072
  @media (max-width: 400px) {
@@ -269,6 +2084,18 @@ function ensureResponsiveStyles(_popup) {
269
2084
  `;
270
2085
  document.head.appendChild(style);
271
2086
  }
2087
+ function ensureCustomCss(css) {
2088
+ const STYLE_ID = "deepdots-custom-css";
2089
+ const existing = document.getElementById(STYLE_ID);
2090
+ if (!css) {
2091
+ existing?.remove();
2092
+ return;
2093
+ }
2094
+ const el = existing ?? document.createElement("style");
2095
+ el.id = STYLE_ID;
2096
+ if (el.textContent !== css) el.textContent = css;
2097
+ document.head.appendChild(el);
2098
+ }
272
2099
  function ensureFontFace(family, url) {
273
2100
  const css = buildFontFaceCss(family, url);
274
2101
  if (!css) return;
@@ -281,9 +2108,11 @@ function ensureFontFace(family, url) {
281
2108
  }
282
2109
  if (el.textContent !== css) el.textContent = css;
283
2110
  }
284
- async function renderPopup(container, surveyId, productId, actions, emit, onClose, env = "production", userId, style, sessionId, miniService, analyticsFeedbackSessionId) {
2111
+ async function renderPopup(container, surveyId, productId, actions, emit, onClose, env = "production", userId, style, sessionId, miniService, analyticsFeedbackSessionId, options) {
285
2112
  let surveyCompletedEmitted = false;
286
2113
  let stylesInjected = false;
2114
+ let pageDepth = 0;
2115
+ let onStartPage = false;
287
2116
  const isDark = style?.theme === "dark";
288
2117
  const theme = {
289
2118
  popupBg: isDark ? "#1e1e1e" : "#fff",
@@ -293,8 +2122,9 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
293
2122
  // oscuros con texto blanco sobre el fondo claro del popup.
294
2123
  colorScheme: isDark ? "dark" : "light",
295
2124
  textPrimary: isDark ? "#f0f0f0" : "#111",
296
- closeBtnHoverBg: isDark ? "rgba(255,255,255,0.10)" : "rgba(0,0,0,0.06)",
297
- closeBtnHoverColor: isDark ? "#fff" : "#000000"
2125
+ closeBtnHoverColor: isDark ? "#fff" : "#000000",
2126
+ textMuted: isDark ? "#9ca3af" : "#6b7280",
2127
+ progressTrack: isDark ? "#3f3f46" : "#e5e7eb"
298
2128
  };
299
2129
  const positionMap = {
300
2130
  "center": { justifyContent: "center", alignItems: "center", background: "rgba(0,0,0,0.5)" },
@@ -307,6 +2137,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
307
2137
  };
308
2138
  const pos = positionMap[style?.position ?? "center"] ?? positionMap["center"];
309
2139
  const popup = document.createElement("div");
2140
+ popup.id = "dd-popup";
310
2141
  popup.className = "deepdots-popup";
311
2142
  popup.style.cssText = `
312
2143
  position: relative;
@@ -320,6 +2151,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
320
2151
  box-shadow: 0 4px 6px rgba(0,0,0,0.1);
321
2152
  max-width: 600px;
322
2153
  width: 90%;
2154
+ max-height: 90vh;
323
2155
  min-height: 200px;
324
2156
  `;
325
2157
  const font = style?.font;
@@ -332,13 +2164,26 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
332
2164
  }
333
2165
  const header = document.createElement("div");
334
2166
  header.className = "deepdots-popup-header";
335
- header.style.cssText = "display:flex; justify-content:flex-end; align-items:center; width:100%;";
2167
+ header.style.cssText = "display:flex; justify-content:space-between; align-items:center; gap:12px; width:100%; flex:0 0 auto;";
2168
+ const titleEl = document.createElement("h2");
2169
+ titleEl.id = "dd-title";
2170
+ titleEl.className = "deepdots-popup-title";
2171
+ titleEl.style.cssText = `margin:0; font-size:17px; font-weight:600; line-height:1.3; color:${theme.textPrimary}; text-transform:none; text-align:left; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;`;
2172
+ titleEl.hidden = true;
2173
+ const setTitle = (value) => {
2174
+ if (!value) return;
2175
+ titleEl.textContent = value;
2176
+ titleEl.hidden = false;
2177
+ };
2178
+ setTitle(options?.title);
2179
+ header.appendChild(titleEl);
336
2180
  const closeBtn = document.createElement("button");
2181
+ closeBtn.id = "dd-close";
337
2182
  closeBtn.type = "button";
338
2183
  closeBtn.setAttribute("aria-label", "Close popup");
339
2184
  closeBtn.innerHTML = `
340
- <svg width="28" height="28" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
341
- <path d="M6 6L18 18M6 18L18 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
2185
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2186
+ <path d="M5 5L19 19M5 19L19 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="butt"/>
342
2187
  </svg>
343
2188
  `;
344
2189
  closeBtn.style.cssText = `
@@ -353,42 +2198,101 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
353
2198
  cursor:pointer;
354
2199
  color:${theme.textPrimary};
355
2200
  padding:4px;
356
- transition: color .15s ease, transform .15s ease, background .15s ease;
2201
+ transition: color .15s ease, transform .15s ease;
357
2202
  box-shadow: none !important;
358
2203
  `;
359
2204
  closeBtn.onmouseenter = () => {
360
2205
  closeBtn.style.color = theme.closeBtnHoverColor;
361
- closeBtn.style.background = theme.closeBtnHoverBg;
362
2206
  closeBtn.style.transform = "scale(1.06)";
363
2207
  };
364
2208
  closeBtn.onmouseleave = () => {
365
2209
  closeBtn.style.color = theme.textPrimary;
366
- closeBtn.style.background = "transparent";
367
2210
  closeBtn.style.transform = "scale(1)";
368
2211
  };
369
2212
  closeBtn.onclick = () => {
370
2213
  emit("popup_clicked", surveyId, { action: "close_icon" });
371
2214
  onClose();
372
2215
  };
2216
+ closeBtn.style.flex = "0 0 auto";
2217
+ closeBtn.style.marginLeft = "auto";
373
2218
  header.appendChild(closeBtn);
2219
+ let progressEnabled = options?.showProgressBar === true;
2220
+ let progressShowUnit = true;
2221
+ let progressUnit = "fraction";
2222
+ const progressEl = document.createElement("div");
2223
+ progressEl.id = "dd-progress";
2224
+ progressEl.className = "deepdots-progress";
2225
+ progressEl.style.cssText = "display:none; flex-direction:column; gap:8px; width:100%; flex:0 0 auto; padding:16px 0; box-sizing:border-box;";
2226
+ const progressHead = document.createElement("div");
2227
+ progressHead.className = "deepdots-progress-head";
2228
+ progressHead.style.cssText = "display:flex; flex-direction:row; justify-content:space-between; align-items:center; width:100%; gap:8px;";
2229
+ const progressLabel = document.createElement("span");
2230
+ progressLabel.id = "dd-progress-label";
2231
+ progressLabel.style.cssText = "font-size:13px; line-height:1.2;";
2232
+ const progressCurrent = document.createElement("span");
2233
+ progressCurrent.id = "dd-progress-current";
2234
+ progressCurrent.style.cssText = `font-weight:700; color:${theme.textPrimary};`;
2235
+ const progressTotal = document.createElement("span");
2236
+ progressTotal.id = "dd-progress-total";
2237
+ progressTotal.style.cssText = `font-weight:400; color:${theme.textMuted};`;
2238
+ progressLabel.appendChild(progressCurrent);
2239
+ progressLabel.appendChild(progressTotal);
2240
+ const progressFollowUp = document.createElement("span");
2241
+ progressFollowUp.id = "dd-progress-followup";
2242
+ progressFollowUp.textContent = "Follow-up";
2243
+ progressFollowUp.style.cssText = "display:none; font-size:12px; font-weight:600; color:#fff; background:rgba(59,130,246,0.44); border-radius:999px; padding:2px 10px;";
2244
+ progressHead.appendChild(progressLabel);
2245
+ progressHead.appendChild(progressFollowUp);
2246
+ const progressTrack = document.createElement("div");
2247
+ progressTrack.className = "deepdots-progress-track";
2248
+ progressTrack.style.cssText = `width:100%; height:4px; border-radius:999px; background:${theme.progressTrack}; overflow:hidden;`;
2249
+ const progressBar = document.createElement("div");
2250
+ progressBar.id = "dd-progress-bar";
2251
+ progressBar.style.cssText = "height:100%; width:0%; background:#22C55E; border-radius:999px; transition:width 450ms ease;";
2252
+ progressTrack.appendChild(progressBar);
2253
+ progressEl.appendChild(progressHead);
2254
+ progressEl.appendChild(progressTrack);
2255
+ function updateProgress(p) {
2256
+ const total = typeof p.total === "number" ? p.total : 0;
2257
+ const progress = typeof p.progress === "number" ? p.progress : 0;
2258
+ if (!progressEnabled || onStartPage || p.completed || total <= 1) {
2259
+ progressEl.style.display = "none";
2260
+ containerContent.style.paddingTop = "16px";
2261
+ return;
2262
+ }
2263
+ progressEl.style.display = "flex";
2264
+ containerContent.style.paddingTop = "0";
2265
+ const current = Math.min(total, Math.max(1, progress + 1));
2266
+ const pct = Math.min(100, Math.max(0, current / total * 100));
2267
+ progressBar.style.width = `${pct}%`;
2268
+ const label = Math.min(total, Math.max(1, Math.floor(progress) + 1));
2269
+ progressLabel.style.display = progressShowUnit ? "block" : "none";
2270
+ if (progressUnit === "percentage") {
2271
+ progressCurrent.textContent = `${Math.round(pct)}%`;
2272
+ progressTotal.textContent = "";
2273
+ } else {
2274
+ progressCurrent.textContent = `Question ${label}`;
2275
+ progressTotal.textContent = ` of ${total}`;
2276
+ }
2277
+ progressFollowUp.style.display = p.followup ? "inline-block" : "none";
2278
+ }
374
2279
  ensureMagicFeedbackStyles(popup);
375
2280
  ensureSpinnerStyles(popup);
376
2281
  ensureResponsiveStyles(popup);
2282
+ ensureCustomCss(options?.surveyCss);
377
2283
  const containerContent = document.createElement("div");
378
- containerContent.className = "deepdots-popup-container-conetent";
379
- containerContent.style.cssText = `
380
- display:flex;
381
- flex-direction:column;
382
- padding: 0 20px 12px 20px;
383
- max-height: 80vh; /* l\xEDmite general del popup */
384
- overflow: hidden; /* quita scroll del contenedor principal */
385
- `;
2284
+ containerContent.id = "dd-content";
2285
+ containerContent.className = "deepdots-popup-container-content";
2286
+ containerContent.style.cssText = "display:flex; flex-direction:column; flex:1 1 auto; min-height:0; padding:16px 0 0 0; overflow:hidden;";
386
2287
  const main = document.createElement("div");
2288
+ main.id = "dd-main";
387
2289
  main.className = "deepdots-popup-main";
388
- main.style.cssText = "display:flex; flex-direction:column; width:100%; max-height:80vh; overflow-y:auto;";
2290
+ main.style.cssText = "display:flex; flex-direction:column; width:100%; flex:1 1 auto; min-height:0; overflow-y:auto;";
389
2291
  const formWrapper = document.createElement("div");
2292
+ formWrapper.id = "dd-form-wrapper";
390
2293
  formWrapper.style.cssText = "width:100%; flex: 1 1 auto;";
391
2294
  const errorHint = document.createElement("div");
2295
+ errorHint.id = "dd-error";
392
2296
  errorHint.className = "deepdots-error-hint";
393
2297
  errorHint.style.cssText = `
394
2298
  display: none;
@@ -417,20 +2321,24 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
417
2321
  main.appendChild(formWrapper);
418
2322
  main.appendChild(errorHint);
419
2323
  const footer = document.createElement("div");
2324
+ footer.id = "dd-footer";
420
2325
  footer.className = "deepdots-popup-footer";
421
2326
  footer.setAttribute("data-actions-wrapper", "true");
422
- footer.style.cssText = "display:flex; flex-direction: row-reverse ;justify-content:space-between; align-items:center; gap:8px; margin-top:auto; width:100%; padding-top:16px;";
2327
+ footer.style.cssText = "display:flex; flex-direction: row-reverse ;justify-content:space-between; align-items:center; gap:4px; margin-top:auto; width:100%; padding-top:12px;";
423
2328
  const backButton = document.createElement("button");
2329
+ backButton.id = "dd-back";
2330
+ backButton.className = "dd-nav-btn";
424
2331
  backButton.textContent = actions?.back ? actions.back.label : "Back";
425
2332
  backButton.style.cssText = `
426
2333
  background: transparent;
427
- color: #333;
428
- border: 1px solid #999;
2334
+ color: ${theme.textMuted};
2335
+ border: none;
2336
+ min-height: 44px;
429
2337
  padding: 12px 24px;
430
- border-radius: 4px;
2338
+ border-radius: 6px;
431
2339
  cursor: pointer;
432
- font-size: 14px;
433
- box-shadow: 0 2px 4px rgba(0,0,0,0.1);
2340
+ font-size: 15px;
2341
+ font-weight: 600;
434
2342
  transition: filter .15s ease;
435
2343
  display: inline-flex;
436
2344
  align-items: center;
@@ -448,15 +2356,19 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
448
2356
  formInstance?.back?.();
449
2357
  };
450
2358
  const startButton = document.createElement("button");
2359
+ startButton.id = "dd-start";
2360
+ startButton.className = "dd-nav-btn";
451
2361
  startButton.textContent = actions?.start ? actions.start.label : "Start survey";
452
2362
  startButton.style.cssText = `
453
2363
  background: #1E293B;
454
2364
  color: #fff;
455
2365
  border: none;
2366
+ min-height: 44px;
456
2367
  padding: 12px 24px;
457
- border-radius: 4px;
2368
+ border-radius: 6px;
458
2369
  cursor: pointer;
459
- font-size: 14px;
2370
+ font-size: 15px;
2371
+ font-weight: 600;
460
2372
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
461
2373
  transition: filter .15s ease;
462
2374
  display: inline-flex;
@@ -467,17 +2379,23 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
467
2379
  startButton.onclick = () => {
468
2380
  emit("popup_clicked", surveyId, { action: "start_survey" });
469
2381
  formInstance?.startForm?.();
2382
+ onStartPage = false;
2383
+ updateProgress({ progress: formInstance?.progress, total: formInstance?.total });
470
2384
  };
471
2385
  const closeButton = document.createElement("button");
2386
+ closeButton.id = "dd-complete";
2387
+ closeButton.className = "dd-nav-btn";
472
2388
  closeButton.textContent = actions?.complete ? actions.complete.label : "Complete survey";
473
2389
  closeButton.style.cssText = `
474
2390
  background: #1E293B;
475
2391
  color: #fff;
476
2392
  border: none;
2393
+ min-height: 44px;
477
2394
  padding: 12px 24px;
478
- border-radius: 4px;
2395
+ border-radius: 6px;
479
2396
  cursor: pointer;
480
- font-size: 14px;
2397
+ font-size: 15px;
2398
+ font-weight: 600;
481
2399
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
482
2400
  transition: filter .15s ease;
483
2401
  display: inline-flex;
@@ -496,15 +2414,19 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
496
2414
  onClose();
497
2415
  };
498
2416
  const submitButton = document.createElement("button");
2417
+ submitButton.id = "dd-submit";
2418
+ submitButton.className = "dd-nav-btn";
499
2419
  submitButton.textContent = actions?.accept ? actions.accept.label : "Send";
500
2420
  submitButton.style.cssText = `
501
2421
  background: #1E293B;
502
2422
  color: #fff;
503
2423
  border: none;
2424
+ min-height: 44px;
504
2425
  padding: 12px 24px;
505
- border-radius: 4px;
2426
+ border-radius: 6px;
506
2427
  cursor: pointer;
507
- font-size: 14px;
2428
+ font-size: 15px;
2429
+ font-weight: 600;
508
2430
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
509
2431
  transition: filter .15s ease;
510
2432
  display: inline-flex;
@@ -526,8 +2448,9 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
526
2448
  footer.appendChild(backButton);
527
2449
  footer.appendChild(closeButton);
528
2450
  footer.appendChild(startButton);
529
- main.appendChild(footer);
530
2451
  containerContent.appendChild(main);
2452
+ footer.style.flex = "0 0 auto";
2453
+ containerContent.appendChild(footer);
531
2454
  function updateButtons(state) {
532
2455
  backButton.style.display = "none";
533
2456
  startButton.style.display = "none";
@@ -564,7 +2487,27 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
564
2487
  break;
565
2488
  }
566
2489
  }
2490
+ function updateNavButtons() {
2491
+ updateButtons(pageDepth > 0 ? "in_progress_next" : "in_progress_first");
2492
+ }
2493
+ let successMessageHtml = "";
2494
+ function showSuccessScreen() {
2495
+ progressEl.style.display = "none";
2496
+ formWrapper.style.display = "none";
2497
+ let done = main.querySelector(".deepdots-success");
2498
+ if (!done) {
2499
+ done = document.createElement("div");
2500
+ done.className = "deepdots-success";
2501
+ done.style.cssText = `width:100%; text-align:center; padding:24px 0; color:${theme.textPrimary};`;
2502
+ main.insertBefore(done, errorHint);
2503
+ }
2504
+ done.innerHTML = successMessageHtml || "<p>Thank you for your feedback!</p>";
2505
+ done.querySelectorAll("img").forEach((img) => {
2506
+ img.style.cssText = "max-width:100%; height:auto; margin:0 auto 16px auto; display:block;";
2507
+ });
2508
+ }
567
2509
  popup.appendChild(header);
2510
+ popup.appendChild(progressEl);
568
2511
  popup.appendChild(containerContent);
569
2512
  container.innerHTML = "";
570
2513
  container.appendChild(popup);
@@ -610,7 +2553,11 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
610
2553
  formInstance = import_native.default.form(surveyId, productId, profile, metadata);
611
2554
  const generateOptions = {
612
2555
  addButton: false,
613
- getMetaData: true
2556
+ getMetaData: true,
2557
+ // La pantalla final la pinta el popup: `renderSuccess` de @magicfeedback/native usa
2558
+ // textContent, así que el mensaje de la plataforma (HTML con imagen) no se vería, y
2559
+ // su fallback es un literal genérico que ignora `style.successMessage`.
2560
+ addSuccessScreen: false
614
2561
  };
615
2562
  generateOptions.onLoadedEvent = ({ formData }) => {
616
2563
  try {
@@ -619,6 +2566,14 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
619
2566
  const s = formData?.style;
620
2567
  if (s && !stylesInjected) {
621
2568
  stylesInjected = true;
2569
+ if (s.successMessage) successMessageHtml = s.successMessage;
2570
+ if (options?.showProgressBar === void 0) progressEnabled = s.showProgressBar === true;
2571
+ if (s.showProgressUnit !== void 0) progressShowUnit = s.showProgressUnit !== false;
2572
+ if (s.progressUnit) progressUnit = s.progressUnit;
2573
+ if (s.loadingBarColor) {
2574
+ progressBar.style.background = s.loadingBarColor;
2575
+ progressFollowUp.style.background = s.loadingBarColor;
2576
+ }
622
2577
  if (s.boxBackgroundColor) {
623
2578
  popup.style.background = s.boxBackgroundColor;
624
2579
  }
@@ -637,53 +2592,14 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
637
2592
  closeButton.style.color = "#fff";
638
2593
  }
639
2594
  if (s.buttonSecondaryColor) {
640
- backButton.style.background = "#fff";
2595
+ backButton.style.background = "transparent";
641
2596
  backButton.style.color = s.buttonSecondaryColor;
642
- backButton.style.border = `1px solid ${s.buttonSecondaryColor}`;
643
- }
644
- if (s.logo) {
645
- if (!document.getElementById("deepdots-popup-logo")) {
646
- const logoImg = document.createElement("img");
647
- logoImg.id = "deepdots-popup-logo";
648
- logoImg.src = s.logo;
649
- logoImg.alt = "Logo";
650
- logoImg.style.cssText = "max-height:40px; max-width:100%; object-fit:contain;";
651
- if (s.logoSize) {
652
- switch (s.logoSize) {
653
- case "small":
654
- logoImg.style.maxHeight = "30px";
655
- break;
656
- case "medium":
657
- logoImg.style.maxHeight = "50px";
658
- break;
659
- case "large":
660
- logoImg.style.maxHeight = "70px";
661
- break;
662
- }
663
- }
664
- if (s.logoPosition) {
665
- switch (s.logoPosition) {
666
- case "left":
667
- logoImg.style.margin = "0 16px 42px 0";
668
- logoImg.style.display = "block";
669
- logoImg.style.marginLeft = "0";
670
- break;
671
- case "right":
672
- logoImg.style.margin = "0 0 42px 16px";
673
- logoImg.style.display = "block";
674
- logoImg.style.marginLeft = "auto";
675
- break;
676
- case "center":
677
- logoImg.style.margin = "0 auto 42px auto";
678
- logoImg.style.display = "block";
679
- break;
680
- }
681
- }
682
- containerContent.insertBefore(logoImg, main);
683
- }
2597
+ backButton.style.border = "none";
684
2598
  }
2599
+ insertPopupLogo(popup, progressEl, s, "deepdots-popup-logo");
685
2600
  if (s.startMessage && s.startMessage !== "") {
686
2601
  sdkLog(s.startMessage);
2602
+ onStartPage = true;
687
2603
  updateButtons("start");
688
2604
  } else {
689
2605
  updateButtons("in_progress_first");
@@ -691,6 +2607,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
691
2607
  } else {
692
2608
  updateButtons("in_progress_first");
693
2609
  }
2610
+ updateProgress({ progress: formInstance.progress, total: formInstance.total });
694
2611
  emit("popup_clicked", surveyId, { action: "loaded" });
695
2612
  setLoading(false);
696
2613
  };
@@ -698,7 +2615,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
698
2615
  setLoading(true);
699
2616
  emit("popup_clicked", surveyId, { action: "before_submit" });
700
2617
  };
701
- generateOptions.afterSubmitEvent = ({ error, completed, total, progress }) => {
2618
+ generateOptions.afterSubmitEvent = ({ error, completed, total, progress, followup }) => {
702
2619
  const errText = error ? typeof error === "string" ? error : error.message ?? String(error) : "";
703
2620
  if (errText) {
704
2621
  setLoading(false);
@@ -706,7 +2623,7 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
706
2623
  errorHint.textContent = "Please answer the required question to continue.";
707
2624
  errorHint.style.display = "block";
708
2625
  emit("popup_clicked", surveyId, { action: "validation_error_required" });
709
- updateButtons("in_progress_next");
2626
+ updateNavButtons();
710
2627
  return;
711
2628
  }
712
2629
  errorHint.textContent = "An error occurred while submitting. Please try again or close the popup.";
@@ -719,23 +2636,21 @@ async function renderPopup(container, surveyId, productId, actions, emit, onClos
719
2636
  if (completed) {
720
2637
  emit("survey_completed", surveyId, { action: "completed" });
721
2638
  surveyCompletedEmitted = true;
2639
+ showSuccessScreen();
722
2640
  updateButtons("completed");
2641
+ updateProgress({ progress, total, completed: true });
723
2642
  return;
724
2643
  }
725
2644
  emit("popup_clicked", surveyId, { action: "partial" });
726
- if (total > 1 && progress > 0 && progress < total) {
727
- updateButtons("in_progress_next");
728
- } else {
729
- updateButtons("in_progress_first");
730
- }
2645
+ pageDepth++;
2646
+ updateNavButtons();
2647
+ updateProgress({ progress, total, followup });
731
2648
  };
732
- generateOptions.onBackEvent = ({ progress }) => {
2649
+ generateOptions.onBackEvent = ({ progress, error, followup }) => {
733
2650
  emit("popup_clicked", surveyId, { action: "back" });
734
- if (progress === 0) {
735
- updateButtons("in_progress_first");
736
- } else {
737
- updateButtons("in_progress_next");
738
- }
2651
+ if (!error) pageDepth = Math.max(0, pageDepth - 1);
2652
+ updateNavButtons();
2653
+ updateProgress({ progress, total: formInstance.total, followup });
739
2654
  };
740
2655
  formInstance.generate(formDivId, generateOptions).catch((err) => {
741
2656
  sdkError("[MagicFeedback] Error generating form:", err);
@@ -752,6 +2667,7 @@ var init_renderPopup = __esm({
752
2667
  "use strict";
753
2668
  init_tracking_manager();
754
2669
  init_font();
2670
+ init_logo();
755
2671
  init_logger();
756
2672
  import_native = __toESM(require("@magicfeedback/native"));
757
2673
  init_style();
@@ -974,14 +2890,17 @@ var POSITION_MAP = {
974
2890
  "top-right": { justifyContent: "flex-end", alignItems: "flex-start", padding: "16px", background: "transparent" },
975
2891
  "top-left": { justifyContent: "flex-start", alignItems: "flex-start", padding: "16px", background: "transparent" }
976
2892
  };
2893
+ function jsonForScript(value) {
2894
+ return JSON.stringify(value ?? null).replace(/</g, "\\u003C").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
2895
+ }
977
2896
  function buildSurveyHtml(opts) {
978
2897
  const env = opts.env === "development" ? "dev" : "prod";
979
- const version = opts.version ?? "2.2.4";
2898
+ const version = opts.version ?? "2.2.8";
980
2899
  const cdn = `https://cdn.jsdelivr.net/npm/@magicfeedback/native@${version}/dist/magicfeedback-sdk.browser.js`;
981
- const sid = JSON.stringify(opts.surveyId);
982
- const pid = JSON.stringify(opts.productId);
983
- const profileJson = JSON.stringify(opts.profile ?? []);
984
- const metaJson = JSON.stringify(opts.metadata ?? []);
2900
+ const sid = jsonForScript(opts.surveyId);
2901
+ const pid = jsonForScript(opts.productId);
2902
+ const profileJson = jsonForScript(opts.profile ?? []);
2903
+ const metaJson = jsonForScript(opts.metadata ?? []);
985
2904
  const fontFaceCss = opts.font ? buildFontFaceCss(opts.font.family, opts.font.url) : "";
986
2905
  const fontFamilyValue = opts.font ? buildFontFamilyValue(opts.font.family) : "-apple-system,system-ui,sans-serif";
987
2906
  const popupClass = opts.font?.family ? "deepdots-popup deepdots-has-font" : "deepdots-popup";
@@ -989,6 +2908,8 @@ function buildSurveyHtml(opts) {
989
2908
  const popupBg = isDark ? "#1e1e1e" : "#fff";
990
2909
  const colorScheme = isDark ? "dark" : "light";
991
2910
  const textPrimary = isDark ? "#f0f0f0" : "#111";
2911
+ const textMuted = isDark ? "#9ca3af" : "#6b7280";
2912
+ const trackBg = isDark ? "#3f3f46" : "#e5e7eb";
992
2913
  const pos = POSITION_MAP[opts.position ?? "center"] ?? POSITION_MAP.center;
993
2914
  const chrome = opts.chrome !== false;
994
2915
  const bodyBg = chrome ? pos.background : "transparent";
@@ -1000,10 +2921,16 @@ function buildSurveyHtml(opts) {
1000
2921
  const cardMaxWidth = chrome ? "600px" : "none";
1001
2922
  const cardWidth = chrome ? "90%" : "100%";
1002
2923
  const cardMinHeight = chrome ? "200px" : "0";
1003
- const backLabel = JSON.stringify(opts.actions?.back?.label ?? "Back");
1004
- const startLabel = JSON.stringify(opts.actions?.start?.label ?? "Start survey");
1005
- const completeLabel = JSON.stringify(opts.actions?.complete?.label ?? "Complete survey");
1006
- const submitLabel = JSON.stringify(opts.actions?.accept?.label ?? "Send");
2924
+ const cardHeight = chrome ? "auto" : "100%";
2925
+ const cardMaxHeight = chrome ? "90vh" : "100%";
2926
+ const mobileCard = chrome ? `.deepdots-popup{width:calc(100% - 24px);max-width:calc(100% - 24px);border-radius:12px;padding:calc(16px + env(safe-area-inset-top)) 16px calc(16px + env(safe-area-inset-bottom)) 16px}` : `.deepdots-popup{width:100%;max-width:100%;border-radius:0;padding:16px}`;
2927
+ const titleJson = jsonForScript(opts.title ?? "");
2928
+ const customCss = (opts.surveyCss ?? "").replace(/<\/\s*style/gi, "<\\/style");
2929
+ const progressPref = opts.showProgressBar === void 0 ? "null" : String(opts.showProgressBar);
2930
+ const backLabel = jsonForScript(opts.actions?.back?.label ?? "Back");
2931
+ const startLabel = jsonForScript(opts.actions?.start?.label ?? "Start survey");
2932
+ const completeLabel = jsonForScript(opts.actions?.complete?.label ?? "Complete survey");
2933
+ const submitLabel = jsonForScript(opts.actions?.accept?.label ?? "Send");
1007
2934
  return `<!DOCTYPE html><html><head>
1008
2935
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
1009
2936
  <meta name="color-scheme" content="${colorScheme}"/>
@@ -1012,56 +2939,97 @@ ${style_default}
1012
2939
  ${fontFaceCss}
1013
2940
  html,body{margin:0;padding:0;height:100%;font-family:${fontFamilyValue}}
1014
2941
  body{display:${bodyDisplay};justify-content:${pos.justifyContent};align-items:${pos.alignItems};background:${bodyBg};padding:${bodyPadding};box-sizing:border-box}
1015
- .deepdots-popup{position:relative;display:flex;flex-direction:column;justify-content:flex-start;background:${cardBg};color-scheme:${colorScheme};border-radius:${cardRadius};padding:24px;box-shadow:${cardShadow};max-width:${cardMaxWidth};width:${cardWidth};min-height:${cardMinHeight};box-sizing:border-box}
1016
- .deepdots-popup-header{display:flex;justify-content:flex-end;align-items:center;width:100%}
1017
- #dd-close{background:transparent;border:none;width:32px;height:32px;display:flex;align-items:center;justify-content:center;border-radius:8px;cursor:pointer;color:${textPrimary};padding:4px}
1018
- .deepdots-popup-container-content{display:flex;flex-direction:column;padding:0 20px 12px 20px;max-height:80vh;overflow:hidden;box-sizing:border-box}
1019
- .deepdots-popup-main{display:flex;flex-direction:column;width:100%;max-height:80vh;overflow-y:auto;overflow-x:hidden;position:relative}
2942
+ .deepdots-popup{position:relative;display:flex;flex-direction:column;justify-content:flex-start;background:${cardBg};color-scheme:${colorScheme};border-radius:${cardRadius};padding:24px;box-shadow:${cardShadow};max-width:${cardMaxWidth};width:${cardWidth};min-height:${cardMinHeight};height:${cardHeight};max-height:${cardMaxHeight};box-sizing:border-box}
2943
+ .deepdots-popup-header{display:flex;justify-content:space-between;align-items:center;gap:12px;width:100%;flex:0 0 auto}
2944
+ /* Neutraliza la regla \`.deepdots-popup h2\` del CSS del survey (uppercase, centrado y
2945
+ margin-bottom 40px), pensada para los enunciados y no para el t\xEDtulo de la cabecera. */
2946
+ #dd-title{margin:0;font-family:var(--deepdots-font,'Montserrat',inherit);font-size:17px;font-weight:600;line-height:1.3;color:${textPrimary};text-transform:none;text-align:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
2947
+ #dd-close{background:transparent;border:none;width:32px;height:32px;display:flex;align-items:center;justify-content:center;border-radius:8px;cursor:pointer;color:${textPrimary};padding:4px;flex:0 0 auto;margin-left:auto}
2948
+ /* Progreso alineado con la cabecera: sin padding horizontal propio, lo marca la tarjeta.
2949
+ El vertical es el mismo arriba y abajo, y del mismo valor que el padding de la tarjeta. */
2950
+ .deepdots-progress{display:none;flex-direction:column;gap:8px;width:100%;flex:0 0 auto;padding:16px 0;box-sizing:border-box}
2951
+ .deepdots-progress-head{display:flex;flex-direction:row;justify-content:space-between;align-items:center;width:100%;gap:8px}
2952
+ #dd-progress-label{font-size:13px;line-height:1.2}
2953
+ /* "Question 1" en negrita y "of 3" en regular gris, como el mockup. */
2954
+ #dd-progress-current{font-weight:700;color:${textPrimary}}
2955
+ #dd-progress-total{font-weight:400;color:${textMuted}}
2956
+ #dd-progress-followup{display:none;font-size:12px;font-weight:600;color:#fff;background:rgba(59,130,246,0.44);border-radius:999px;padding:2px 10px}
2957
+ .deepdots-progress-track{width:100%;height:4px;border-radius:999px;background:${trackBg};overflow:hidden}
2958
+ #dd-progress-bar{height:100%;width:0%;background:#22C55E;border-radius:999px;transition:width 450ms ease}
2959
+ /* El popup es una columna: solo el bloque de preguntas hace scroll, para que el footer
2960
+ con las acciones quede siempre visible en el borde inferior (antes viv\xEDa dentro del
2961
+ \xE1rea scrollable y hab\xEDa que bajar hasta el final para ver "Send"). */
2962
+ /* Sin sangrado extra: el contenido se alinea con el t\xEDtulo y con la barra de progreso (antes
2963
+ sumaba 20px a los lados sobre el padding de la tarjeta y quedaba m\xE1s adentro que la cabecera). */
2964
+ /* Sin barra de progreso, este padding-top es el que separa la cabecera de la pregunta. Con
2965
+ barra, el JS lo pone a 0 y el hueco lo aporta el padding inferior del bloque de progreso,
2966
+ de modo que el espacio por arriba y por abajo de la barra es id\xE9ntico. */
2967
+ .deepdots-popup-container-content{display:flex;flex-direction:column;flex:1 1 auto;min-height:0;padding:16px 0 0 0;overflow:hidden;box-sizing:border-box}
2968
+ /* El enunciado trae margin-top:20px del CSS de surveys, que sumaba al hueco de la barra y
2969
+ descompensaba la simetr\xEDa. Solo se anula en el primero: entre preguntas sigue separando. */
2970
+ .deepdots-popup .magicfeedback-questions .magicfeedback-div:first-child .magicfeedback-label{margin-top:0}
2971
+ .deepdots-popup-main{display:flex;flex-direction:column;width:100%;flex:1 1 auto;min-height:0;overflow-y:auto;overflow-x:hidden;position:relative}
1020
2972
  #dd-form-wrapper{width:100%;flex:1 1 auto}
1021
2973
  #mf{width:100%;box-sizing:border-box;visibility:hidden}
1022
2974
  .deepdots-popup-main *{max-width:100%;box-sizing:border-box}
1023
- #dd-logo{max-height:40px;max-width:100%;object-fit:contain}
2975
+ #dd-logo{max-height:40px;max-width:100%;object-fit:contain;display:block;margin:12px 0 0 0}
1024
2976
  .deepdots-error-hint{display:none;margin:12px 0 0 0;padding:10px 12px;border-radius:6px;background:#FEF3C7;color:#92400E;border:1px solid #FCD34D;font-size:13px}
1025
- .deepdots-popup-footer{display:flex;flex-direction:row-reverse;justify-content:space-between;align-items:center;gap:8px;margin-top:auto;width:100%;padding-top:16px}
1026
- .dd-nav-btn{display:none;border:none;padding:12px 24px;border-radius:4px;cursor:pointer;font-size:14px;box-shadow:0 2px 4px rgba(0,0,0,0.1);align-items:center;justify-content:center;text-align:center}
1027
- #dd-back{background:transparent;color:#333;border:1px solid #999}
2977
+ /* Pantalla final: el HTML del editor de la plataforma (imagen + texto), centrado. */
2978
+ .deepdots-success{display:none;width:100%;text-align:center;padding:24px 0;color:${textPrimary}}
2979
+ .deepdots-success img{max-width:100%;height:auto;margin:0 auto 16px auto;display:block}
2980
+ .deepdots-success p{margin:0;font-size:16px;font-weight:600;line-height:1.4}
2981
+ .deepdots-popup-footer{display:flex;flex-direction:row-reverse;justify-content:space-between;align-items:center;gap:4px;margin-top:auto;width:100%;padding-top:12px}
2982
+ .dd-nav-btn{display:none;border:none;min-height:44px;padding:12px 24px;border-radius:6px;cursor:pointer;font-size:15px;font-weight:600;align-items:center;justify-content:center;text-align:center}
2983
+ /* Secundario como bot\xF3n de texto: sin borde ni fondo, para que el primario sea la \xFAnica CTA. */
2984
+ #dd-back{background:transparent;color:${textMuted};border:none}
1028
2985
  #dd-start,#dd-complete,#dd-submit{background:#1E293B;color:#fff;border:none}
1029
2986
  #dd-submit:disabled,#dd-start:disabled,#dd-back:disabled,#dd-complete:disabled{opacity:0.6;cursor:not-allowed}
1030
2987
  .mf-spinner{display:none;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}
1031
2988
  .mf-spinner-circle{width:28px;height:28px;border:3px solid #e0e6ed;border-top-color:#1E293B;border-radius:50%;animation:ddspin 0.9s linear infinite}
1032
2989
  @keyframes ddspin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}
1033
2990
  @media (max-width:640px){
1034
- .deepdots-popup{width:calc(100% - 24px);max-width:calc(100% - 24px);border-radius:12px}
1035
- .deepdots-popup-footer{flex-direction:column-reverse;gap:12px}
2991
+ ${mobileCard}
2992
+ /* Apilados: la acci\xF3n principal (Send/Start/Complete) arriba y Back debajo. El orden del
2993
+ DOM ya es ese, as\xED que \`column\` (no \`column-reverse\`) es lo que lo respeta. */
2994
+ .deepdots-popup-footer{flex-direction:column;gap:4px}
1036
2995
  .dd-nav-btn{width:100%}
1037
2996
  .magicfeedback-checkbox-container,.magicfeedback-radio-container{margin:4px 0;padding:4px 8px}
1038
2997
  .magicfeedback-checkbox label,.magicfeedback-radio-container label{font-size:15px}
1039
2998
  .deepdots-popup input[type="radio"]{margin:6px 0 6px 8px}
1040
2999
  .deepdots-popup input[type="checkbox"]{width:16px;height:16px}
1041
3000
  }
3001
+ ${customCss}
1042
3002
  </style>
1043
3003
  </head><body>
1044
3004
  <div class="${popupClass}" id="dd-popup">
1045
3005
  <div class="deepdots-popup-header">
3006
+ <h2 id="dd-title" class="deepdots-popup-title" hidden></h2>
1046
3007
  <button type="button" id="dd-close" aria-label="Close popup">
1047
- <svg width="28" height="28" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
1048
- <path d="M6 6L18 18M6 18L18 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3008
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
3009
+ <path d="M5 5L19 19M5 19L19 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="butt"/>
1049
3010
  </svg>
1050
3011
  </button>
1051
3012
  </div>
1052
- <div class="deepdots-popup-container-content">
3013
+ <div class="deepdots-progress" id="dd-progress">
3014
+ <div class="deepdots-progress-head">
3015
+ <span id="dd-progress-label"><span id="dd-progress-current"></span><span id="dd-progress-total"></span></span>
3016
+ <span id="dd-progress-followup">Follow-up</span>
3017
+ </div>
3018
+ <div class="deepdots-progress-track"><div id="dd-progress-bar"></div></div>
3019
+ </div>
3020
+ <div class="deepdots-popup-container-content" id="dd-content">
1053
3021
  <div class="deepdots-popup-main" id="dd-main">
1054
3022
  <div id="dd-form-wrapper">
1055
3023
  <div class="mf-spinner" id="dd-spinner" role="status" aria-label="Loading survey"><div class="mf-spinner-circle"></div></div>
1056
3024
  <div id="mf"></div>
1057
3025
  </div>
1058
3026
  <div class="deepdots-error-hint" id="dd-error" role="alert" aria-live="polite"></div>
1059
- <div class="deepdots-popup-footer" id="dd-footer">
1060
- <button type="button" class="dd-nav-btn" id="dd-submit">Send</button>
1061
- <button type="button" class="dd-nav-btn" id="dd-back">Back</button>
1062
- <button type="button" class="dd-nav-btn" id="dd-complete">Complete survey</button>
1063
- <button type="button" class="dd-nav-btn" id="dd-start">Start survey</button>
1064
- </div>
3027
+ </div>
3028
+ <div class="deepdots-popup-footer" id="dd-footer">
3029
+ <button type="button" class="dd-nav-btn" id="dd-submit">Send</button>
3030
+ <button type="button" class="dd-nav-btn" id="dd-back">Back</button>
3031
+ <button type="button" class="dd-nav-btn" id="dd-complete">Complete survey</button>
3032
+ <button type="button" class="dd-nav-btn" id="dd-start">Start survey</button>
1065
3033
  </div>
1066
3034
  </div>
1067
3035
  </div>
@@ -1074,6 +3042,7 @@ body{display:${bodyDisplay};justify-content:${pos.justifyContent};align-items:${
1074
3042
 
1075
3043
  var popup=document.getElementById('dd-popup');
1076
3044
  var main=document.getElementById('dd-main');
3045
+ var content=document.getElementById('dd-content');
1077
3046
  var footer=document.getElementById('dd-footer');
1078
3047
  var spinner=document.getElementById('dd-spinner');
1079
3048
  var formHost=document.getElementById('mf');
@@ -1082,6 +3051,58 @@ body{display:${bodyDisplay};justify-content:${pos.justifyContent};align-items:${
1082
3051
  var startBtn=document.getElementById('dd-start');
1083
3052
  var completeBtn=document.getElementById('dd-complete');
1084
3053
  var submitBtn=document.getElementById('dd-submit');
3054
+ var titleEl=document.getElementById('dd-title');
3055
+ var progressEl=document.getElementById('dd-progress');
3056
+ var progressLabel=document.getElementById('dd-progress-label');
3057
+ var progressCurrent=document.getElementById('dd-progress-current');
3058
+ var progressTotal=document.getElementById('dd-progress-total');
3059
+ var progressFollowUp=document.getElementById('dd-progress-followup');
3060
+ var progressBar=document.getElementById('dd-progress-bar');
3061
+
3062
+ function setTitle(t){
3063
+ if(!t) return;
3064
+ titleEl.textContent=t;
3065
+ titleEl.hidden=false;
3066
+ }
3067
+ setTitle(${titleJson});
3068
+
3069
+ // Estado de la barra de progreso. \`progressPref\` null = manda la plataforma (style).
3070
+ var progressPref=${progressPref};
3071
+ var progressEnabled=progressPref===true;
3072
+ var progressShowUnit=true;
3073
+ var progressUnit='fraction';
3074
+ var onStartPage=false;
3075
+
3076
+ function updateProgress(p){
3077
+ var total=p&&typeof p.total==='number'?p.total:0;
3078
+ var progress=p&&typeof p.progress==='number'?p.progress:0;
3079
+ // Solo tiene sentido con m\xE1s de una p\xE1gina, fuera de la pantalla de inicio y sin completar.
3080
+ if(!progressEnabled||onStartPage||p&&p.completed||total<=1){
3081
+ progressEl.style.display='none';
3082
+ // Sin barra, el hueco cabecera\u2192pregunta lo pone el contenido.
3083
+ content.style.paddingTop='16px';
3084
+ return;
3085
+ }
3086
+ progressEl.style.display='flex';
3087
+ // Con barra, el hueco inferior ya lo pone el bloque de progreso: no duplicarlo.
3088
+ content.style.paddingTop='0';
3089
+ // Espejo de LineProgressQuestion (MagicSurvey): la barra usa el valor real (las follow-up
3090
+ // suman +0.5 y avanzan media casilla) y la etiqueta redondea hacia abajo, porque una
3091
+ // follow-up es un paso DENTRO de la misma pregunta, no la siguiente.
3092
+ var current=Math.min(total,Math.max(1,progress+1));
3093
+ var pct=Math.min(100,Math.max(0,(current/total)*100));
3094
+ progressBar.style.width=pct+'%';
3095
+ var label=Math.min(total,Math.max(1,Math.floor(progress)+1));
3096
+ progressLabel.style.display=progressShowUnit?'block':'none';
3097
+ if(progressUnit==='percentage'){
3098
+ progressCurrent.textContent=Math.round(pct)+'%';
3099
+ progressTotal.textContent='';
3100
+ } else {
3101
+ progressCurrent.textContent='Question '+label;
3102
+ progressTotal.textContent=' of '+total;
3103
+ }
3104
+ progressFollowUp.style.display=p&&p.followup?'inline-block':'none';
3105
+ }
1085
3106
 
1086
3107
  backBtn.textContent=${backLabel};
1087
3108
  startBtn.textContent=${startLabel};
@@ -1090,7 +3111,13 @@ body{display:${bodyDisplay};justify-content:${pos.justifyContent};align-items:${
1090
3111
 
1091
3112
  document.getElementById('dd-close').onclick=function(){ emitJSON('popup_close'); };
1092
3113
  backBtn.onclick=function(){ if(window.DeepdotsForm && window.DeepdotsForm.back){ window.DeepdotsForm.back(); } };
1093
- startBtn.onclick=function(){ if(window.DeepdotsForm && window.DeepdotsForm.startForm){ window.DeepdotsForm.startForm(); } };
3114
+ startBtn.onclick=function(){
3115
+ if(window.DeepdotsForm && window.DeepdotsForm.startForm){
3116
+ window.DeepdotsForm.startForm();
3117
+ onStartPage=false;
3118
+ updateProgress({ progress:window.DeepdotsForm.progress, total:window.DeepdotsForm.total, completed:false, followup:false });
3119
+ }
3120
+ };
1094
3121
  completeBtn.onclick=function(){ emitJSON('popup_close'); };
1095
3122
  var surveyCompletedEmitted=false;
1096
3123
  submitBtn.onclick=function(){
@@ -1098,6 +3125,36 @@ body{display:${bodyDisplay};justify-content:${pos.justifyContent};align-items:${
1098
3125
  if(window.DeepdotsForm && window.DeepdotsForm.send){ window.DeepdotsForm.send(); }
1099
3126
  };
1100
3127
 
3128
+ // Mensaje final configurado en la plataforma (\`style.successMessage\`). Se guarda al cargar
3129
+ // y se pinta al completar. Va por innerHTML porque es HTML del editor de la plataforma
3130
+ // (imagen + texto), igual que ya hace \`renderStartMessage\` con el mensaje de inicio.
3131
+ var successMessageHtml='';
3132
+ function showSuccessScreen(){
3133
+ progressEl.style.display='none';
3134
+ var wrapper=document.getElementById('dd-form-wrapper');
3135
+ if(wrapper){ wrapper.style.display='none'; }
3136
+ var done=document.getElementById('dd-success');
3137
+ if(!done){
3138
+ done=document.createElement('div');
3139
+ done.id='dd-success';
3140
+ done.className='deepdots-success';
3141
+ main.insertBefore(done, errorHint);
3142
+ }
3143
+ done.innerHTML=successMessageHtml || '<p>Thank you for your feedback!</p>';
3144
+ done.style.display='block';
3145
+ }
3146
+
3147
+ // Profundidad de navegaci\xF3n DENTRO del survey: +1 por p\xE1gina avanzada, -1 al volver.
3148
+ // Sustituye a la condici\xF3n \`total>1 && progress>0 && progress<total\`, que escond\xEDa el
3149
+ // Back siempre que la siguiente pantalla era una follow-up din\xE1mica: las follow-up no
3150
+ // entran en el grafo (suman +0.5 al progress y no tocan el total), as\xED que un survey de
3151
+ // una pregunta con follow-up tiene total=1 y nunca cumpl\xEDa \`total>1\`.
3152
+ var pageDepth=0;
3153
+
3154
+ function updateNavButtons(){
3155
+ updateButtons(pageDepth>0?'in_progress_next':'in_progress_first');
3156
+ }
3157
+
1101
3158
  function updateButtons(state){
1102
3159
  backBtn.style.display='none';
1103
3160
  startBtn.style.display='none';
@@ -1142,10 +3199,20 @@ body{display:${bodyDisplay};justify-content:${pos.justifyContent};align-items:${
1142
3199
  form.generate('mf', {
1143
3200
  addButton:false,
1144
3201
  getMetaData:true,
3202
+ // La pantalla final la pinta el popup: renderSuccess de @magicfeedback/native usa
3203
+ // textContent, as\xED que el mensaje de la plataforma (HTML con imagen) no se ver\xEDa, y su
3204
+ // fallback es un literal gen\xE9rico que ignora style.successMessage.
3205
+ addSuccessScreen:false,
1145
3206
  onLoadedEvent:function(args){
1146
3207
  var s=args && args.formData ? args.formData.style : null;
1147
3208
  if(s && !stylesInjected){
1148
3209
  stylesInjected=true;
3210
+ if(s.successMessage){ successMessageHtml=s.successMessage; }
3211
+ // La barra de progreso la decide el host (init) y, si no se pronuncia, la plataforma.
3212
+ if(progressPref===null){ progressEnabled=s.showProgressBar===true; }
3213
+ if(s.showProgressUnit!==undefined){ progressShowUnit=s.showProgressUnit!==false; }
3214
+ if(s.progressUnit){ progressUnit=s.progressUnit; }
3215
+ if(s.loadingBarColor){ progressBar.style.background=s.loadingBarColor; progressFollowUp.style.background=s.loadingBarColor; }
1149
3216
  if(chromeOn && s.boxBackgroundColor){ popup.style.background=s.boxBackgroundColor; }
1150
3217
  if(s.contentAlign){ main.style.justifyContent = s.contentAlign==='center' ? 'center' : 'flex-start'; }
1151
3218
  if(s.buttonPrimaryColor){
@@ -1154,7 +3221,8 @@ body{display:${bodyDisplay};justify-content:${pos.justifyContent};align-items:${
1154
3221
  completeBtn.style.background=s.buttonPrimaryColor; completeBtn.style.border='none'; completeBtn.style.color='#fff';
1155
3222
  }
1156
3223
  if(s.buttonSecondaryColor){
1157
- backBtn.style.background='#fff'; backBtn.style.color=s.buttonSecondaryColor; backBtn.style.border='1px solid '+s.buttonSecondaryColor;
3224
+ // Bot\xF3n de texto: solo ti\xF1e la etiqueta, sin recuperar fondo ni borde.
3225
+ backBtn.style.background='transparent'; backBtn.style.color=s.buttonSecondaryColor; backBtn.style.border='none';
1158
3226
  }
1159
3227
  if(s.logo && !document.getElementById('dd-logo')){
1160
3228
  var logoImg=document.createElement('img');
@@ -1162,16 +3230,20 @@ body{display:${bodyDisplay};justify-content:${pos.justifyContent};align-items:${
1162
3230
  if(s.logoSize==='small'){ logoImg.style.maxHeight='30px'; }
1163
3231
  else if(s.logoSize==='medium'){ logoImg.style.maxHeight='50px'; }
1164
3232
  else if(s.logoSize==='large'){ logoImg.style.maxHeight='70px'; }
1165
- if(s.logoPosition==='left'){ logoImg.style.margin='0 16px 20px 0'; logoImg.style.display='block'; logoImg.style.marginLeft='0'; }
1166
- else if(s.logoPosition==='right'){ logoImg.style.margin='0 0 20px 16px'; logoImg.style.display='block'; logoImg.style.marginLeft='auto'; }
1167
- else if(s.logoPosition==='center'){ logoImg.style.margin='0 auto 20px auto'; logoImg.style.display='block'; }
1168
- main.insertBefore(logoImg, document.getElementById('dd-form-wrapper'));
3233
+ if(s.logoPosition==='left'){ logoImg.style.margin='12px 16px 0 0'; logoImg.style.marginLeft='0'; }
3234
+ else if(s.logoPosition==='right'){ logoImg.style.margin='12px 0 0 16px'; logoImg.style.marginLeft='auto'; }
3235
+ else if(s.logoPosition==='center'){ logoImg.style.margin='12px auto 0 auto'; }
3236
+ // Encima de la barra de progreso, como hermano del header (espejo de ui/logo.ts en
3237
+ // web). Fuera de #dd-main, as\xED el logo no se va con el scroll del formulario.
3238
+ popup.insertBefore(logoImg, progressEl);
1169
3239
  }
1170
- if(s.startMessage && s.startMessage!==''){ updateButtons('start'); }
3240
+ if(s.startMessage && s.startMessage!==''){ onStartPage=true; updateButtons('start'); }
1171
3241
  else { updateButtons('in_progress_first'); }
1172
3242
  } else {
1173
3243
  updateButtons('in_progress_first');
1174
3244
  }
3245
+ // El total solo se conoce una vez montado el form; sin \xE9l no hay barra que pintar.
3246
+ updateProgress({ progress:form.progress, total:form.total, completed:false, followup:false });
1175
3247
  emitJSON('loaded');
1176
3248
  setLoading(false);
1177
3249
  },
@@ -1184,9 +3256,10 @@ body{display:${bodyDisplay};justify-content:${pos.justifyContent};align-items:${
1184
3256
  if(error){
1185
3257
  setLoading(false);
1186
3258
  if(error.toLowerCase().indexOf('no response')!==-1){
3259
+ // La p\xE1gina no ha cambiado: el estado de navegaci\xF3n se queda como estaba.
1187
3260
  errorHint.textContent='Please answer the required question to continue.';
1188
3261
  errorHint.style.display='block';
1189
- updateButtons('in_progress_next');
3262
+ updateNavButtons();
1190
3263
  return;
1191
3264
  }
1192
3265
  errorHint.textContent='An error occurred while submitting. Please try again or close the popup.';
@@ -1197,17 +3270,23 @@ body{display:${bodyDisplay};justify-content:${pos.justifyContent};align-items:${
1197
3270
  setLoading(false);
1198
3271
  if(p && p.completed){
1199
3272
  surveyCompletedEmitted=true;
3273
+ showSuccessScreen();
1200
3274
  updateButtons('completed');
3275
+ updateProgress(p);
1201
3276
  emitJSON('survey_completed', p);
1202
3277
  return;
1203
3278
  }
1204
- if(p && p.total>1 && p.progress>0 && p.progress<p.total){ updateButtons('in_progress_next'); }
1205
- else { updateButtons('in_progress_first'); }
3279
+ pageDepth++;
3280
+ updateNavButtons();
3281
+ updateProgress(p);
1206
3282
  emitJSON('after_submit', p);
1207
3283
  },
1208
3284
  onBackEvent:function(p){
1209
- if(p && p.progress===0){ updateButtons('in_progress_first'); }
1210
- else { updateButtons('in_progress_next'); }
3285
+ // Con error ("No page found") no hubo navegaci\xF3n: la profundidad no se toca.
3286
+ if(!(p&&p.error)){ pageDepth=Math.max(0,pageDepth-1); }
3287
+ updateNavButtons();
3288
+ // onBackEvent no trae \`total\`: se lee del form, que es su due\xF1o.
3289
+ updateProgress({ progress:p&&p.progress, total:form.total, completed:false, followup:p&&p.followup });
1211
3290
  emitJSON('back', p);
1212
3291
  }
1213
3292
  }).catch(function(e){ setLoading(false); emit('error:init'); });
@@ -1236,7 +3315,7 @@ var ReactNativePopupRenderer = class {
1236
3315
  }
1237
3316
  init() {
1238
3317
  }
1239
- show(surveyId, productId, actions, emit, onClose, env = "production", userId, style, sessionId, miniService, analyticsFeedbackSessionId, renderChrome) {
3318
+ show(surveyId, productId, actions, emit, onClose, env = "production", userId, style, sessionId, miniService, analyticsFeedbackSessionId, renderChrome, options) {
1240
3319
  this.emitFn = emit;
1241
3320
  this.onCloseFn = onClose;
1242
3321
  this.currentSurveyId = surveyId;
@@ -1253,7 +3332,10 @@ var ReactNativePopupRenderer = class {
1253
3332
  position: style?.position,
1254
3333
  actions,
1255
3334
  // renderChrome:false (init) → HTML sin tarjeta/overlay: el host lo envuelve en su Modal.
1256
- chrome: renderChrome
3335
+ chrome: renderChrome,
3336
+ title: options?.title,
3337
+ showProgressBar: options?.showProgressBar,
3338
+ surveyCss: options?.surveyCss
1257
3339
  });
1258
3340
  if (this.options.onShow) {
1259
3341
  this.options.onShow({ surveyId, productId, html });
@@ -1293,7 +3375,6 @@ var ReactNativePopupRenderer = class {
1293
3375
  break;
1294
3376
  case "survey_completed":
1295
3377
  this.emitFn("survey_completed", surveyId);
1296
- this.onCloseFn?.();
1297
3378
  break;
1298
3379
  case "popup_close":
1299
3380
  this.onCloseFn?.();
@@ -1344,14 +3425,14 @@ var BrowserPopupRenderer = class {
1344
3425
  document.body.appendChild(this.container);
1345
3426
  }
1346
3427
  }
1347
- show(surveyId, productId, actions, emit, onClose, env = "production", userId, style, sessionId, miniService, analyticsFeedbackSessionId, _renderChrome) {
3428
+ show(surveyId, productId, actions, emit, onClose, env = "production", userId, style, sessionId, miniService, analyticsFeedbackSessionId, _renderChrome, options) {
1348
3429
  if (this.visible) return;
1349
3430
  if (!this.container || !document.body.contains(this.container)) this.init();
1350
3431
  if (!this.container) return;
1351
3432
  this.visible = true;
1352
3433
  const container = this.container;
1353
3434
  void Promise.resolve().then(() => (init_renderPopup(), renderPopup_exports)).then(({ renderPopup: renderPopup2 }) => {
1354
- renderPopup2(container, surveyId, productId, actions, emit, onClose, env, userId, style, sessionId, miniService, analyticsFeedbackSessionId);
3435
+ renderPopup2(container, surveyId, productId, actions, emit, onClose, env, userId, style, sessionId, miniService, analyticsFeedbackSessionId, options);
1355
3436
  });
1356
3437
  }
1357
3438
  hide() {
@@ -2207,6 +4288,10 @@ var DeepdotsPopups = class {
2207
4288
  this.env = "production";
2208
4289
  /** Si el SDK pinta el "modal" del popup (RN). Default true; false = el host lo envuelve. */
2209
4290
  this.renderChrome = true;
4291
+ /** Barra de progreso. undefined = la decide la plataforma (style.showProgressBar). */
4292
+ this.showProgressBar = void 0;
4293
+ /** CSS del host inyectado al final de los estilos del popup. */
4294
+ this.surveyCss = void 0;
2210
4295
  /** Identidad + sesión (Fase 1 tracking). Null hasta init(). */
2211
4296
  this.tracking = null;
2212
4297
  /** Capa de analytics (canal separado del feedback). Null hasta init(). */
@@ -2258,6 +4343,8 @@ var DeepdotsPopups = class {
2258
4343
  this.baseUrl = env.apiBaseUrl;
2259
4344
  this.env = config.nodeEnv || "production";
2260
4345
  this.renderChrome = config.renderChrome ?? true;
4346
+ this.showProgressBar = config.showProgressBar;
4347
+ this.surveyCss = config.surveyCss;
2261
4348
  this.config = {
2262
4349
  apiKey: config.apiKey || void 0,
2263
4350
  debug: config.debug || false,
@@ -2703,7 +4790,7 @@ var DeepdotsPopups = class {
2703
4790
  this.log("Showing popup (definition)", def);
2704
4791
  this.surveyToPopupId.set(def.surveyId, def.id);
2705
4792
  this.lastShown.set(def.id, Date.now());
2706
- this.renderPopup(def.surveyId, def.productId, def.actions, def.style);
4793
+ this.renderPopup(def.surveyId, def.productId, def.actions, def.style, def.title);
2707
4794
  this.emitEvent("popup_shown", def.surveyId, { popupId: def.id });
2708
4795
  }
2709
4796
  shouldShow(def, pathUrl, skipPathCheck = false) {
@@ -3041,7 +5128,7 @@ var DeepdotsPopups = class {
3041
5128
  document.body.appendChild(this.popupContainer);
3042
5129
  }
3043
5130
  /** Render the popup UI */
3044
- renderPopup(surveyId, productId, actions, style) {
5131
+ renderPopup(surveyId, productId, actions, style, title) {
3045
5132
  const userId = this.tracking?.getUserId() ?? this.config?.userId;
3046
5133
  const sessionId = this.tracking?.getSessionId() ?? void 0;
3047
5134
  const miniService = this.analytics?.getMiniService() ?? void 0;
@@ -3060,7 +5147,8 @@ var DeepdotsPopups = class {
3060
5147
  sessionId,
3061
5148
  miniService,
3062
5149
  analyticsFeedbackSessionId,
3063
- this.renderChrome
5150
+ this.renderChrome,
5151
+ { title, showProgressBar: this.showProgressBar, surveyCss: this.surveyCss }
3064
5152
  );
3065
5153
  return;
3066
5154
  }
@@ -3079,7 +5167,8 @@ var DeepdotsPopups = class {
3079
5167
  style,
3080
5168
  sessionId,
3081
5169
  miniService,
3082
- analyticsFeedbackSessionId
5170
+ analyticsFeedbackSessionId,
5171
+ { title, showProgressBar: this.showProgressBar, surveyCss: this.surveyCss }
3083
5172
  );
3084
5173
  });
3085
5174
  }