1<!DOCTYPE html><!-- Created with https://systeme.io --><html lang="es"><head><link rel="icon" type="image/png" href="/15882402/697d1c3158a9f_logo.png"><link rel="apple-touch-icon" href="/15882402/697d1c3158a9f_logo.png"><meta charSet="utf-8"/><title data-react-helmet="true"></title><meta data-react-helmet="true" name="viewport" content="width=device-width, initial-scale=1"/><meta data-react-helmet="true" name="title" content=""/><meta data-react-helmet="true" name="description"/><meta data-react-helmet="true" name="author"/><meta data-react-helmet="true" name="keywords"/><meta data-react-helmet="true" property="og:image" content=""/><meta data-react-helmet="true" property="og:url" content="https://www.opanal.org/portal-interno"/><style data-styled="" data-styled-version="6.5.3">@layer properties,theme,base,components,commonComponents,commonComponentsUtils,utilities;/*!sc*/ 2html{box-sizing:border-box;scroll-behavior:smooth;overscroll-behavior-x:none;-webkit-text-size-adjust:100%;text-size-adjust:100%;}/*!sc*/ 3body{margin:0;}/*!sc*/ 4a{text-decoration:none;}/*!sc*/ 5p span>a[href^="tel:"]{color:inherit;}/*!sc*/ 6p{margin:0;}/*!sc*/ 7*,*:before,*:after{box-sizing:inherit;}/*!sc*/ 8*{-webkit-font-smoothing:antialiased;}/*!sc*/ 9h1,h2,h3,h4,h5,h6{margin:0;font-weight:normal;}/*!sc*/ 10section h1{margin:0;}/*!sc*/ 11@layer base{button,input{margin:0;font-family:unset;}}/*!sc*/ 12ul{margin:0;}/*!sc*/ 13data-styled.g11[id="sc-global-eOtyEU"]{content:"sc-global-eOtyEU1,"}/*!sc*/ 14.gFDeHN{position:absolute;z-index:0;height:100%;width:100%;top:0;left:0;z-index:-1;filter:blur(0px);background-image:none;}/*!sc*/ 15@media only screen and (max-width: 800px){.gFDeHN{background-image:none;}}/*!sc*/ 16data-styled.g15[id="sc-crHjOq"]{content:"gFDeHN,"}/*!sc*/ 17.jqsMpv{position:relative;width:100%;}/*!sc*/ 18data-styled.g16[id="sc-eggkz"]{content:"jqsMpv,"}/*!sc*/ 19.gbtzXi{position:relative;text-align:initial;}/*!sc*/ 20.bnUURH{position:relative;text-align:initial;margin:0px 0px 0px 0px;}/*!sc*/ 21@media only screen and (max-width: 800px){.bnUURH{margin-top:0px;margin-right:0px;margin-bottom:0px;margin-left:0px;}}/*!sc*/ 22data-styled.g44[id="sc-jcFiBM"]{content:"gbtzXi,bnUURH,"}/*!sc*/ 23.hiEHBT{display:flex;flex-direction:column;grid-column-start:1;grid-column-end:13;align-self:flex-start;}/*!sc*/ 24@media only screen and (max-width: 800px){.hiEHBT{align-self:unset;width:100%;grid-column-start:1;grid-column-end:12;padding-left:0;padding-right:0;}}/*!sc*/ 25data-styled.g79[id="sc-bTfXSk"]{content:"hiEHBT,"}/*!sc*/ 26.krlRSM{display:grid;position:relative;justify-content:space-between;grid-template-columns:repeat(12, 1fr);column-gap:20px;padding-top:10px;padding-right:10px;padding-bottom:10px;padding-left:10px;background-image:none;background-size:initial;background-position:50% 50%;background-repeat:repeat;background-attachment:initial;column-gap:unset!important;}/*!sc*/ 27@media only screen and (max-width: 800px){.krlRSM{padding-top:5px;padding-right:5px;padding-bottom:5px;padding-left:5px;}}/*!sc*/ 28@media only screen and (max-width: 800px){.krlRSM{display:flex;flex-direction:column;grid-template-columns:auto;background-image:none;}}/*!sc*/ 29data-styled.g80[id="sc-kHOYJp"]{content:"krlRSM,"}/*!sc*/ 30.krelXo{display:flex;position:relative;padding-top:40px;padding-right:40px;padding-bottom:40px;padding-left:40px;background-image:none;background-size:initial;background-position:50% 50%;background-repeat:no-repeat;background-attachment:initial;}/*!sc*/ 31@media only screen and (max-width: 800px){.krelXo{padding-top:5px;padding-right:5px;padding-bottom:5px;padding-left:5px;}}/*!sc*/ 32@media only screen and (max-width: 800px){.krelXo{background-image:none;}}/*!sc*/ 33data-styled.g81[id="sc-hOGlKT"]{content:"krelXo,"}/*!sc*/ 34.KfaxH{max-width:100%;width:100%;margin:auto;}/*!sc*/ 35@media only screen and (max-width: 800px){.KfaxH{max-width:initial;}}/*!sc*/ 36data-styled.g82[id="sc-dtMhIu"]{content:"KfaxH,"}/*!sc*/ 37.kFbANl{display:flex;width:100%;height:100%;min-height:100vh;position:relative;}/*!sc*/ 38data-styled.g83[id="sc-cZMPup"]{content:"kFbANl,"}/*!sc*/ 39.fwprJq{min-height:20px;text-align:center;}/*!sc*/ 40data-styled.g385[id="sc-kQoOGY"]{content:"fwprJq,"}/*!sc*/ 41</style><link data-react-helmet="true" rel="canonical" href="https://www.opanal.org/portal-interno"/><link rel="stylesheet" href="https://d3fit27i5nzkqh.cloudfront.net/sales/page.b408d3a89d6ec61a.css"/><style>:host,:root{--fa-family-brands:"Font Awesome 7 Brands";--fa-font-brands:normal 400 1em/1 var(--fa-family-brands);}@font-face{font-family:"Font Awesome 7 Brands";font-style:normal;font-weight:400;font-display:swap;src:url(https://d3fit27i5nzkqh.cloudfront.net/assets/fontawesome/7.2.0/webfonts/fa-brands-400.woff2);}:host,:root{--fa-family-duotone:"Font Awesome 7 Duotone";--fa-font-duotone:normal 900 1em/1 var(--fa-family-duotone);--fa-style-family-duotone:var(--fa-family-duotone);}@font-face{font-family:"Font Awesome 7 Duotone";font-style:normal;font-weight:900;font-display:swap;src:url(https://d3fit27i5nzkqh.cloudfront.net/assets/fontawesome/7.2.0/webfonts/fa-duotone-900.woff2);}:host,:root{--fa-font-light:normal 300 1em/1 var(--fa-family-classic);}@font-face{font-family:"Font Awesome 7 Pro";font-style:normal;font-weight:300;font-display:swap;src:url(https://d3fit27i5nzkqh.cloudfront.net/assets/fontawesome/7.2.0/webfonts/fa-light-300.woff2);}:host,:root{--fa-font-regular:normal 400 1em/1 var(--fa-family-classic);}@font-face{font-family:"Font Awesome 7 Pro";font-style:normal;font-weight:400;font-display:swap;src:url(https://d3fit27i5nzkqh.cloudfront.net/assets/fontawesome/7.2.0/webfonts/fa-regular-400.woff2);}:host,:root{--fa-font-solid:normal 900 1em/1 var(--fa-family-classic);}@font-face{font-family:"Font Awesome 7 Pro";font-style:normal;font-weight:900;font-display:swap;src:url(https://d3fit27i5nzkqh.cloudfront.net/assets/fontawesome/7.2.0/webfonts/fa-solid-900.woff2);}:host,:root{--fa-family-classic:"Font Awesome 7 Pro";--fa-font-thin:normal 100 1em/1 var(--fa-family-classic);--fa-style-family-classic:var(--fa-family-classic);}@font-face{font-family:"Font Awesome 7 Pro";font-style:normal;font-weight:100;font-display:swap;src:url(https://d3fit27i5nzkqh.cloudfront.net/assets/fontawesome/7.2.0/webfonts/fa-thin-100.woff2);}@font-face{font-family:"Font Awesome 5 Brands";font-display:swap;font-weight:400;src:url(https://d3fit27i5nzkqh.cloudfront.net/assets/fontawesome/7.2.0/webfonts/fa-brands-400.woff2) format("woff2");}@font-face{font-family:"Font Awesome 5 Pro";font-display:swap;font-weight:900;src:url(https://d3fit27i5nzkqh.cloudfront.net/assets/fontawesome/7.2.0/webfonts/fa-solid-900.woff2) format("woff2");}@font-face{font-family:"Font Awesome 5 Pro";font-display:swap;font-weight:400;src:url(https://d3fit27i5nzkqh.cloudfront.net/assets/fontawesome/7.2.0/webfonts/fa-regular-400.woff2) format("woff2");}@font-face{font-family:"Font Awesome 5 Pro";font-display:swap;font-weight:300;src:url(https://d3fit27i5nzkqh.cloudfront.net/assets/fontawesome/7.2.0/webfonts/fa-light-300.woff2) format("woff2");}@font-face{font-family:"Font Awesome 5 Duotone";font-display:swap;font-weight:900;src:url(https://d3fit27i5nzkqh.cloudfront.net/assets/fontawesome/7.2.0/webfonts/fa-duotone-900.woff2) format("woff2");}@font-face{font-family:"FontAwesome";font-display:swap;src:url(https://d3fit27i5nzkqh.cloudfront.net/assets/fontawesome/7.2.0/webfonts/fa-solid-900.woff2) format("woff2");}@font-face{font-family:"FontAwesome";font-display:swap;src:url(https://d3fit27i5nzkqh.cloudfront.net/assets/fontawesome/7.2.0/webfonts/fa-brands-400.woff2) format("woff2");}@font-face{font-family:"FontAwesome";font-display:swap;src:url(https://d3fit27i5nzkqh.cloudfront.net/assets/fontawesome/7.2.0/webfonts/fa-regular-400.woff2) format("woff2");
41unicode-range:u+f003,u+f006,u+f014,u+f016-f017,u+f01a-f01b,u+f01d,u+f022,u+f03e,u+f044,u+f046,u+f05c-f05d,u+f06e,u+f070,u+f087-f088,u+f08a,u+f094,u+f096-f097,u+f09d,u+f0a0,u+f0a2,u+f0a4-f0a7,u+f0c5,u+f0c7,u+f0e5-f0e6,u+f0eb,u+f0f6-f0f8,u+f10c,u+f114-f115,u+f118-f11a,u+f11c-f11d,u+f133,u+f147,u+f14e,u+f150-f152,u+f185-f186,u+f18e,u+f190-f192,u+f196,u+f1c1-f1c9,u+f1d9,u+f1db,u+f1e3,u+f1ea,u+f1f7,u+f1f9,u+f20a,u+f247-f248,u+f24a,u+f24d,u+f255-f25b,u+f25d,u+f271-f274,u+f278,u+f27b,u+f28c,u+f28e,u+f29c,u+f2b5,u+f2b7,u+f2ba,u+f2bc,u+f2be,u+f2c0-f2c1,u+f2c3,u+f2d0,u+f2d2,u+f2d4,u+f2dc;}@font-face{font-family:"FontAwesome";font-display:swap;src:url(https://d3fit27i5nzkqh.cloudfront.net/assets/fontawesome/7.2.0/webfonts/fa-v4compatibility.woff2) format("woff2");unicode-range:u+f041,u+f047,u+f065-f066,u+f07d-f07e,u+f080,u+f08b,u+f08e,u+f090,u+f09a,u+f0ac,u+f0ae,u+f0b2,u+f0d0,u+f0d6,u+f0e4,u+f0ec,u+f10a-f10b,u+f123,u+f13e,u+f148-f149,u+f14c,u+f156,u+f15e,u+f160-f161,u+f163,u+f175-f178,u+f195,u+f1f8,u+f219,u+f27a;}.fal{--_fa-family:var(--fa-family,var(--fa-style-family,"Font Awesome 7 Pro"));-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;display:var(--fa-display,inline-block);font-family:var(--_fa-family);font-feature-settings:normal;font-style:normal;font-synthesis:none;font-variant:normal;font-weight:var(--fa-style,900);line-height:1;text-align:center;text-rendering:auto;width:var(--fa-width,1.25em);}.fal:before{content:var(--fa);}.fal{--fa-family:var(--fa-family-classic);}.fal{--fa-style:300;}.fa-chevron-circle-left{--fa:"\f137";}.fa-chevron-circle-right{--fa:"\f138";}.fas{--_fa-family:var(--fa-family,var(--fa-style-family,"Font Awesome 7 Pro"));-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;display:var(--fa-display,inline-block);font-family:var(--_fa-family);font-feature-settings:normal;font-style:normal;font-synthesis:none;font-variant:normal;font-weight:var(--fa-style,900);line-height:1;text-align:center;text-rendering:auto;width:var(--fa-width,1.25em);}.fas:before{content:var(--fa);}.fas{--fa-family:var(--fa-family-classic);}.fas{--fa-style:900;}.fa-chevron-down{--fa:"\f078";}.fa-chevron-left{--fa:"\f053";}.fad{--_fa-family:var(--fa-family,var(--fa-style-family,"Font Awesome 7 Pro"));-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;display:var(--fa-display,inline-block);font-family:var(--_fa-family);font-feature-settings:normal;font-style:normal;font-synthesis:none;font-variant:normal;font-weight:var(--fa-style,900);line-height:1;text-align:center;text-rendering:auto;width:var(--fa-width,1.25em);}.fad:before{content:var(--fa);}.fad:after{content:var(--fa);font-feature-settings:"ss01";}.fad{--fa-family:var(--fa-family-duotone);--fa-style:900;position:relative;letter-spacing:normal;}.fad:before{position:absolute;color:var(--fa-primary-color,currentColor);opacity:var(--fa-primary-opacity,1);}.fad:after{color:var(--fa-secondary-color,currentColor);}.fad:after{opacity:var(--fa-secondary-opacity,.4);}.fa-chevron-right{--fa:"\f054";}.fa-chevron-up{--fa:"\f077";}.fa-circle{--fa:"\f111";}.far{--_fa-family:var(--fa-family,var(--fa-style-family,"Font Awesome 7 Pro"));-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;display:var(--fa-display,inline-block);font-family:var(--_fa-family);font-feature-settings:normal;font-style:normal;font-synthesis:none;font-variant:normal;font-weight:var(--fa-style,900);line-height:1;text-align:center;text-rendering:auto;width:var(--fa-width,1.25em);}.far:before{content:var(--fa);}.far{--fa-family:var(--fa-family-classic);}.far{--fa-style:400;}.fa-clock{--fa:"\f017";}.fa-eye{--fa:"\f06e";}.fa-eye-slash{--fa:"\f070";}.fa{--_fa-family:var(--fa-family,var(--fa-style-family,"Font Awesome 7 Pro"));-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;display:var(--fa-display,inline-block);font-family:var(--_fa-family);font-feature-settings:normal;font-style:normal;font-synthesis:none;font-variant:normal;font-weight:var(--fa-style,900);line-height:1;text-align:center;text-rendering:auto;width:var(--fa-width,1.25em);}.fa:before{content:var(--fa);}.fa-times{--fa:"\f00d";}</style> <meta property="og:type" content="website"/></head><body><div id="app"><div class="sc-cZMPup kFbANl"><div class="sc-eggkz jqsMpv"><div class="sc-crHjOq gFDeHN"></div><div class="sc-jcFiBM gbtzXi"><section id="section-0b1ba2d1" class="sc-hOGlKT krelXo"><div width="100%" class="sc-dtMhIu KfaxH"><div class="sc-jcFiBM gbtzXi"><div id="row-4c2f6aa3" class="sc-kHOYJp krlRSM"><div size="12" class="sc-bTfXSk hiEHBT"><div class="sc-jcFiBM bnUURH"><div id="rawhtml-18f2cb90" class="sc-kQoOGY fwprJq"><!-- Portal Interno OPANAL --> 42 43<!-- Firebase SDKs -->
44<script src="https://www.gstatic.com/firebasejs/10.12.0/firebase-app-compat.js"></script>
vendor: 1 bytes, line 44
44
45<script src="https://www.gstatic.com/firebasejs/10.12.0/firebase-auth-compat.js"></script>
vendor: 1 bytes, line 45
45
46<script src="https://www.gstatic.com/firebasejs/10.12.0/firebase-database-compat.js"></script>
46 47 48<!-- Selector de idioma Español/Inglés -->
49<script>window.gtranslateSettings = {"default_language":"es","native_language_names":true,"languages":["es","en"],"wrapper_selector":".gtranslate_wrapper"}</script>
vendor: 1 bytes, line 49
49
50<script src="https://cdn.gtranslate.net/widgets/latest/ln.js" defer></script>
50 51 52<style> 53 54html, body { margin: 0; background: #FCF8F3; } 55 56.full-width{ 57 width:100vw; 58 margin-left:calc(-50vw + 50%); 59 padding: 0 2rem; 60 box-sizing: border-box; 61} 62 63@media (max-width:768px){ 64 .full-width{ padding: 0; } 65} 66 67#autoIframe{ margin-top: -80px; } 68 69/* ===== HEADER PROPIO DEL PORTAL ===== */ 70.pi-header { 71 background: #1B3C53; 72 padding: 1.5rem 2rem; 73 display: flex; 74 align-items: center; 75 justify-content: space-between; 76} 77 78.pi-header-left { 79 display: flex; 80 align-items: center; 81 gap: 1rem; 82} 83 84.pi-header img { height: 50px; } 85 86.pi-header-title { 87 color: white; 88 font-weight: bold; 89 font-size: 1.4rem; 90} 91 92.pi-header-title span { color: #9fc1d6; } 93 94.pi-user-box { 95 display: flex; 96 align-items: center; 97 gap: 1rem; 98 color: #dbe7ee; 99 font-size: 1rem; 100} 101 102.pi-logout-btn { 103 background: transparent; 104 border: 1.5px solid #dbe7ee; 105 color: #dbe7ee; 106 padding: 0.6rem 1.3rem; 107 border-radius: 2rem; 108 font-size: 0.95rem; 109 cursor: pointer; 110} 111 112.pi-logout-btn:hover { background: rgba(255,255,255,0.1); } 113 114.pi-role-badge { 115 font-size: 0.8rem; 116 text-transform: uppercase; 117 letter-spacing: 0.05em; 118 padding: 0.3rem 0.8rem; 119 border-radius: 1rem; 120 background: #456882; 121 color: white; 122} 123 124@media (max-width: 640px) { 125 .pi-header { flex-wrap: wrap; gap: 0.75rem; padding: 1.1rem 1.25rem; } 126 .pi-header-title { font-size: 1.15rem; } 127 .pi-user-box { font-size: 0.85rem; gap: 0.6rem; flex-wrap: wrap; } 128 .pi-logout-btn { padding: 0.45rem 1rem; font-size: 0.85rem; } 129} 130 131/* ===== Selector de idioma (GTranslate) ===== */ 132.gtranslate_wrapper { 133 display: flex; 134 align-items: center; 135 gap: 0.4rem; 136 font-size: 0.85rem; 137} 138.gtranslate_wrapper a { 139 color: #dbe7ee !important; 140 text-decoration: none !important; 141 font-size: 0.85rem !important; 142} 143.gtranslate_wrapper a:hover { color: #fff !important; text-decoration: underline !important; } 144.gtranslate_wrapper select { 145 background: transparent; 146 color: #dbe7ee; 147 border: 1.5px solid #dbe7ee; 148 border-radius: 0.5rem; 149 padding: 0.2rem 0.5rem; 150 font-size: 0.8rem; 151} 152 153/* ===== BURBUJA DE USUARIO ===== */ 154.pi-avatar-wrap { position: relative; } 155 156.pi-avatar-btn { 157 width: 42px; 158 height: 42px; 159 border-radius: 50%; 160 background: #456882; 161 color: white; 162 border: 1.5px solid #dbe7ee; 163 font-weight: 700; 164 font-size: 1.05rem; 165 cursor: pointer; 166 display: flex; 167 align-items: center; 168 justify-content: center; 169 text-transform: uppercase; 170 line-height: 1; 171 padding: 0; 172} 173 174.pi-avatar-btn:hover { background: #2e4a5f; } 175 176.pi-user-dropdown { 177 position: absolute; 178 top: calc(100% + 12px); 179 right: 0; 180 background: white; 181 border: 1px solid #e9ddd0; 182 border-radius: 0.9rem; 183 padding: 1.1rem 1.2rem; 184 min-width: 230px; 185 box-shadow: 0 12px 30px rgba(0,0,0,0.18); 186 text-align: left; 187 z-index: 9999; 188} 189 190.pi-dropdown-email { 191 font-size: 0.85rem; 192 font-weight: 600; 193 color: #111827; 194 word-break: break-all; 195 margin: 0 0 0.6rem 0; 196} 197 198.pi-dropdown-role { margin: 0 0 1rem 0; } 199 200.pi-dropdown-logout { 201 width: 100%; 202 background: transparent; 203 border: 1.5px solid #d1c4b8; 204 color: #456882; 205 padding: 0.55rem 1rem; 206 border-radius: 2rem; 207 font-size: 0.9rem; 208 font-weight: 600; 209 cursor: pointer; 210} 211.pi-dropdown-logout:hover { background: #f3ece4; } 212 213@media (max-width: 640px) {
214 .pi-user-dropdown { right: -0.5rem; } 215} 216 217/* ===== LOGIN ===== */ 218.pi-login-wrap { 219 min-height: 100vh; 220 box-sizing: border-box; 221 display: flex; 222 align-items: center; 223 justify-content: center; 224 background: #456882; 225 padding: 2rem 1rem; 226} 227 228.pi-login-card { 229 background: white; 230 border: 1px solid #e9ddd0; 231 border-radius: 1.25rem; 232 padding: 2.5rem 2rem; 233 width: 380px; 234 max-width: 92vw; 235 text-align: center; 236} 237 238.pi-login-card img { height: 96px; margin-bottom: 1.25rem; } 239 240.pi-login-title { 241 font-size: 1.2rem; 242 font-weight: bold; 243 color: #111827; 244 margin-bottom: 0.4rem; 245} 246 247.pi-login-subtitle { 248 font-size: 0.85rem; 249 color: #6b7280; 250 margin-bottom: 1.5rem; 251} 252 253.pi-field-group { margin-bottom: 1rem; text-align: left; } 254 255.pi-field-label { 256 display: block; 257 font-size: 0.72rem; 258 font-weight: 600; 259 color: #6b7280; 260 letter-spacing: 0.05em; 261 text-transform: uppercase; 262 margin-bottom: 0.35rem; 263} 264 265.pi-input { 266 width: 100%; 267 padding: 0.6rem 0.9rem; 268 border: 1.5px solid #e9ddd0; 269 border-radius: 0.6rem; 270 font-size: 0.9rem; 271 background: #FCF8F3; 272 color: #111827; 273 outline: none; 274 box-sizing: border-box; 275} 276 277.pi-input:focus { border-color: #456882; } 278 279.pi-login-btn { 280 width: 100%; 281 background: #456882; 282 color: white; 283 border: none; 284 padding: 0.85rem 1rem; 285 border-radius: 2rem; 286 font-size: 0.95rem; 287 font-weight: 600; 288 cursor: pointer; 289 margin-top: 0.5rem; 290} 291 292.pi-login-btn:hover { background: #2e4a5f; } 293.pi-login-btn:disabled { opacity: 0.6; cursor: default; } 294 295.pi-login-error { 296 font-size: 0.82rem; 297 color: #b91c1c; 298 margin-top: 1rem; 299 min-height: 1.2em; 300} 301 302.pi-hidden { display: none !important; } 303 304#pi-portal { min-height: 100vh; box-sizing: border-box; } 305 306/* ===== SUBMENU (calendario / repositorio) ===== */ 307.clean-submenu{ 308 display:flex; 309 justify-content:center; 310 gap:2rem; 311 padding:1.5rem 1rem; 312 margin-bottom:0; 313 background-color:#FCF8F3; 314 border-bottom:1px solid #F2F2F2; 315} 316 317.tab{ 318 font-family:'Inter', sans-serif; 319 font-size:0.875rem; 320 text-transform:uppercase; 321 letter-spacing:0.04em; 322 color:#1B3C53; 323 cursor:pointer; 324 position:relative; 325 padding-bottom:0.5rem; 326 background:none; 327 border:none; 328 transition:opacity .3s; 329} 330 331.tab:hover{ opacity:.7; } 332 333.tab::after{ 334 content:""; 335 position:absolute; 336 left:0; 337 bottom:0; 338 width:0; 339 height:2px; 340 background:#1B3C53; 341 transition:width .3s; 342} 343 344.tab.active::after{ width:100%; } 345.tab.active{ font-weight:500; } 346 347.tab-content{ 348 display:none; 349 padding:3rem 1rem; 350 background: #FCF8F3; 351} 352 353.tab-content.active{ display:block; } 354 355.container{ max-width:1200px; margin:0 auto; } 356 357@media(max-width:768px){ 358 .clean-submenu{ 359 display:grid; 360 grid-template-columns:1fr 1fr; 361 gap:8px; 362 padding:.6rem; 363 } 364 .tab{ 365 width:100%; 366 display:flex; 367 align-items:center; 368 justify-content:center; 369 min-height:44px; 370 padding:8px 10px; 371 font-size:.75rem; 372 border-radius:16px; 373 text-transform:none; 374 } 375 .tab::after{ display:none; } 376 .tab.active{ background:#1B3C53; color:#fff; } 377} 378 379.eventos-section, .eventos-section-wrapper { background: #FCF8F3 !important; } 380 381/* ===== BIBLIOTECA / REPOSITORIO ===== */ 382.odf-section { 383 background-color: #FCF8F3; 384 padding: 2rem 1rem 1.5rem 1rem; 385 position: relative; 386} 387 388.odf-container { max-width: 1280px; margin: 0 auto; } 389 390.odf-header { 391 display: flex; 392 align-items: center; 393 justify-content: space-between; 394 margin-bottom: 1.5rem; 395 flex-wrap: wrap; 396 gap: 0.75rem; 397} 398 399.odf-title { font-size: 1.5rem; font-weight: bold; color: #111827; } 400.odf-title span { color: #456882; } 401 402.odf-toolbar { display: flex; align-items: center; gap: 0.75rem; } 403 404.odf-save-badge { 405 font-size: 0.78rem; 406 color: #166534; 407 background: #dcfce7; 408 border-radius: 0.5rem; 409 padding: 0.3rem 0.7rem; 410 opacity: 0; 411 transition: opacity 0.3s; 412 font-weight: 500; 413} 414.odf-save-badge.odf-show { opacity: 1; } 415 416.odf-main-add-btn { 417 display: inline-flex; 418 align-items: center; 419 gap: 0.45rem; 420 font-size: 1rem; 421 font-weight: 600; 422 padding: 0.6rem 1.4rem; 423 background: #456882; 424 color: white; 425 border: none; 426 border-radius: 2rem; 427 cursor: pointer; 428 transition: background 0.15s; 429 white-space: nowrap; 430} 431.odf-main-add-btn:hover { background: #2e4a5f; } 432 433.odf-year-block { margin-bottom: 1.5rem; } 434 435.odf-year-header { 436 display: flex; 437 align-items: center; 438 gap: 0.75rem; 439 margin-bottom: 0.75rem; 440} 441 442.odf-year-pill { 443 background: #456882; 444 color: white; 445 font-size: 0.8rem; 446 font-weight: bold; 447 letter-spacing: 0.06em; 448 padding: 0.3rem 0.9rem; 449 border-radius: 2rem; 450 white-space: nowrap; 451} 452 453.odf-year-line { flex: 1; height: 1px; background: #e5d9cc; } 454 455.odf-table-wrapper { 456 background: white; 457 border-radius: 1rem; 458 overflow: hidden; 459 border: 1px solid #e9ddd0; 460} 461 462.odf-table { width: 100%; border-collapse: collapse; font-size: 0.9rem; table-layout: fixed; } 463.odf-table thead { background: #F6EFE6; } 464 465.odf-table th { 466 text-align: left; 467 padding: 0.75rem 1.25rem; 468 font-size: 0.75rem; 469 font-weight: 600; 470 color: #6b7280; 471 letter-spacing: 0.05em; 472 text-transform: uppercase; 473 vertical-align: middle; 474} 475 476.odf-table td { 477 padding: 0.75rem 1.25rem; 478 border-top: 1px solid #f3ece4; 479 color: #111827; 480 vertical-align: middle; 481 overflow: hidden; 482 text-overflow: ellipsis; 483} 484 485.odf-col-name { width: 32%; } 486.odf-col-date { width: 14%; } 487.odf-col-author { width: 28%; } 488.odf-col-mod { width: 20%; } 489.odf-col-acts { width: 6%; } 490 491.odf-table tbody tr:hover td { background: #fdf9f5; } 492 493.odf-file-link { 494 display: inline-flex; 495 align-items: center; 496 gap: 0.45rem; 497 color: #456882; 498 text-decoration: none; 499 font-weight: 600; 500 font-size: 0.9rem; 501 white-space: nowrap; 502 overflow: hidden; 503 text-overflow: ellipsis; 504 max-width: 100%; 505} 506.odf-file-link:hover { color: #2e4a5f; text-decoration: underline; } 507 508.odf-date-cell { color: #6b7280; font-size: 0.85rem; white-space: nowrap; } 509 510.odf-author-cell { 511 font-size: 0.8rem; 512 color: #6b7280; 513 white-space: nowrap; 514 overflow: hidden; 515 text-overflow: ellipsis; 516} 517 518.odf-author-label { 519 font-size: 0.7rem; 520 color: #9ca3af; 521 text-transform: uppercase; 522 letter-spacing: 0.04em; 523 display: block; 524 margin-bottom: 1px; 525} 526 527.odf-mod-cell { 528 font-size: 0.78rem; 529 color: #9ca3af; 530 white-space: nowrap; 531 overflow: hidden; 532 text-overflow: ellipsis; 533} 534 535.odf-actions-cell { display: flex; gap: 0.2rem; justify-content: flex-end; align-items: center; } 536 537.odf-edit-btn { 538 background: none; border: none; cursor: pointer; color: #9ca3af; 539 padding: 0.3rem; border-radius: 0.4rem; transition: color 0.15s, background 0.15s; 540 font-size: 0.95rem; line-height: 1; 541} 542.odf-edit-btn:hover { color: #456882; background: #e0eaf1; } 543 544.odf-delete-btn { 545 background: none; border: none; cursor: pointer; color: #d1c4b8; 546 padding: 0.3rem; border-radius: 0.4rem; transition: color 0.15s, background 0.15s; 547 font-size: 0.95rem; line-height: 1; 548} 549.odf-delete-btn:hover { color: #b91c1c; background: #fee2e2; } 550 551.odf-empty-row td { text-align: center; padding: 2rem; color: #b0a090; font-size: 0.85rem; } 552.odf-loading { text-align: center; padding: 3rem 2rem; color: #9ca3af; font-size: 0.9rem; } 553 554/* Modales agregar/editar archivo */ 555.odf-overlay { 556 position: fixed; inset: 0; background: rgba(0,0,0,0.4); 557 display: flex; align-items: center; justify-content: center; z-index: 9999; 558} 559.odf-overlay.odf-hidden { display: none; } 560 561.odf-modal { 562 background: #FCF8F3; border-radius: 1rem; padding: 2rem; 563 width: 420px; max-width: 92vw; border: 1px solid #e9ddd0; 564} 565 566.odf-modal-title { font-size: 1.1rem; font-weight: bold; color: #111827; margin-bottom: 1.5rem; } 567.odf-modal-title span { color: #456882; } 568 569.odf-field-group { margin-bottom: 1.1rem; } 570 571.odf-field-label { 572 display: block; font-size: 0.75rem; font-weight: 600; color: #6b7280; 573 letter-spacing: 0.05em; text-transform: uppercase; margin-bottom: 0.4rem; 574} 575.odf-field-label .odf-required { color: #b91c1c; margin-left: 2px; } 576 577.odf-input { 578 width: 100%; padding: 0.6rem 0.9rem; border: 1.5px solid #e9ddd0; border-radius: 0.6rem; 579 font-size: 0.9rem; background: white; color: #111827; outline: none; box-sizing: border-box; 580} 581.odf-input:focus { border-color: #456882; } 582.odf-input.odf-input-error { border-color: #b91c1c; } 583 584.odf-error { font-size: 0.75rem; color: #b91c1c; margin-top: 0.3rem; } 585.odf-error.odf-hidden { display: none; } 586 587.odf-modal-actions { display: flex; justify-content: flex-end; gap: 0.6rem; margin-top: 1.5rem; } 588 589.odf-btn-primary { 590 background: #456882; color: white; border: none; padding: 0.55rem 1.3rem; 591 border-radius: 2rem; font-size: 0.9rem; font-weight: 500; cursor: pointer; 592} 593.odf-btn-primary:hover { background: #2e4a5f; } 594 595.odf-btn-cancel { 596 background: transparent; border: 1.5px solid #d1c4b8; padding: 0.55rem 1.1rem; 597 border-radius: 2rem; font-size: 0.9rem; cursor: pointer; color: #6b7280; 598} 599.odf-btn-cancel:hover { background: #f3ece4; } 600 601@media (max-width: 768px) { 602 .odf-col-author, .odf-col-mod, 603 .odf-table th:nth-child(3), .odf-table th:nth-child(4), 604 .odf-table td:nth-child(3), .odf-table td:nth-child(4) { display: none; } 605 .odf-col-date { width: 25%; } 606 .odf-col-name { width: 65%; } 607} 608 609/* ===== ADMINISTRACIÃN (solo admin) ===== */ 610.pi-admin-msg { font-size: 0.85rem; margin-top: 0.85rem; margin-bottom: 0; min-height: 1.1em; } 611.pi-admin-help { color: #6b7280; font-size: 0.85rem; margin: 0 0 1.1rem 0; } 612.pi-admin-panel { margin-bottom: 1.5rem; } 613 614.pi-admin-form-row { 615 display: flex; 616 align-items: flex-end; 617 gap: 1rem; 618 flex-wrap: wrap; 619 margin-bottom: 0.5rem; 620} 621.pi-admin-form-row .odf-field-group { flex: 0 1 340px; margin-bottom: 0; } 622 623.pi-admin-subtitle { font-size: 1rem; font-weight: 600; color: #111827; margin: 1.85rem 0 0.5rem 0; } 624 625@media (max-width: 640px) { 626 .pi-admin-form-row { flex-direction: column; align-items: stretch; } 627 .pi-admin-form-row .odf-field-group { flex: 1 1 auto; } 628} 629 630/* BUSCADOR */ 631.odf-search-box { position: relative; width: 260px; } 632 633#odf-searchInput { 634 width: 100%; padding: 0.5rem 0.9rem; border-radius: 6px; border: 1.5px solid #e5d9cc; 635 outline: none; font-size: 0.85rem; box-sizing: border-box; background: white; color: #111827; 636} 637#odf-searchInput:focus { border-color: #456882; } 638 639#odf-searchResults { 640 position: absolute; top: 110%; left: 0; width: 100%; background: white; 641 border-radius: 0.5rem; box-shadow: 0 10px 25px rgba(0,0,0,0.15); display: none; 642 z-index: 9999; overflow: hidden; border: 1px solid #e9ddd0; 643} 644#odf-searchResults .odf-result-item { padding: 9px 12px; cursor: pointer; font-size: 0.85rem; border-bottom: 1px solid #f3ece4; } 645#odf-searchResults .odf-result-item:last-child { border-bottom: none; } 646#odf-searchResults .odf-result-item:hover { background: #f3ece4; } 647#odf-searchResults .odf-result-name { font-weight: 600; color: #111827; } 648#odf-searchResults .odf-result-meta { font-size: 0.75rem; color: #9ca3af; margin-top: 2px; } 649#odf-searchResults .odf-no-results { padding: 12px; text-align: center; color: #9ca3af; font-size: 0.83rem; } 650 651</style> 652 653<!-- ============================================================ 654 PANTALLA DE LOGIN (se muestra hasta que Firebase Auth confirma sesión) 655============================================================ --> 656<div id="pi-login-screen" class="pi-login-wrap">
657 <div class="pi-login-card"> 658 <img src="https://d1yei2z3i6k35z.cloudfront.net/15882402/6a2af06f0122f4.91897886_fondoblanco.jpg" alt="OPANAL" /> 659 <p class="pi-login-title">Portal Interno OPANAL</p> 660 <p class="pi-login-subtitle">Ingresá con tu cuenta para acceder.</p> 661 662 <div class="pi-field-group"> 663 <label class="pi-field-label">Correo electrónico</label> 664 <input class="pi-input" type="email" id="pi-login-email" placeholder="[email protected]" autocomplete="username" /> 665 </div> 666 <div class="pi-field-group"> 667 <label class="pi-field-label">Contraseña</label> 668 <input class="pi-input" type="password" id="pi-login-password" placeholder="â¢â¢â¢â¢â¢â¢â¢â¢" autocomplete="current-password" /> 669 </div> 670 671 <button class="pi-login-btn" id="pi-login-btn" onclick="piLogin()">Ingresar</button> 672 <p class="pi-login-error pi-hidden" id="pi-login-error">Mail o contraseña incorrectos.</p> 673 </div> 674</div> 675 676<!-- ============================================================ 677 PORTAL (oculto hasta login exitoso) 678============================================================ --> 679<section id="pi-portal" style="background:#FCF8F3; display:none;"> 680 681 <div class="pi-header"> 682 <div class="pi-header-left"> 683 <img src="https://d1yei2z3i6k35z.cloudfront.net/15882402/6a2af06f0122f4.91897886_fondoblanco.jpg" alt="OPANAL" /> 684 <span class="pi-header-title">Portal <span>Interno OPANAL</span></span> 685 </div> 686 <div class="pi-user-box"> 687 <div class="gtranslate_wrapper"></div> 688 <div class="pi-avatar-wrap" id="pi-avatar-wrap"> 689 <button class="pi-avatar-btn notranslate" id="pi-avatar-btn" onclick="piToggleUserMenu()" title="Mi cuenta" translate="no">?</button> 690 <div class="pi-user-dropdown pi-hidden" id="pi-user-dropdown"> 691 <p class="pi-dropdown-email" id="pi-user-email"></p> 692 <p class="pi-dropdown-role"><span class="pi-role-badge" id="pi-role-badge">Miembro</span></p> 693 <button class="pi-dropdown-logout" onclick="piLogout()">Cerrar sesión</button> 694 </div> 695 </div> 696 </div> 697 </div> 698 699 <nav class="clean-submenu"> 700 <button class="tab active" onclick="showTab(0)">Calendario de reuniones</button> 701 <button class="tab" onclick="showTab(1)">Repositorio Institucional</button> 702 <button class="tab pi-hidden" id="pi-admin-tab-btn" onclick="showTab(2)">Administración</button> 703 </nav> 704 705 <!-- CALENDARIO --> 706 <div class="tab-content active"> 707 <div class="container"> 708 <div class="full-width"> 709 <iframe 710 src="https://calendar.google.com/calendar/embed?src=b3BhbmFsd2ViQGdtYWlsLmNvbQ" 711 style="border:0; width:100%; height:1000px;" 712 frameborder="0" 713 scrolling="no"> 714 </iframe> 715 </div> 716 </div> 717 </div> 718 719 <!-- BIBLIOTECA / REPOSITORIO --> 720 <div class="tab-content"> 721 <div class="container"> 722 <div style="background:#F6EFE6; width:100%; overflow:hidden;"> 723 <div class="odf-section"> 724 <div class="odf-container"> 725 726 <div class="odf-header"> 727 <h2 class="odf-title">Archivos <span>OneDrive</span></h2> 728 729 <div class="odf-search-box"> 730 <input id="odf-searchInput" placeholder="ð Buscar archivo..." autocomplete="off" /> 731 <div id="odf-searchResults"></div> 732 </div> 733 734 <div class="odf-toolbar"> 735 <span id="odf-save-badge" class="odf-save-badge">â Guardado</span> 736 <button class="odf-main-add-btn pi-hidden" id="odf-add-btn" onclick="odfOpenModal()">+ Agregar archivo</button> 737 </div> 738 </div> 739 740 <div id="odf-app"> 741 <div class="odf-loading">Cargando archivos...</div> 742 </div> 743 744 </div> 745 </div> 746 </div> 747 748 <!-- MODAL: AGREGAR / EDITAR ARCHIVO --> 749 <div class="odf-overlay odf-hidden" id="odf-overlay"> 750 <div class="odf-modal"> 751 <p class="odf-modal-title" id="odf-modal-title">Agregar archivo</p> 752 753 <div class="odf-field-group"> 754 <label class="odf-field-label">Nombre del archivo</label> 755 <input class="odf-input" type="text" id="odf-input-name" placeholder="Ej: Informe trimestral Q1" /> 756 <p class="odf-error odf-hidden" id="odf-err-name">
756Ingresá un nombre</p> 757 </div> 758 759 <div class="odf-field-group"> 760 <label class="odf-field-label">Link de OneDrive <span class="odf-required">*</span></label> 761 <input class="odf-input" type="url" id="odf-input-link" placeholder="https://onedrive.live.com/..." /> 762 <p class="odf-error odf-hidden" id="odf-err-link">El link es obligatorio y debe comenzar con http</p> 763 </div> 764 765 <div class="odf-field-group"> 766 <label class="odf-field-label">Fecha de subida <span class="odf-required">*</span></label> 767 <input class="odf-input" type="date" id="odf-input-date" /> 768 <p class="odf-error odf-hidden" id="odf-err-date">La fecha es obligatoria</p> 769 </div> 770 771 <div class="odf-modal-actions"> 772 <button class="odf-btn-cancel" onclick="odfCloseModal()">Cancelar</button> 773 <button class="odf-btn-primary" id="odf-btn-save" onclick="odfSaveFile()">Guardar</button> 774 </div> 775 </div> 776 </div> 777 778 </div> 779 </div> 780 781 <!-- ADMINISTRACIÃN (solo admin) --> 782 <div class="tab-content"> 783 <div class="container"> 784 785 <!-- Gestión de usuarios --> 786 <div style="background:#F6EFE6; width:100%; overflow:hidden;" class="pi-admin-panel"> 787 <div class="odf-section"> 788 <div class="odf-container"> 789 <div class="odf-header"> 790 <h2 class="odf-title">Gestión de <span>usuarios</span></h2> 791 </div> 792 <p class="pi-admin-help">Ingrese el correo electrónico de la persona. Si aún no cuenta con una cuenta, el sistema la creará automáticamente y le enviará un correo electrónico para que establezca su contraseña. Si ya cuenta con una cuenta registrada, se le reenviará ese mismo correo de acceso.</p> 793 <div class="pi-admin-form-row"> 794 <div class="odf-field-group"> 795 <label class="odf-field-label">Correo electrónico</label> 796 <input class="odf-input" type="email" id="pi-admin-user-email" placeholder="[email protected]" /> 797 </div> 798 <button class="odf-btn-primary" id="pi-admin-user-btn" onclick="piAdminAddUser()">Agregar y enviar acceso</button> 799 </div> 800 <p class="pi-admin-msg" id="pi-admin-user-msg"></p> 801 802 <p class="pi-admin-subtitle">Usuarios registrados</p> 803 <p class="pi-admin-help" style="margin-bottom:0.75rem;">Esta lista incluye únicamente a las personas agregadas o gestionadas desde este panel. Las cuentas creadas previamente por otro medio no se mostrarán aquÃ.</p> 804 <div id="pi-admin-users-list"><div class="odf-loading">Cargando usuarios...</div></div> 805 </div> 806 </div> 807 </div> 808 809 <!-- AuditorÃa de archivos eliminados --> 810 <div style="background:#F6EFE6; width:100%; overflow:hidden;" class="pi-admin-panel"> 811 <div class="odf-section"> 812 <div class="odf-container"> 813 <div class="odf-header"> 814 <h2 class="odf-title">AuditorÃa de <span>archivos eliminados</span></h2> 815 <div class="odf-toolbar"> 816 <button class="odf-main-add-btn" onclick="piOpenTrash()">ðï¸ <span class="notranslate" id="pi-trash-btn-label" translate="no">Ver papelera</span></button> 817 </div> 818 </div> 819 <p class="pi-admin-help" style="margin-bottom:0;">En esta sección se muestran los archivos eliminados del Repositorio Institucional, incluyendo el usuario responsable y la fecha de eliminación, en caso de que sea necesario restaurar alguno.</p> 820 </div> 821 </div> 822 </div> 823 824 </div> 825 </div> 826 827 <!-- MODAL: PAPELERA --> 828 <div class="odf-overlay odf-hidden" id="pi-trash-overlay"> 829 <div class="odf-modal" style="width:640px;"> 830 <p class="odf-modal-title">Historial de <span>archivos eliminados</span></p> 831 <div id="pi-trash-list"></div> 832 <div class="odf-modal-actions"> 833 <button class="odf-btn-cancel" onclick="piCloseTrash()">Cerrar</button> 834 </div> 835 </div> 836 </div> 837 838</section> 839
840<script> 841 842(function debleedSystemeWrapper() { 843 function debleed(el) { 844 var cur = el, hops = 0; 845 while (cur && hops < 8) { 846 if (cur.tagName === 'BODY') break; 847 if ( 848 cur.tagName === 'SECTION' || 849 (cur.id && (cur.id.indexOf('row-') === 0 || cur.id.indexOf('section-') === 0)) 850 ) { 851 cur.style.padding = '0'; 852 cur.style.margin = '0'; 853 } 854 cur = cur.parentElement; 855 hops++; 856 } 857 } 858 function run() { 859 debleed(document.getElementById('pi-login-screen')); 860 debleed(document.getElementById('pi-portal')); 861 } 862 run(); 863 if (document.readyState !== 'complete') { 864 document.addEventListener('DOMContentLoaded', run); 865 window.addEventListener('load', run); 866 } 867})(); 868 869function showTab(index){ 870 const tabs = document.querySelectorAll('.tab'); 871 const contents = document.querySelectorAll('.tab-content'); 872 tabs.forEach(tab => tab.classList.remove('active')); 873 contents.forEach(content => content.classList.remove('active')); 874 tabs[index].classList.add('active'); 875 contents[index].classList.add('active'); 876} 877 878/* ================= FIREBASE ================= */ 879firebase.initializeApp({ 880 apiKey: "AIzaSyArthFm16e3djN0xqhpF0ci6LCccCGgLBE", 881 authDomain: "opanal.firebaseapp.com", 882 databaseURL: "https://opanal-default-rtdb.firebaseio.com", 883 projectId: "opanal", 884 storageBucket: "opanal.firebasestorage.app", 885 messagingSenderId: "862238375033", 886 appId: "1:862238375033:web:d8d2d966d15083317268a8" 887}); 888 889var auth = firebase.auth(); 890var db = firebase.database(); 891var ref = db.ref('onedrive_files'); 892var trashRef = db.ref('onedrive_files_trash'); 893var usersRef = db.ref('portal_users'); 894 895var isAdmin = false; 896var odfBound = false; 897var piUsersBound = false; 898 899/* ---- Login ---- */ 900window.piLogin = function() { 901 var email = document.getElementById('pi-login-email').value.trim(); 902 var pass = document.getElementById('pi-login-password').value; 903 var btn = document.getElementById('pi-login-btn'); 904 var err = document.getElementById('pi-login-error'); 905 906 err.classList.add('pi-hidden'); 907 908 if (!email || !pass) { 909 err.textContent = 'Completá mail y contraseña.'; 910 err.classList.remove('pi-hidden'); 911 return; 912 } 913 914 btn.disabled = true; 915 btn.textContent = 'Ingresando...'; 916 917 auth.signInWithEmailAndPassword(email, pass) 918 .catch(function(error) { 919 err.textContent = 'Mail o contraseña incorrectos.'; 920 err.classList.remove('pi-hidden'); 921 }) 922 .finally(function() { 923 btn.disabled = false; 924 btn.textContent = 'Ingresar'; 925 }); 926}; 927 928// Enter para enviar el login 929['pi-login-email', 'pi-login-password'].forEach(function(id) { 930 document.getElementById(id).addEventListener('keydown', function(e) { 931 if (e.key === 'Enter') window.piLogin(); 932 }); 933}); 934 935window.piLogout = function() { 936 auth.signOut(); 937}; 938 939/* ---- Burbuja de usuario (mail + rol + cerrar sesión) ---- */ 940window.piToggleUserMenu = function() { 941 var dd = document.getElementById('pi-user-dropdown'); 942 if (dd) dd.classList.toggle('pi-hidden'); 943}; 944 945document.addEventListener('click', function(e) { 946 var wrap = document.getElementById('pi-avatar-wrap'); 947 var dd = document.getElementById('pi-user-dropdown'); 948 if (!wrap || !dd || dd.classList.contains('pi-hidden')) return; 949 if (!wrap.contains(e.target)) dd.classList.add('pi-hidden'); 950}, true); 951 952window.addEventListener('blur', function() { 953 setTimeout(function() { 954 if (document.activeElement && document.activeElement.tagName === 'IFRAME') { 955 var dd = document.getElementById('pi-user-dropdown'); 956 if (dd) dd.classList.add('pi-hidden'); 957 } 958 }, 0); 959}); 960 961/* ---- Estado de sesión ---- */ 962auth.onAuthStateChanged(function(user) { 963 var loginScreen = document.getElementById('pi-login-screen'); 964 var portal = document.getElementById('pi-portal'); 965 var dd = document.getElementById('pi-user-dropdown'); 966 967 if (!user) { 968 isAdmin = false; 969 loginScreen.classList.remove('pi-hidden'); 970 loginScreen.style.display = 'flex'; 971 portal.style.display = 'none'; 972 if (dd) dd.classList.add('pi-hidden'); 973 return; 974 } 975 976 loginScreen.style.display = 'none'; 977 portal.style.display = 'block'; 978 document.getElementById('pi-user-email').textContent = user.email; 979 var avatarBtn = document.getElementById('pi-avatar-btn'); 980 if (avatarBtn) avatarBtn.textContent = (user.email || '?').trim().charAt(0).toUpperCase(); 981 982 db.ref('admins/' + user.uid).once('value').then(function(snap) { 983 isAdmin = snap.val() === true; 984 document.getElementById('pi-role-badge').textContent = isAdmin ? 'Administrador' : 'Miembro'; 985 document.getElementById('odf-add-btn').classList.toggle('pi-hidden', !isAdmin); 986 document.getElementById('pi-admin-tab-btn').classList.toggle('pi-hidden', !isAdmin); 987 renderRepositorio(); // re-renderizar filas para mostrar/ocultar acciones según rol 988 if (isAdmin && !piUsersBound) { 989 piUsersBound = true; 990 bindPortalUsers(); 991 } 992 }); 993 994 if (!odfBound) { 995 odfBound = true; 996 bindRepositorio(); 997 } 998}); 999 1000/* ================= REPOSITORIO ================= */ 1001window._odfData = {}; 1002var data = window._odfData; 1003var years = []; 1004var saving = false;
1005var editTarget = null; 1006 1007function bindRepositorio() { 1008 ref.on('value', function(snapshot) { 1009 var val = snapshot.val(); 1010 Object.keys(data).forEach(function(k) { delete data[k]; }); 1011 if (val) { 1012 var incoming = val.data || {}; 1013 Object.keys(incoming).forEach(function(k) { data[k] = incoming[k]; }); 1014 years = val.years || []; 1015 if (!Array.isArray(years)) years = Object.values(years).map(Number); 1016 Object.keys(data).forEach(function(y) { 1017 if (data[y] && !Array.isArray(data[y])) data[y] = Object.values(data[y]); 1018 if (!data[y]) data[y] = []; 1019 }); 1020 } 1021 initDefaultYears(); 1022 renderRepositorio(); 1023 }, function(err) { 1024 console.error('Firebase error:', err); 1025 initDefaultYears(); 1026 renderRepositorio(); 1027 }); 1028 1029 // Buscador 1030 var searchInput = document.getElementById('odf-searchInput'); 1031 var searchResults = document.getElementById('odf-searchResults'); 1032 1033 searchInput.addEventListener('input', function() { 1034 var q = this.value.toLowerCase().trim(); 1035 if (!q) { 1036 searchResults.style.display = 'none'; 1037 searchResults.innerHTML = ''; 1038 return; 1039 } 1040 var results = []; 1041 Object.keys(data).forEach(function(year) { 1042 (data[year] || []).forEach(function(file) { 1043 if (!file) return; 1044 if ( 1045 (file.name && file.name.toLowerCase().includes(q)) || 1046 (file.date && file.date.includes(q)) || 1047 (file.createdBy && file.createdBy.toLowerCase().includes(q)) || 1048 year.toString().includes(q) 1049 ) { 1050 results.push({ year: year, name: file.name, date: file.date, link: file.link, createdBy: file.createdBy }); 1051 } 1052 }); 1053 }); 1054 1055 searchResults.innerHTML = ''; 1056 if (results.length === 0) { 1057 searchResults.innerHTML = '<div class="odf-no-results">Sin resultados</div>'; 1058 } else { 1059 results.slice(0, 6).forEach(function(f) { 1060 var div = document.createElement('div'); 1061 div.className = 'odf-result-item'; 1062 div.innerHTML = 1063 '<div class="odf-result-name">ð ' + escHtml(f.name || '(sin nombre)') + '</div>' + 1064 '<div class="odf-result-meta">' + fmt(f.date) + ' · ' + f.year + (f.createdBy ? ' · ' + escHtml(shortUser(f.createdBy)) : '') + '</div>'; 1065 div.addEventListener('click', function() { 1066 window.open(f.link, '_blank'); 1067 searchResults.style.display = 'none'; 1068 searchInput.value = ''; 1069 }); 1070 searchResults.appendChild(div); 1071 }); 1072 } 1073 searchResults.style.display = 'block'; 1074 }); 1075 1076 document.addEventListener('click', function(e) { 1077 if (!searchInput.contains(e.target) && !searchResults.contains(e.target)) { 1078 searchResults.style.display = 'none'; 1079 } 1080 }); 1081 1082 document.getElementById('odf-overlay').addEventListener('click', function(e) { 1083 if (e.target === this) odfCloseModal(); 1084 }); 1085} 1086 1087function initDefaultYears() { 1088 if (years.length === 0) { 1089 var cur = new Date().getFullYear(); 1090 years = [cur, cur - 1, cur - 2]; 1091 years.forEach(function(y) { if (!data[y]) data[y] = []; }); 1092 } 1093} 1094 1095function saveData(callback) { 1096 if (saving) return; 1097 saving = true; 1098 var btn = document.getElementById('odf-btn-save'); 1099 if (btn) { btn.textContent = 'Guardando...'; btn.disabled = true; } 1100 1101 ref.set({ data: data, years: years }, function(err) { 1102 saving = false; 1103 if (btn) { btn.textContent = 'Guardar'; btn.disabled = false; } 1104 if (!err) { 1105 var badge = document.getElementById('odf-save-badge'); 1106 badge.classList.add('odf-show'); 1107 setTimeout(function() { badge.classList.remove('odf-show'); }, 2000); 1108 if (callback) callback(); 1109 } else { 1110 alert('No tenés permiso para guardar, o hubo un error de conexión.'); 1111 console.error(err); 1112 } 1113 }); 1114} 1115 1116function fmt(dateStr) { 1117 var p = dateStr.split('-'); 1118 return p[2] + '/' + p[1] + '/' + p[0]; 1119} 1120 1121function escHtml(str) { 1122 if (!str) return ''; 1123 return str.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"'); 1124} 1125 1126function shortUser(u) { 1127 if (!u) return 'â'; 1128 if (u.indexOf('@') > -1 && u.length > 22) { 1129 var parts = u.split('@'); 1130 return parts[0] + '@' + parts[1].split('.')[0]; 1131 } 1132 return u.length > 24 ? u.substring(0, 22) + 'â¦' : u; 1133} 1134 1135function renderRepositorio() { 1136 var app = document.getElementById('odf-app'); 1137 if (!app) return; 1138 var sorted = years.slice().sort(function(a,b){ return b - a; }) 1139 .filter(function(year){ return data[year] && data[year].length > 0; }); 1140 var html = ''; 1141 1142 if (sorted.length === 0) { 1143 app.innerHTML = '<p style="text-align:center; color:#6b7280; padding:2rem 0;">TodavÃa no hay archivos cargados.</p>'; 1144 return; 1145 } 1146 1147 sorted.forEach(function(year) { 1148 var rows = data[year] || []; 1149 var rowsHtml = ''; 1150 1151 if (rows.length === 0) { 1152 rowsHtml = '<tr class="odf-empty-row"><td colspan="5">Sin archivos cargados para este año</td></tr>'; 1153 } else { 1154 rows.forEach(function(f, i) { 1155 if (!f) return; 1156 1157 var authorHtml = 1158 '<td class="odf-author-cell">' + 1159 '<span class="odf-author-label">Subido por</span>' + 1160 escHtml(shortUser(f.createdBy)) + 1161 '</td>'; 1162 1163 var modHtml = '<td class="odf-mod-cell">'; 1164 if (f.modifiedBy) { 1165 modHtml += '<span class="odf-author-label">Modificado por</span>' + escHtml(shortUser(f.modifiedBy)); 1166 } else { 1167 modHtml += '<span style="color:#e5d9cc;">â</span>'; 1168 } 1169 modHtml += '</td>'; 1170 1171 var actionsHtml = isAdmin 1172 ? ('<div class="odf-actions-cell">' + 1173 '<button class="odf-edit-btn" onclick="odfEditFile
1173(' + year + ',' + i + ')" title="Editar">âï¸</button>' + 1174 '<button class="odf-delete-btn" onclick="odfDeleteFile(' + year + ',' + i + ')" title="Eliminar">â</button>' + 1175 '</div>') 1176 : ''; 1177 1178 rowsHtml += 1179 '<tr>' + 1180 '<td class="odf-col-name"><a class="odf-file-link" href="' + escHtml(f.link) + '" target="_blank" rel="noopener">📄 ' + escHtml(f.name || '(sin nombre)') + '</a></td>' + 1181 '<td class="odf-col-date odf-date-cell">' + fmt(f.date) + '</td>' + 1182 authorHtml + 1183 modHtml + 1184 '<td class="odf-col-acts">' + actionsHtml + '</td>' + 1185 '</tr>'; 1186 }); 1187 } 1188 1189 html += 1190 '<div class="odf-year-block">' + 1191 '<div class="odf-year-header">' + 1192 '<span class="odf-year-pill">' + year + '</span>' + 1193 '<div class="odf-year-line"></div>' + 1194 '</div>' + 1195 '<div class="odf-table-wrapper">' + 1196 '<table class="odf-table">' + 1197 '<thead><tr>' + 1198 '<th class="odf-col-name">Nombre de archivo</th>' + 1199 '<th class="odf-col-date">Fecha</th>' + 1200 '<th class="odf-col-author">Subido por</th>' + 1201 '<th class="odf-col-mod">Modificado por</th>' + 1202 '<th class="odf-col-acts"></th>' + 1203 '</tr></thead>' + 1204 '<tbody>' + rowsHtml + '</tbody>' + 1205 '</table>' + 1206 '</div>' + 1207 '</div>'; 1208 }); 1209 1210 app.innerHTML = html; 1211} 1212 1213window.odfOpenModal = function() { 1214 if (!isAdmin) return; 1215 editTarget = null; 1216 document.getElementById('odf-modal-title').textContent = 'Agregar archivo'; 1217 document.getElementById('odf-input-name').value = ''; 1218 document.getElementById('odf-input-link').value = ''; 1219 document.getElementById('odf-input-date').value = new Date().toISOString().split('T')[0]; 1220 clearErrors(); 1221 document.getElementById('odf-overlay').classList.remove('odf-hidden'); 1222}; 1223 1224window.odfEditFile = function(year, idx) { 1225 if (!isAdmin) return; 1226 var f = data[year] && data[year][idx]; 1227 if (!f) return; 1228 1229 editTarget = { year: year, idx: idx }; 1230 document.getElementById('odf-modal-title').textContent = 'Editar archivo'; 1231 document.getElementById('odf-input-name').value = f.name || ''; 1232 document.getElementById('odf-input-link').value = f.link || ''; 1233 document.getElementById('odf-input-date').value = f.date || ''; 1234 clearErrors(); 1235 document.getElementById('odf-overlay').classList.remove('odf-hidden'); 1236}; 1237 1238window.odfCloseModal = function() { 1239 document.getElementById('odf-overlay').classList.add('odf-hidden'); 1240}; 1241 1242function clearErrors() { 1243 ['odf-err-name','odf-err-link','odf-err-date'].forEach(function(id) { 1244 document.getElementById(id).classList.add('odf-hidden'); 1245 }); 1246 ['odf-input-name','odf-input-link','odf-input-date'].forEach(function(id) { 1247 document.getElementById(id).classList.remove('odf-input-error'); 1248 }); 1249} 1250 1251window.odfSaveFile = function() { 1252 if (!isAdmin) return; 1253 var name = document.getElementById('odf-input-name').value.trim(); 1254 var link = document.getElementById('odf-input-link').value.trim(); 1255 var date = document.getElementById('odf-input-date').value; 1256 var ok = true; 1257 1258 clearErrors(); 1259 1260 if (!link || !link.startsWith('http')) { 1261 document.getElementById('odf-err-link').classList.remove('odf-hidden'); 1262 document.getElementById('odf-input-link').classList.add('odf-input-error'); 1263 ok = false; 1264 } 1265 if (!date) { 1266 document.getElementById('odf-err-date').classList.remove('odf-hidden'); 1267 document.getElementById('odf-input-date').classList.add('odf-input-error'); 1268 ok = false; 1269 } 1270 if (!ok) return; 1271 1272 var currentUser = auth.currentUser ? auth.currentUser.email : 'admin'; 1273 var fileYear = parseInt(date.split('-')[0]); 1274 if (!data[fileYear]) data[fileYear] = []; 1275 if (years.indexOf(fileYear) === -1) years.push(fileYear); 1276 1277 if (editTarget !== null) { 1278 var oldYear = parseInt(editTarget.year); 1279 var oldIdx = editTarget.idx; 1280 var oldFile = data[oldYear][oldIdx] || {}; 1281 var updatedFile = { 1282 name: name, 1283 date: date, 1284 link: link, 1285 createdBy: oldFile.createdBy || currentUser, 1286 createdAt: oldFile.createdAt || '', 1287 modifiedBy: currentUser, 1288 modifiedAt: new Date().toISOString() 1289 }; 1290 1291 if (oldYear === fileYear) { 1292 data[fileYear][oldIdx] = updatedFile; 1293 } else { 1294 data[oldYear].splice(oldIdx, 1); 1295 data[fileYear].push(updatedFile); 1296 } 1297 } else { 1298 data[fileYear].push({ 1299 name: name, 1300 date: date, 1301 link: link, 1302 createdBy: currentUser, 1303 createdAt: new Date().toISOString(), 1304 modifiedBy: null, 1305 modifiedAt: null 1306 }); 1307 } 1308 1309 saveData(function() { odfCloseModal(); }); 1310}; 1311 1312window.odfDeleteFile = function(year, idx) { 1313 if (!isAdmin) return; 1314 if (!confirm('¿Eliminar este archivo?')) return; 1315 var removed = data[year][idx]; 1316 data[year].splice(idx, 1); 1317 saveData(function() { 1318 if (removed) { 1319 trashRef.push({ 1320 year: year, 1321 file: removed, 1322 deletedBy: auth.currentUser ? auth.currentUser.email : 'admin', 1323 deletedAt: new Date().toISOString() 1324 }); 1325 } 1326 }); 1327}; 1328 1329/* ================= PAPELERA / AUDITORÃA ================= */ 1330var trashEntries = {}; 1331 1332/* ===== Textos propios que no deben quedar en manos de la traducción automática ===== */ 1333function piCurrentLang() { 1334 return (document.documentElement.lang === 'en') ? 'en' : 'es'; 1335} 1336function piApplyLangOverrides() { 1337 var lang = piCurrentLang();
1338 var trashLbl = document.getElementById('pi-trash-btn-label'); 1339 if (trashLbl) trashLbl.textContent = (lang === 'en') ? 'View Recycle Bin' : 'Ver papelera'; 1340} 1341piApplyLangOverrides(); 1342new MutationObserver(piApplyLangOverrides).observe(document.documentElement, { attributes: true, attributeFilter: ['lang', 'class'] }); 1343 1344function fmtDateTime(iso) { 1345 if (!iso) return 'â'; 1346 var d = new Date(iso); 1347 if (isNaN(d.getTime())) return iso; 1348 return d.toLocaleDateString('es-AR') + ' ' + d.toLocaleTimeString('es-AR', { hour: '2-digit', minute: '2-digit' }); 1349} 1350 1351window.piOpenTrash = function() { 1352 if (!isAdmin) return; 1353 document.getElementById('pi-trash-overlay').classList.remove('odf-hidden'); 1354 piLoadTrash(); 1355}; 1356 1357window.piCloseTrash = function() { 1358 document.getElementById('pi-trash-overlay').classList.add('odf-hidden'); 1359}; 1360 1361document.getElementById('pi-trash-overlay').addEventListener('click', function(e) { 1362 if (e.target === this) window.piCloseTrash(); 1363}); 1364 1365function piLoadTrash() { 1366 var list = document.getElementById('pi-trash-list'); 1367 list.innerHTML = '<div class="odf-loading">Cargando...</div>'; 1368 trashRef.once('value').then(function(snap) { 1369 var val = snap.val() || {}; 1370 var entries = Object.keys(val).map(function(k) { var e = val[k]; e._key = k; return e; }); 1371 entries.sort(function(a, b) { return (b.deletedAt || '').localeCompare(a.deletedAt || ''); }); 1372 trashEntries = {}; 1373 entries.forEach(function(e) { trashEntries[e._key] = e; }); 1374 renderTrashList(entries); 1375 }, function(err) { 1376 list.innerHTML = '<p style="text-align:center;color:#b91c1c;padding:1.5rem 0;">No fue posible cargar la información de la papelera. Intente nuevamente más tarde.</p>'; 1377 console.error(err); 1378 }); 1379} 1380 1381function renderTrashList(entries) { 1382 var list = document.getElementById('pi-trash-list'); 1383 if (entries.length === 0) { 1384 list.innerHTML = '<p style="text-align:center;color:#6b7280;padding:1.5rem 0;">La papelera se encuentra vacÃa. No hay archivos eliminados registrados.</p>'; 1385 return; 1386 } 1387 var html = 1388 '<div class="odf-table-wrapper">' + 1389 '<table class="odf-table">' + 1390 '<thead><tr>' + 1391 '<th class="odf-col-name">Nombre del archivo</th>' + 1392 '<th class="odf-col-date">Año</th>' + 1393 '<th class="odf-col-author">Usuario responsable</th>' + 1394 '<th class="odf-col-mod">Fecha de eliminación</th>' + 1395 '<th class="odf-col-acts"></th>' + 1396 '</tr></thead><tbody>'; 1397 entries.forEach(function(e) { 1398 var f = e.file || {}; 1399 html += 1400 '<tr>' + 1401 '<td class="odf-col-name">' + escHtml(f.name || '(sin nombre)') + '</td>' + 1402 '<td class="odf-col-date odf-date-cell">' + e.year + '</td>' + 1403 '<td class="odf-author-cell">' + escHtml(shortUser(e.deletedBy)) + '</td>' + 1404 '<td class="odf-mod-cell">' + fmtDateTime(e.deletedAt) + '</td>' + 1405 '<td class="odf-col-acts">' + 1406 '<button class="odf-btn-primary" style="padding:0.35rem 0.9rem;font-size:0.8rem;" onclick="piRestoreTrashItem(\'' + e._key + '\')">Restaurar</button>' + 1407 '</td>' + 1408 '</tr>'; 1409 }); 1410 html += '</tbody></table></div>'; 1411 list.innerHTML = html; 1412} 1413 1414window.piRestoreTrashItem = function(key) { 1415 if (!isAdmin) return; 1416 var e = trashEntries[key]; 1417 if (!e) return; 1418 var y = parseInt(e.year); 1419 if (!data[y]) data[y] = []; 1420 if (years.indexOf(y) === -1) years.push(y); 1421 data[y].push(e.file); 1422 saveData(function() { 1423 trashRef.child(key).remove().then(function() { piLoadTrash(); }); 1424 }); 1425}; 1426 1427/* ================= GESTIÃN DE USUARIOS ================= */ 1428function piTempPassword() { 1429 var arr = new Uint8Array(24); 1430 crypto.getRandomValues(arr); 1431 return Array.prototype.map.call(arr, function(b) { return b.toString(36); }).join('').slice(0, 24) + 'Aa1!'; 1432} 1433 1434function piActionLabel(action) { 1435 if (action === 'created') return 'Cuenta creada'; 1436 if (action === 'reset_resent') return 'Acceso reenviado'; 1437 return 'Sin registro'; 1438} 1439 1440function bindPortalUsers() { 1441 usersRef.on('value', function(snapshot) { 1442 var val = snapshot.val() || {}; 1443 var list = Object.keys(val).map(function(k) { var u = val[k]; u._key = k; return u; }); 1444 list.sort(function(a, b) { return (b.createdAt || '').localeCompare(a.createdAt || ''); }); 1445 renderPortalUsers(list); 1446 }, function(err) {
1447 var el = document.getElementById('pi-admin-users-list'); 1448 if (el) el.innerHTML = '<p style="text-align:center;color:#b91c1c;padding:1rem 0;">No fue posible cargar el listado de usuarios.</p>'; 1449 console.error(err); 1450 }); 1451} 1452 1453function renderPortalUsers(list) { 1454 var el = document.getElementById('pi-admin-users-list'); 1455 if (!el) return; 1456 if (list.length === 0) { 1457 el.innerHTML = '<p style="text-align:center;color:#6b7280;padding:1rem 0;">TodavÃa no se registraron usuarios desde este panel.</p>'; 1458 return; 1459 } 1460 var html = 1461 '<div class="odf-table-wrapper">' + 1462 '<table class="odf-table">' + 1463 '<thead><tr>' + 1464 '<th class="odf-col-name">Correo electrónico</th>' + 1465 '<th class="odf-col-date">Fecha de alta</th>' + 1466 '<th class="odf-col-mod">Ãltima acción</th>' + 1467 '</tr></thead><tbody>'; 1468 list.forEach(function(u) { 1469 html += 1470 '<tr>' + 1471 '<td class="odf-col-name">' + escHtml(u.email || 'â') + '</td>' + 1472 '<td class="odf-col-date odf-date-cell">' + fmtDateTime(u.createdAt) + '</td>' + 1473 '<td class="odf-mod-cell">' + escHtml(piActionLabel(u.lastAction)) + ' · ' + fmtDateTime(u.lastActionAt) + '</td>' + 1474 '</tr>'; 1475 }); 1476 html += '</tbody></table></div>'; 1477 el.innerHTML = html; 1478} 1479 1480function piTrackExistingUser(email, nowIso) { 1481 return usersRef.orderByChild('email').equalTo(email).once('value').then(function(snap) { 1482 var val = snap.val(); 1483 if (val) { 1484 var key = Object.keys(val)[0]; 1485 return usersRef.child(key).update({ lastAction: 'reset_resent', lastActionAt: nowIso }); 1486 } 1487 var fallbackKey = email.replace(/[.#$\[\]\/]/g, '_'); 1488 return usersRef.child(fallbackKey).set({ 1489 email: email, 1490 createdAt: nowIso, 1491 lastAction: 'reset_resent', 1492 lastActionAt: nowIso 1493 }); 1494 }); 1495} 1496 1497window.piAdminAddUser = function() { 1498 if (!isAdmin) return; 1499 var emailInput = document.getElementById('pi-admin-user-email'); 1500 var msg = document.getElementById('pi-admin-user-msg'); 1501 var btn = document.getElementById('pi-admin-user-btn'); 1502 var email = emailInput.value.trim(); 1503 var nowIso = new Date().toISOString(); 1504 1505 msg.textContent = ''; 1506 1507 if (!email || email.indexOf('@') === -1) { 1508 msg.textContent = 'Ingrese un correo electrónico válido.'; 1509 msg.style.color = '#b91c1c'; 1510 return; 1511 } 1512 1513 btn.disabled = true; 1514 btn.textContent = 'Procesando...'; 1515 1516 var secondaryApp = firebase.apps.some(function(a) { return a.name === 'Secondary'; }) 1517 ? firebase.app('Secondary') 1518 : firebase.initializeApp(firebase.app().options, 'Secondary'); 1519 var secondaryAuth = secondaryApp.auth(); 1520 1521 secondaryAuth.createUserWithEmailAndPassword(email, piTempPassword()) 1522 .then(function(cred) { 1523 var uid = cred.user.uid; 1524 return secondaryAuth.signOut() 1525 .then(function() { return auth.sendPasswordResetEmail(email); }) 1526 .then(function() { 1527 return usersRef.child(uid).set({ 1528 email: email, 1529 createdAt: nowIso, 1530 lastAction: 'created', 1531 lastActionAt: nowIso 1532 }); 1533 }); 1534 }) 1535 .then(function() { 1536 msg.textContent = 'Cuenta creada correctamente. Se envió un correo electrónico a ' + email + ' para que establezca su contraseña.'; 1537 msg.style.color = '#166534'; 1538 emailInput.value = ''; 1539 }) 1540 .catch(function(error) { 1541 if (error && error.code === 'auth/email-already-in-use') { 1542 auth.sendPasswordResetEmail(email) 1543 .then(function() { return piTrackExistingUser(email, nowIso); }) 1544 .then(function() { 1545 msg.textContent = 'Ya existe una cuenta registrada con este correo electrónico. Se reenvió el correo para restablecer la contraseña.'; 1546 msg.style.color = '#166534'; 1547 emailInput.value = ''; 1548 }) 1549 .catch(function(err2) { 1550 msg.textContent = 'No fue posible reenviar el correo electrónico: ' + (err2 && err2.message ? err2.message : 'error desconocido.'); 1551 msg.style.color = '#b91c1c'; 1552 }); 1553 } else { 1554 msg.textContent = 'Ocurrió un error: ' + (error && error.message ? error.message : 'error desconocido.'); 1555 msg.style.color = '#b91c1c'; 1556 } 1557 }) 1558 .finally(function() { 1559 btn.disabled = false;
1560 btn.textContent = 'Agregar y enviar acceso'; 1561 }); 1562}; 1563 1564</script>
1564 1565</div></div></div></div></div></div></section></div></div></div></div>
1565<script data-cookieconsent="ignore" charSet="UTF-8">window.__PRELOADED_STATE__={"page":{"id":44408366,"type":"sales_page","locale":"es","entities":{"0b44292c-2c9f-4b8e-bf28-abb0b0bbfd2f":{"id":"0b44292c-2c9f-4b8e-bf28-abb0b0bbfd2f","type":"Row","htmlAttrId":"row-4c2f6aa3","childIds":["c22abb90-1c64-4ada-8952-ac490857de71"],"parentId":"68775490-971b-4f63-b077-97802531e5a9","padding":{"paddingTop":10,"paddingLeft":10,"paddingRight":10,"paddingBottom":10},"background":[],"mobilePadding":{"paddingTop":5,"paddingLeft":5,"paddingRight":5,"paddingBottom":5}},"19a03973-70b8-4e50-a101-226b1ba60132":{"id":"19a03973-70b8-4e50-a101-226b1ba60132","type":"Body","htmlAttrId":"body-fe0a06d6","childIds":["68775490-971b-4f63-b077-97802531e5a9"],"background":[]},"68775490-971b-4f63-b077-97802531e5a9":{"id":"68775490-971b-4f63-b077-97802531e5a9","type":"Section","htmlAttrId":"section-0b1ba2d1","childIds":["0b44292c-2c9f-4b8e-bf28-abb0b0bbfd2f"],"parentId":"19a03973-70b8-4e50-a101-226b1ba60132","padding":{"paddingTop":40,"paddingLeft":40,"paddingRight":40,"paddingBottom":40},"background":{"backgroundRepeat":"no-repeat"},"contentWidth":"fullPage","mobilePadding":{"paddingTop":5,"paddingLeft":5,"paddingRight":5,"paddingBottom":5}},"c22abb90-1c64-4ada-8952-ac490857de71":{"id":"c22abb90-1c64-4ada-8952-ac490857de71","type":"Column","htmlAttrId":"column-22be168a","childIds":["fb9a90ec-5193-4640-b51c-9033385381db"],"parentId":"0b44292c-2c9f-4b8e-bf28-abb0b0bbfd2f","size":12,"alignSelf":"flex-start"},"fb9a90ec-5193-4640-b51c-9033385381db":{"id":"fb9a90ec-5193-4640-b51c-9033385381db","type":"RawHtml","htmlAttrId":"rawhtml-18f2cb90","parentId":"c22abb90-1c64-4ada-8952-ac490857de71","html":"\x3c!-- Portal Interno OPANAL -->\n\n\x3c!-- Firebase SDKs -->\n\x3cscript src=\"https://www.gstatic.com/firebasejs/10.12.0/firebase-app-compat.js\">\x3c/script>\n\x3cscript src=\"https://www.gstatic.com/firebasejs/10.12.0/firebase-auth-compat.js\">\x3c/script>\n\x3cscript src=\"https://www.gstatic.com/firebasejs/10.12.0/firebase-database-compat.js\">\x3c/script>\n\n\x3c!-- Selector de idioma Español/Inglés -->\n\x3cscript>window.gtranslateSettings = {\"default_language\":\"es\",\"native_language_names\":true,\"languages\":[\"es\",\"en\"],\"wrapper_selector\":\".gtranslate_wrapper\"}\x3c/script>\n\x3cscript src=\"https://cdn.gtranslate.net/widgets/latest/ln.js\" defer>\x3c/script>\n\n\x3cstyle>\n\nhtml, body { margin: 0; background: #FCF8F3; }\n\n.full-width{\n width:100vw;\n margin-left:calc(-50vw + 50%);\n padding: 0 2rem;\n box-sizing: border-box;\n}\n\n@media (max-width:768px){\n .full-width{ padding: 0; }\n}\n\n#autoIframe{ margin-top: -80px; }\n\n/* ===== HEADER PROPIO DEL PORTAL ===== */\n.pi-header {\n background: #1B3C53;\n padding: 1.5rem 2rem;\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.pi-header-left {\n display: flex;\n align-items: center;\n gap: 1rem;\n}\n\n.pi-header img { height: 50px; }\n\n.pi-header-title {\n color: white;\n font-weight: bold;\n font-size: 1.4rem;\n}\n\n.pi-header-title span { color: #9fc1d6; }\n\n.pi-user-box {\n display: flex;\n align-items: center;\n gap: 1rem;\n color: #dbe7ee;\n font-size: 1rem;\n}\n\n.pi-logout-btn {\n background: transparent;\n border: 1.5px solid #dbe7ee;\n color: #dbe7ee;\n padding: 0.6rem 1.3rem;\n border-radius: 2rem;\n font-size: 0.95rem;\n cursor: pointer;\n}\n\n.pi-logout-btn:hover { background: rgba(255,255,255,0.1); }\n\n.pi-role-badge {\n font-size: 0.8rem;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n padding: 0.3rem 0.8rem;\n border-radius: 1rem;\n background: #456882;\n color: white;\n}\n\n@media (max-width: 640px) {\n .pi-header { flex-wrap: wrap; gap: 0.75rem; padding: 1.1rem 1.25rem; }\n .pi-header-title { font-size: 1.15rem; }\n .pi-user-box { font-size: 0.85rem; gap: 0.6rem; flex-wrap: wrap; }\n .pi-logout-btn { padding: 0.45rem 1rem; font-size: 0.85rem; }\n}\n\n/* ===== Selector de idioma (GTranslate) ===== */\n.gtranslate_wrapper {\n display: flex;\n align-items: center;\n gap: 0.4rem;\n font-size: 0.85rem;\n}\n.gtranslate_wrapper a {\n color: #dbe7ee !important;\n text-decoration: none !important;\n font-size: 0.85rem !important;\n}\n.gtranslate_wrapper a:hover { color: #fff !important; text-decoration: underline !important; }\n.gtranslate_wrapper select {\n background: transparent;\n color: #dbe7ee;\n border: 1.5px solid #dbe7ee;\n border-radius: 0.5rem;\n padding: 0.2rem 0.5rem;\n font-size: 0.8rem;\n}\n\n/* ===== BURBUJA DE USUARIO ===== */\n.pi-avatar-wrap { position: relative; }\n\n.pi-avatar-btn {\n width: 42px;\n height: 42px;\n border-radius: 50%;\n background: #456882;\n color: white;\n border: 1.5px solid #dbe7ee;\n font-weight: 700;\n font-size: 1.05rem;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n text-transform: uppercase;\n line-height: 1;\n padding: 0;\n}\n\n.pi-avatar-btn:hover { background: #2e4a5f; }
1565\n\n.pi-user-dropdown {\n position: absolute;\n top: calc(100% + 12px);\n right: 0;\n background: white;\n border: 1px solid #e9ddd0;\n border-radius: 0.9rem;\n padding: 1.1rem 1.2rem;\n min-width: 230px;\n box-shadow: 0 12px 30px rgba(0,0,0,0.18);\n text-align: left;\n z-index: 9999;\n}\n\n.pi-dropdown-email {\n font-size: 0.85rem;\n font-weight: 600;\n color: #111827;\n word-break: break-all;\n margin: 0 0 0.6rem 0;\n}\n\n.pi-dropdown-role { margin: 0 0 1rem 0; }\n\n.pi-dropdown-logout {\n width: 100%;\n background: transparent;\n border: 1.5px solid #d1c4b8;\n color: #456882;\n padding: 0.55rem 1rem;\n border-radius: 2rem;\n font-size: 0.9rem;\n font-weight: 600;\n cursor: pointer;\n}\n.pi-dropdown-logout:hover { background: #f3ece4; }\n\n@media (max-width: 640px) {\n .pi-user-dropdown { right: -0.5rem; }\n}\n\n/* ===== LOGIN ===== */\n.pi-login-wrap {\n min-height: 100vh;\n box-sizing: border-box;\n display: flex;\n align-items: center;\n justify-content: center;\n background: #456882;\n padding: 2rem 1rem;\n}\n\n.pi-login-card {\n background: white;\n border: 1px solid #e9ddd0;\n border-radius: 1.25rem;\n padding: 2.5rem 2rem;\n width: 380px;\n max-width: 92vw;\n text-align: center;\n}\n\n.pi-login-card img { height: 96px; margin-bottom: 1.25rem; }\n\n.pi-login-title {\n font-size: 1.2rem;\n font-weight: bold;\n color: #111827;\n margin-bottom: 0.4rem;\n}\n\n.pi-login-subtitle {\n font-size: 0.85rem;\n color: #6b7280;\n margin-bottom: 1.5rem;\n}\n\n.pi-field-group { margin-bottom: 1rem; text-align: left; }\n\n.pi-field-label {\n display: block;\n font-size: 0.72rem;\n font-weight: 600;\n color: #6b7280;\n letter-spacing: 0.05em;\n text-transform: uppercase;\n margin-bottom: 0.35rem;\n}\n\n.pi-input {\n width: 100%;\n padding: 0.6rem 0.9rem;\n border: 1.5px solid #e9ddd0;\n border-radius: 0.6rem;\n font-size: 0.9rem;\n background: #FCF8F3;\n color: #111827;\n outline: none;\n box-sizing: border-box;\n}\n\n.pi-input:focus { border-color: #456882; }\n\n.pi-login-btn {\n width: 100%;\n background: #456882;\n color: white;\n border: none;\n padding: 0.85rem 1rem;\n border-radius: 2rem;\n font-size: 0.95rem;\n font-weight: 600;\n cursor: pointer;\n margin-top: 0.5rem;\n}\n\n.pi-login-btn:hover { background: #2e4a5f; }\n.pi-login-btn:disabled { opacity: 0.6; cursor: default; }\n\n.pi-login-error {\n font-size: 0.82rem;\n color: #b91c1c;\n margin-top: 1rem;\n min-height: 1.2em;\n}\n\n.pi-hidden { display: none !important; }\n\n#pi-portal { min-height: 100vh; box-sizing: border-box; }\n\n/* ===== SUBMENU (calendario / repositorio) ===== */\n.clean-submenu{\n display:flex;\n justify-content:center;\n gap:2rem;\n padding:1.5rem 1rem;\n margin-bottom:0;\n background-color:#FCF8F3;\n border-bottom:1px solid #F2F2F2;\n}\n\n.tab{\n font-family:'Inter', sans-serif;\n font-size:0.875rem;\n text-transform:uppercase;\n letter-spacing:0.04em;\n color:#1B3C53;\n cursor:pointer;\n position:relative;\n padding-bottom:0.5rem;\n background:none;\n border:none;\n transition:opacity .3s;\n}\n\n.tab:hover{ opacity:.7; }\n\n.tab::after{\n content:\"\";\n position:absolute;\n left:0;\n bottom:0;\n width:0;\n height:2px;\n background:#1B3C53;\n transition:width .3s;\n}\n\n.tab.active::after{ width:100%; }\n.tab.active{ font-weight:500; }\n\n.tab-content{\n display:none;\n padding:3rem 1rem;\n background: #FCF8F3;\n}\n\n.tab-content.active{ display:block; }\n\n.container{ max-width:1200px; margin:0 auto; }\n\n@media(max-width:768px){\n .clean-submenu{\n display:grid;\n grid-template-columns:1fr 1fr;\n gap:8px;\n padding:.6rem;\n }\n .tab{\n width:100%;\n display:flex;\n align-items:center;\n justify-content:center;\n min-height:44px;\n padding:8px 10px;\n font-size:.75rem;\n border-radius:16px;\n text-transform:none;\n }\n .tab::after{ display:none; }\n .tab.active{ background:#1B3C53; color:#fff; }\n}\n\n.eventos-section, .eventos-section-wrapper { background: #FCF8F3 !important; }\n\n/* ===== BIBLIOTECA / REPOSITORIO ===== */\n.odf-section {\n background-color: #FCF8F3;\n padding: 2rem 1rem 1.5rem 1rem;\n position: relative;\n}\n\n.odf-container { max-width: 1280px; margin: 0 auto; }\n\n.odf-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 1.5rem;\n flex-wrap: wrap;\n gap: 0.75rem;\n}\n\n.odf-title { font-size: 1.5rem; font-weight: bold; color: #111827; }\n.odf-title span { color: #456882; }\n\n.odf-toolbar { display: flex; align-items: center; gap: 0.75rem; }\n\n.odf-save-badge {\n font-size: 0.78rem;\n color: #166534;\n background: #dcfce7;\n border-radius: 0.5rem;\n padding: 0.3rem 0.7rem;\n opacity: 0;\n transition: opacity 0.3s;\n font-weight: 500;\n}\n.odf-save-badge.odf-show { opacity: 1; }\n\n.odf-main-add-btn {\n display: inline-flex;\n align-items: center;\n gap: 0.45rem;\n font-size: 1rem;\n font-weight: 600;\n padding: 0.6rem 1.4rem;\n background: #456882;\n color: white;\n border: none;\n border-radius: 2rem;\n cursor: pointer;\n transition: background 0.15s;\n white-space: nowrap;\n}\n.odf-main-add-btn:hover { background: #2e4a5f; }\n\n.odf-year-block { margin-bottom: 1.5rem; }\n\n.odf-year-header {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n margin-bottom: 0.75rem;\n}\n\n.odf-year-pill {\n background: #456882;\n color: white;\n font-size: 0.8rem;\n font-weight: bold;\n letter-spacing: 0.06em;\n padding: 0.3rem 0.9rem;\n border-radius: 2rem;\n white-space: nowrap;\n}\n\n.odf-year-line { flex: 1; height: 1px; background: #e5d9cc; }\n\n.odf-table-wrapper {\n background: white;\n border-radius: 1rem;\n overflow: hidden;\n border: 1px solid #e9ddd0;\n}\n\n.odf-table { width: 100%; border-collapse: collapse; font-size: 0.9rem; table-layout: fixed; }\n.odf-table thead { background: #F6EFE6; }\n\n.odf-table th {\n text-align: left;\n padding: 0.75rem 1.25rem;\n font-size: 0.75rem;\n font-weight: 600;\n color: #6b7280;\n letter-spacing: 0.05em;\n text-transform: uppercase;\n vertical-align: middle;\n}\n\n.odf-table td {\n padding: 0.75rem 1.25rem;\n border-top: 1px solid #f3ece4;\n color: #111827;\n vertical-align: middle;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.odf-col-name { width: 32%; }\n.odf-col-date { width: 14%; }\n.odf-col-author { width: 28%; }\n.odf-col-mod { width: 20%; }\n.odf-col-acts { width: 6%; }\n\n.odf-table tbody tr:hover td { background: #fdf9f5; }\n\n.odf-file-link {\n display: inline-flex;\n align-items: center;\n gap: 0.45rem;\n color: #456882;\n text-decoration: none;\n font-weight: 600;\n font-size: 0.9rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n max-width: 100%;\n}\n.odf-file-link:hover { color: #2e4a5f; text-decoration: underline; }\n\n.odf-date-cell { color: #6b7280; font-size: 0.85rem; white-space: nowrap; }\n\n.odf-author-cell {\n font-size: 0.8rem;\n color: #6b7280;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.odf-author-label {\n font-size: 0.7rem;\n color: #9ca3af;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n display: block;\n margin-bottom: 1px;\n}\n\n.odf-mod-cell {\n font-size: 0.78rem;\n color: #9ca3af;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.odf-actions-cell { display: flex; gap: 0.2rem; justify-content: flex-end; align-items: center; }\n\n.odf-edit-btn {\n background: none; border: none; cursor: pointer; color: #9ca3af;\n padding: 0.3rem; border-radius: 0.4rem; transition: color 0.15s, background 0.15s;\n font-size: 0.95rem; line-height: 1;\n}\n.odf-edit-btn:hover { color: #456882; background: #e0eaf1; }\n\n.odf-delete-btn {\n background: none; border: none; cursor: pointer; color: #d1c4b8;\n padding: 0.3rem; border-radius: 0.4rem; transition: color 0.15s, background 0.15s;\n font-size: 0.95rem; line-height: 1;\n}\n.odf-delete-btn:hover { color: #b91c1c; background: #fee2e2; }\n\n.odf-empty-row td { text-align: center; padding: 2rem; color: #b0a090; font-size: 0.85rem; }\n.odf-loading { text-align: center; padding: 3rem 2rem; color: #9ca3af; font-size: 0.9rem; }\n\n/* Modales agregar/editar archivo */\n.odf-overlay {\n position: fixed; inset: 0; background: rgba(0,0,0,0.4);\n display: flex; align-items: center; justify-content: center; z-index: 9999;\n}\n.odf-overlay.odf-hidden { display: none; }\n\n.odf-modal {\n background: #FCF8F3; border-radius: 1rem; padding: 2rem;\n width: 420px; max-width: 92vw; border: 1px solid #e9ddd0;\n}\n\n.odf-modal-title { font-size: 1.1rem; font-weight: bold; color: #111827; margin-bottom: 1.5rem; }\n.odf-modal-title span { color: #456882; }\n\n.odf-field-group { margin-bottom: 1.1rem; }\n\n.odf-field-label {\n display: block; font-size: 0.75rem; font-weight: 600; color: #6b7280;\n letter-spacing: 0.05em; text-transform: uppercase; margin-bottom: 0.4rem;\n}\n.odf-field-label .odf-required { color: #b91c1c; margin-left: 2px; }\n\n.odf-input {\n width: 100%; padding: 0.6rem 0.9rem; border: 1.5px solid #e9ddd0; border-radius: 0.6rem;\n font-size: 0.9rem; background: white; color: #111827; outline: none; box-sizing: border-box;\n}\n.odf-input:focus { border-color: #456882; }\n.odf-input.odf-input-error { border-color: #b91c1c; }\n\n.odf-error { font-size: 0.75rem; color: #b91c1c; margin-top: 0.3rem; }\n.odf-error.odf-hidden { display: none; }\n\n.odf-modal-actions { display: flex; justify-content: flex-end; gap: 0.6rem; margin-top: 1.5rem; }\n\n.odf-btn-primary {\n background: #456882; color: white; border: none; padding: 0.55rem 1.3rem;\n border-radius: 2rem; font-size: 0.9rem; font-weight: 500; cursor: pointer;\n}\n.odf-btn-primary:hover { background: #2e4a5f; }\n\n.odf-btn-cancel {\n background: transparent; border: 1.5px solid #d1c4b8; padding: 0.55rem 1.1rem;\n border-radius: 2rem; font-size: 0.9rem; cursor: pointer; color: #6b7280;\n}\n.odf-btn-cancel:hover { background: #f3ece4; }\n\n@media (max-width: 768px) {\n .odf-col-author, .odf-col-mod,\n .odf-table th:nth-child(3), .odf-table th:nth-child(4),\n .odf-table td:nth-child(3), .odf-table td:nth-child(4) { display: none; }\n .odf-col-date { width: 25%; }\n .odf-col-name { width: 65%; }\n}\n\n/* ===== ADMINISTRACIÃN (solo admin) ===== */\n.pi-admin-msg { font-size: 0.85rem; margin-top: 0.85rem; margin-bottom: 0; min-height: 1.1em; }\n.pi-admin-help { color: #6b7280; font-size: 0.85rem; margin: 0 0 1.1rem 0; }\n.pi-admin-panel { margin-bottom: 1.5rem; }\n\n.pi-admin-form-row {\n display: flex;\n align-items: flex-end;\n gap: 1rem;\n flex-wrap: wrap;\n margin-bottom: 0.5rem;\n}\n.pi-admin-form-row .odf-field-group { flex: 0 1 340px; margin-bottom: 0; }\n\n.pi-admin-subtitle { font-size: 1rem; font-weight: 600; color: #111827; margin: 1.85rem 0 0.5rem 0; }\n\n@media (max-width: 640px) {\n .pi-admin-form-row { flex-direction: column; align-items: stretch; }\n .pi-admin-form-row .odf-field-group { flex: 1 1 auto; }\n}\n\n/* BUSCADOR */\n.odf-search-box { position: relative; width: 260px; }\n\n#odf-searchInput {\n width: 100%; padding: 0.5rem 0.9rem; border-radius: 6px; border: 1.5px solid #e5d9cc;\n outline: none; font-size: 0.85rem; box-sizing: border-box; background: white; color: #111827;\n}\n#odf-searchInput:focus { border-color: #456882; }\n\n#odf-searchResults {\n position: absolute; top: 110%; left: 0; width: 100%; background: white;\n border-radius: 0.5rem; box-shadow: 0 10px 25px rgba(0,0,0,0.15); display: none;\n z-index: 9999; overflow: hidden; border: 1px solid #e9ddd0;\n}\n#odf-searchResults .odf-result-item { padding: 9px 12px; cursor: pointer; font-size: 0.85rem; border-bottom: 1px solid #f3ece4; }\n#odf-searchResults .odf-result-item:last-child { border-bottom: none; }\n#odf-searchResults .odf-result-item:hover { background: #f3ece4; }\n#odf-searchResults .odf-result-name { font-weight: 600; color: #111827; }\n#odf-searchResults .odf-result-meta { font-size: 0.75rem; color: #9ca3af; margin-top: 2px; }\n#odf-searchResults .odf-no-results { padding: 12px; text-align: center; color: #9ca3af; font-size: 0.83rem; }\n\n\x3c/style>\n\n\x3c!-- ============================================================\n PANTALLA DE LOGIN (se muestra hasta que Firebase Auth confirma sesión)\n============================================================ -->\n\x3cdiv id=\"pi-login-screen\" class=\"pi-login-wrap\">\n \x3cdiv class=\"pi-login-card\">\n \x3cimg src=\"https://d1yei2z3i6k35z.cloudfront.net/15882402/6a2af06f0122f4.91897886_fondoblanco.jpg\" alt=\"OPANAL\" />\n \x3cp class=\"pi-login-title\">Portal Interno OPANAL\x3c/p>\n \x3cp class=\"pi-login-subtitle\">Ingresá con tu cuenta para acceder.\x3c/p>\n\n \x3cdiv class=\"pi-field-group\">\n \x3clabel class=\"pi-field-label\">Correo electrónico\x3c/label>\n \x3cinput class=\"pi-input\" type=\"email\" id=\"pi-login-email\" placeholder=\"[email protected]\" autocomplete=\"username\" />\n \x3c/div>\n \x3cdiv class=\"pi-field-group\">\n \x3clabel class=\"pi-field-label\">Contraseña\x3c/label>\n \x3cinput class=\"pi-input\" type=\"password\" id=\"pi-login-password\" placeholder=\"â¢â¢â¢â¢â¢â¢â¢â¢\" autocomplete=\"current-password\" />\n \x3c/div>\n\n \x3cbutton class=\"pi-login-btn\" id=\"pi-login-btn\" onclick=\"piLogin()\">Ingresar\x3c/button>\n \x3cp class=\"pi-login-error pi-hidden\" id=\"pi-login-error\">Mail o contraseña incorrectos.\x3c/p>\n \x3c/div>\n\x3c/div>\n\n\x3c!-- ============================================================\n PORTAL (oculto hasta login exitoso)\n============================================================ -->\n\x3csection id=\"pi-portal\" style=\"background:#FCF8F3; display:none;\">\n\n \x3cdiv class=\"pi-header\">\n \x3cdiv class=\"pi-header-left\">\n \x3cimg src=\"https://d1yei2z3i6k35z.cloudfront.net/15882402/6a2af06f0122f4.91897886_fondoblanco.jpg\" alt=\"OPANAL\" />\n \x3cspan class=\"pi-header-title\">Portal \x3cspan>Interno OPANAL\x3c/span>\x3c/span>\n \x3c/div>\n \x3cdiv class=\"pi-user-box\">\n \x3cdiv class=\"gtranslate_wrapper\">\x3c/div>\n \x3cdiv class=\"pi-avatar-wrap\" id=\"pi-avatar-wrap\">\n \x3cbutton class=\"pi-avatar-btn notranslate\" id=\"pi-avatar-btn\" onclick=\"piToggleUserMenu()\" title=\"Mi cuenta\" translate=\"no\">?\x3c/button>
1565\n \x3cdiv class=\"pi-user-dropdown pi-hidden\" id=\"pi-user-dropdown\">\n \x3cp class=\"pi-dropdown-email\" id=\"pi-user-email\">\x3c/p>\n \x3cp class=\"pi-dropdown-role\">\x3cspan class=\"pi-role-badge\" id=\"pi-role-badge\">Miembro\x3c/span>\x3c/p>\n \x3cbutton class=\"pi-dropdown-logout\" onclick=\"piLogout()\">Cerrar sesión\x3c/button>\n \x3c/div>\n \x3c/div>\n \x3c/div>\n \x3c/div>\n\n \x3cnav class=\"clean-submenu\">\n \x3cbutton class=\"tab active\" onclick=\"showTab(0)\">Calendario de reuniones\x3c/button>\n \x3cbutton class=\"tab\" onclick=\"showTab(1)\">Repositorio Institucional\x3c/button>\n \x3cbutton class=\"tab pi-hidden\" id=\"pi-admin-tab-btn\" onclick=\"showTab(2)\">Administración\x3c/button>\n \x3c/nav>\n\n \x3c!-- CALENDARIO -->\n \x3cdiv class=\"tab-content active\">\n \x3cdiv class=\"container\">\n \x3cdiv class=\"full-width\">\n \x3ciframe\n src=\"https://calendar.google.com/calendar/embed?src=b3BhbmFsd2ViQGdtYWlsLmNvbQ\"\n style=\"border:0; width:100%; height:1000px;\"\n frameborder=\"0\"\n scrolling=\"no\">\n \x3c/iframe>\n \x3c/div>\n \x3c/div>\n \x3c/div>\n\n \x3c!-- BIBLIOTECA / REPOSITORIO -->\n \x3cdiv class=\"tab-content\">\n \x3cdiv class=\"container\">\n \x3cdiv style=\"background:#F6EFE6; width:100%; overflow:hidden;\">\n \x3cdiv class=\"odf-section\">\n \x3cdiv class=\"odf-container\">\n\n \x3cdiv class=\"odf-header\">\n \x3ch2 class=\"odf-title\">Archivos \x3cspan>OneDrive\x3c/span>\x3c/h2>\n\n \x3cdiv class=\"odf-search-box\">\n \x3cinput id=\"odf-searchInput\" placeholder=\"ð Buscar archivo...\" autocomplete=\"off\" />\n \x3cdiv id=\"odf-searchResults\">\x3c/div>\n \x3c/div>\n\n \x3cdiv class=\"odf-toolbar\">\n \x3cspan id=\"odf-save-badge\" class=\"odf-save-badge\">â Guardado\x3c/span>\n \x3cbutton class=\"odf-main-add-btn pi-hidden\" id=\"odf-add-btn\" onclick=\"odfOpenModal()\">+ Agregar archivo\x3c/button>\n \x3c/div>\n \x3c/div>\n\n \x3cdiv id=\"odf-app\">\n \x3cdiv class=\"odf-loading\">Cargando archivos...\x3c/div>\n \x3c/div>\n\n \x3c/div>\n \x3c/div>\n \x3c/div>\n\n \x3c!-- MODAL: AGREGAR / EDITAR ARCHIVO -->\n \x3cdiv class=\"odf-overlay odf-hidden\" id=\"odf-overlay\">\n \x3cdiv class=\"odf-modal\">\n \x3cp class=\"odf-modal-title\" id=\"odf-modal-title\">Agregar archivo\x3c/p>\n\n \x3cdiv class=\"odf-field-group\">\n \x3clabel class=\"odf-field-label\">Nombre del archivo\x3c/label>\n \x3cinput class=\"odf-input\" type=\"text\" id=\"odf-input-name\" placeholder=\"Ej: Informe trimestral Q1\" />\n \x3cp class=\"odf-error odf-hidden\" id=\"odf-err-name\">Ingresá un nombre\x3c/p>\n \x3c/div>\n\n \x3cdiv class=\"odf-field-group\">\n \x3clabel class=\"odf-field-label\">Link de OneDrive \x3cspan class=\"odf-required\">*\x3c/span>\x3c/label>\n \x3cinput class=\"odf-input\" type=\"url\" id=\"odf-input-link\" placeholder=\"https://onedrive.live.com/...\" />\n \x3cp class=\"odf-error odf-hidden\" id=\"odf-err-link\">El link es obligatorio y debe comenzar con http\x3c/p>\n \x3c/div>\n\n \x3cdiv class=\"odf-field-group\">\n \x3clabel class=\"odf-field-label\">Fecha de subida \x3cspan class=\"odf-required\">*\x3c/span>\x3c/label>\n \x3cinput class=\"odf-input\" type=\"date\" id=\"odf-input-date\" />\n \x3cp class=\"odf-error odf-hidden\" id=\"odf-err-date\">La fecha es obligatoria\x3c/p>\n \x3c/div>\n\n \x3cdiv class=\"odf-modal-actions\">\n \x3cbutton class=\"odf-btn-cancel\" onclick=\"odfCloseModal()\">Cancelar\x3c/button>\n \x3cbutton class=\"odf-btn-primary\" id=\"odf-btn-save\" onclick=\"odfSaveFile()\">Guardar\x3c/button>\n \x3c/div>\n \x3c/div>\n \x3c/div>\n\n \x3c/div>\n \x3c/div>\n\n \x3c!-- ADMINISTRACIÃN (solo admin) -->\n \x3cdiv class=\"tab-content\">\n \x3cdiv class=\"container\">\n\n \x3c!-- Gestión de usuarios -->\n \x3cdiv style=\"background:#F6EFE6; width:100%; overflow:hidden;\" class=\"pi-admin-panel\">\n \x3cdiv class=\"odf-section\">\n \x3cdiv class=\"odf-container\">\n \x3cdiv class=\"odf-header\">\n \x3ch2 class=\"odf-title\">Gestión de \x3cspan>usuarios\x3c/span>\x3c/h2>\n \x3c/div>\n \x3cp class=\"pi-admin-help\">Ingrese el correo electrónico de la persona. Si aún no cuenta con una cuenta, el sistema la creará automáticamente y le enviará un correo electrónico para que establezca su contraseña. Si ya cuenta con una cuenta registrada, se le reenviará ese mismo correo de acceso.\x3c/p>\n \x3cdiv class=\"pi-admin-form-row\">\n \x3cdiv class=\"odf-field-group\">\n \x3clabel class=\"odf-field-label\">Correo electrónico\x3c/label>\n \x3cinput class=\"odf-input\" type=\"email\" id=\"pi-admin-user-email\" placeholder=\"[email protected]\" />\n \x3c/div>\n \x3cbutton class=\"odf-btn-primary\" id=\"pi-admin-user-btn\" onclick=\"piAdminAddUser()\">Agregar y enviar acceso\x3c/button>\n \x3c/div>\n \x3cp class=\"pi-admin-msg\" id=\"pi-admin-user-msg\">\x3c/p>\n\n \x3cp class=\"pi-admin-subtitle\">Usuarios registrados\x3c/p>\n \x3cp class=\"pi-admin-help\" style=\"margin-bottom:0.75rem;\">Esta lista incluye únicamente a las personas agregadas o gestionadas desde este panel. Las cuentas creadas previamente por otro medio no se mostrarán aquÃ.\x3c/p>
1565\n \x3cdiv id=\"pi-admin-users-list\">\x3cdiv class=\"odf-loading\">Cargando usuarios...\x3c/div>\x3c/div>\n \x3c/div>\n \x3c/div>\n \x3c/div>\n\n \x3c!-- AuditorÃa de archivos eliminados -->\n \x3cdiv style=\"background:#F6EFE6; width:100%; overflow:hidden;\" class=\"pi-admin-panel\">\n \x3cdiv class=\"odf-section\">\n \x3cdiv class=\"odf-container\">\n \x3cdiv class=\"odf-header\">\n \x3ch2 class=\"odf-title\">AuditorÃa de \x3cspan>archivos eliminados\x3c/span>\x3c/h2>\n \x3cdiv class=\"odf-toolbar\">\n \x3cbutton class=\"odf-main-add-btn\" onclick=\"piOpenTrash()\">ðï¸ \x3cspan class=\"notranslate\" id=\"pi-trash-btn-label\" translate=\"no\">Ver papelera\x3c/span>\x3c/button>\n \x3c/div>\n \x3c/div>\n \x3cp class=\"pi-admin-help\" style=\"margin-bottom:0;\">En esta sección se muestran los archivos eliminados del Repositorio Institucional, incluyendo el usuario responsable y la fecha de eliminación, en caso de que sea necesario restaurar alguno.\x3c/p>\n \x3c/div>\n \x3c/div>\n \x3c/div>\n\n \x3c/div>\n \x3c/div>\n\n \x3c!-- MODAL: PAPELERA -->\n \x3cdiv class=\"odf-overlay odf-hidden\" id=\"pi-trash-overlay\">\n \x3cdiv class=\"odf-modal\" style=\"width:640px;\">\n \x3cp class=\"odf-modal-title\">Historial de \x3cspan>archivos eliminados\x3c/span>\x3c/p>\n \x3cdiv id=\"pi-trash-list\">\x3c/div>\n \x3cdiv class=\"odf-modal-actions\">\n \x3cbutton class=\"odf-btn-cancel\" onclick=\"piCloseTrash()\">Cerrar\x3c/button>\n \x3c/div>\n \x3c/div>\n \x3c/div>\n\n\x3c/section>\n\n\x3cscript>\n\n(function debleedSystemeWrapper() {\n function debleed(el) {\n var cur = el, hops = 0;\n while (cur && hops \x3c 8) {\n if (cur.tagName === 'BODY') break;\n if (\n cur.tagName === 'SECTION' ||\n (cur.id && (cur.id.indexOf('row-') === 0 || cur.id.indexOf('section-') === 0))\n ) {\n cur.style.padding = '0';\n cur.style.margin = '0';\n }\n cur = cur.parentElement;\n hops++;\n }\n }\n function run() {\n debleed(document.getElementById('pi-login-screen'));\n debleed(document.getElementById('pi-portal'));\n }\n run();\n if (document.readyState !== 'complete') {\n document.addEventListener('DOMContentLoaded', run);\n window.addEventListener('load', run);\n }\n})();\n\nfunction showTab(index){\n const tabs = document.querySelectorAll('.tab');\n const contents = document.querySelectorAll('.tab-content');
1565\n tabs.forEach(tab => tab.classList.remove('active'));\n contents.forEach(content => content.classList.remove('active'));\n tabs[index].classList.add('active');\n contents[index].classList.add('active');\n}\n\n/* ================= FIREBASE ================= */\nfirebase.initializeApp({\n apiKey: \"AIzaSyArthFm16e3djN0xqhpF0ci6LCccCGgLBE\",\n authDomain: \"opanal.firebaseapp.com\",\n databaseURL: \"https://opanal-default-rtdb.firebaseio.com\",\n projectId: \"opanal\",\n storageBucket: \"opanal.firebasestorage.app\",\n messagingSenderId: \"862238375033\",\n appId: \"1:862238375033:web:d8d2d966d15083317268a8\"\n});\n\nvar auth = firebase.auth();\nvar db = firebase.database();\nvar ref = db.ref('onedrive_files');\nvar trashRef = db.ref('onedrive_files_trash');\nvar usersRef = db.ref('portal_users');\n\nvar isAdmin = false;\nvar odfBound = false;\nvar piUsersBound = false;\n\n/* ---- Login ---- */\nwindow.piLogin = function() {\n var email = document.getElementById('pi-login-email').value.trim();\n var pass = document.getElementById('pi-login-password').value;\n var btn = document.getElementById('pi-login-btn');\n var err = document.getElementById('pi-login-error');\n\n err.classList.add('pi-hidden');\n\n if (!email || !pass) {\n err.textContent = 'Completá mail y contraseña.';\n err.classList.remove('pi-hidden');\n return;\n }\n\n btn.disabled = true;\n btn.textContent = 'Ingresando...';\n\n auth.signInWithEmailAndPassword(email, pass)\n .catch(function(error) {\n err.textContent = 'Mail o contraseña incorrectos.';\n err.classList.remove('pi-hidden');\n })\n .finally(function() {\n btn.disabled = false;\n btn.textContent = 'Ingresar';\n });\n};\n\n// Enter para enviar el login\n['pi-login-email', 'pi-login-password'].forEach(function(id) {\n document.getElementById(id).addEventListener('keydown', function(e) {\n if (e.key === 'Enter') window.piLogin();\n });\n});\n\nwindow.piLogout = function() {\n auth.signOut();\n};\n\n/* ---- Burbuja de usuario (mail + rol + cerrar sesión) ---- */\nwindow.piToggleUserMenu = function() {\n var dd = document.getElementById('pi-user-dropdown');\n if (dd) dd.classList.toggle('pi-hidden');\n};\n\ndocument.addEventListener('click', function(e) {\n var wrap = document.getElementById('pi-avatar-wrap');\n var dd = document.getElementById('pi-user-dropdown');\n if (!wrap || !dd || dd.classList.contains('pi-hidden')) return;\n if (!wrap.contains(e.target)) dd.classList.add('pi-hidden');\n}, true);\n\nwindow.addEventListener('blur', function() {\n setTimeout(function() {\n if (document.activeElement && document.activeElement.tagName === 'IFRAME') {\n var dd = document.getElementById('pi-user-dropdown');\n if (dd) dd.classList.add('pi-hidden');\n }\n }, 0);\n});\n\n/* ---- Estado de sesión ---- */\nauth.onAuthStateChanged(function(user) {\n var loginScreen = document.getElementById('pi-login-screen');\n var portal = document.getElementById('pi-portal');\n var dd = document.getElementById('pi-user-dropdown');\n\n if (!user) {\n isAdmin = false;\n loginScreen.classList.remove('pi-hidden');\n loginScreen.style.display = 'flex';\n portal.style.display = 'none';\n if (dd) dd.classList.add('pi-hidden');\n return;\n }\n\n loginScreen.style.display = 'none';\n portal.style.display = 'block';\n document.getElementById('pi-user-email').textContent = user.email;\n var avatarBtn = document.getElementById('pi-avatar-btn');\n if (avatarBtn) avatarBtn.textContent = (user.email || '?').trim().charAt(0).toUpperCase();\n\n db.ref('admins/' + user.uid).once('value').then(function(snap) {\n isAdmin = snap.val() === true;\n document.getElementById('pi-role-badge').textContent = isAdmin ? 'Administrador' : 'Miembro';\n document.getElementById('odf-add-btn').classList.toggle('pi-hidden', !isAdmin);\n document.getElementById('pi-admin-tab-btn').classList.toggle('pi-hidden', !isAdmin);\n renderRepositorio(); // re-renderizar filas para mostrar/ocultar acciones según rol\n if (isAdmin && !piUsersBound) {\n piUsersBound = true;\n bindPortalUsers();\n }\n });\n\n if (!odfBound) {\n odfBound = true;\n bindRepositorio();\n }\n});\n\n/* ================= REPOSITORIO ================= */\nwindow._odfData = {};\nvar data = window._odfData;\nvar years = [];\nvar saving = false;\nvar editTarget = null;\n\nfunction bindRepositorio() {\n ref.on('value', function(snapshot) {\n var val = snapshot.val();
1565\n Object.keys(data).forEach(function(k) { delete data[k]; });\n if (val) {\n var incoming = val.data || {};\n Object.keys(incoming).forEach(function(k) { data[k] = incoming[k]; });\n years = val.years || [];\n if (!Array.isArray(years)) years = Object.values(years).map(Number);\n Object.keys(data).forEach(function(y) {\n if (data[y] && !Array.isArray(data[y])) data[y] = Object.values(data[y]);\n if (!data[y]) data[y] = [];\n });\n }\n initDefaultYears();\n renderRepositorio();\n }, function(err) {\n console.error('Firebase error:', err);\n initDefaultYears();\n renderRepositorio();\n });\n\n // Buscador\n var searchInput = document.getElementById('odf-searchInput');\n var searchResults = document.getElementById('odf-searchResults');\n\n searchInput.addEventListener('input', function() {\n var q = this.value.toLowerCase().trim();\n if (!q) {\n searchResults.style.display = 'none';\n searchResults.innerHTML = '';\n return;\n }\n var results = [];\n Object.keys(data).forEach(function(year) {\n (data[year] || []).forEach(function(file) {\n if (!file) return;\n if (\n (file.name && file.name.toLowerCase().includes(q)) ||\n (file.date && file.date.includes(q)) ||\n (file.createdBy && file.createdBy.toLowerCase().includes(q)) ||\n year.toString().includes(q)\n ) {\n results.push({ year: year, name: file.name, date: file.date, link: file.link, createdBy: file.createdBy });\n }\n });\n });\n\n searchResults.innerHTML = '';\n if (results.length === 0) {\n searchResults.innerHTML = '\x3cdiv class=\"odf-no-results\">Sin resultados\x3c/div>';\n } else {\n results.slice(0, 6).forEach(function(f) {\n var div = document.createElement('div');\n div.className = 'odf-result-item';\n div.innerHTML =\n '\x3cdiv class=\"odf-result-name\">ð ' + escHtml(f.name || '(sin nombre)') + '\x3c/div>' +\n '\x3cdiv class=\"odf-result-meta\">' + fmt(f.date) + ' · ' + f.year + (f.createdBy ? ' · ' + escHtml(shortUser(f.createdBy)) : '') + '\x3c/div>';\n div.addEventListener('click', function() {\n window.open(f.link, '_blank');\n searchResults.style.display = 'none';\n searchInput.value = '';\n });\n searchResults.appendChild(div);\n });\n }\n searchResults.style.display = 'block';\n });\n\n document.addEventListener('click', function(e) {\n if (!searchInput.contains(e.target) && !searchResults.contains(e.target)) {\n searchResults.style.display = 'none';\n }\n });\n\n document.getElementById('odf-overlay').addEventListener('click', function(e) {\n if (e.target === this) odfCloseModal();\n });\n}\n\nfunction initDefaultYears() {\n if (years.length === 0) {\n var cur = new Date().getFullYear();\n years = [cur, cur - 1, cur - 2];\n years.forEach(function(y) { if (!data[y]) data[y] = []; });\n }\n}\n\nfunction saveData(callback) {\n if (saving) return;\n saving = true;\n var btn = document.getElementById('odf-btn-save');\n if (btn) { btn.textContent = 'Guardando...'; btn.disabled = true; }\n\n ref.set({ data: data, years: years }, function(err) {\n saving = false;\n if (btn) { btn.textContent = 'Guardar'; btn.disabled = false; }\n if (!err) {\n var badge = document.getElementById('odf-save-badge');\n badge.classList.add('odf-show');\n setTimeout(function() { badge.classList.remove('odf-show'); }, 2000);\n if (callback) callback();\n } else {\n alert('No tenés permiso para guardar, o hubo un error de conexión.');\n console.error(err);\n }\n });\n}\n\nfunction fmt(dateStr) {\n var p = dateStr.split('-');\n return p[2] + '/' + p[1] + '/' + p[0];\n}\n\nfunction escHtml(str) {\n if (!str) return '';\n return str.replace(/&/g,'&').replace(/\x3c/g,'<').replace(/>/g,'>').replace(/\"/g,'"');\n}\n\nfunction shortUser(u) {\n if (!u) return 'â';\n if (u.indexOf('@') > -1 && u.length > 22) {\n var parts = u.split('@');\n return parts[0] + '@' + parts[1].split('.')[0];\n }\n return u.length > 24 ? u.substring(0, 22) + 'â¦' : u;\n}\n\nfunction renderRepositorio() {\n var app = document.getElementById('odf-app');\n if (!app) return;\n var sorted = years.slice().sort(function(a,b){ return b - a; })\n .filter(function(year){ return data[year] && data[year].length > 0; });\n var html = '';\n\n if (sorted.length === 0) {\n app.innerHTML = '\x3cp style=\"text-align:center; color:#6b7280; padding:2rem 0;\">TodavÃa no hay archivos cargados.\x3c/p>';\n return;\n }\n\n sorted.forEach(function(year) {\n var rows = data[year] || [];\n var rowsHtml = '';\n\n if (rows.length === 0) {\n rowsHtml = '\x3ctr class=\"odf-empty-row\">\x3ctd colspan=\"5\">Sin archivos cargados para este año\x3c/td>\x3c/tr>';\n } else {\n rows.forEach(function(f, i) {\n if (!f) return;\n\n var authorHtml =\n '\x3ctd class=\"odf-author-cell\">' +\n '\x3cspan class=\"odf-author-label\">Subido por\x3c/span>' +\n escHtml(shortUser(f.createdBy)) +\n '\x3c/td>';
1565\n\n var modHtml = '\x3ctd class=\"odf-mod-cell\">';\n if (f.modifiedBy) {\n modHtml += '\x3cspan class=\"odf-author-label\">Modificado por\x3c/span>' + escHtml(shortUser(f.modifiedBy));\n } else {\n modHtml += '\x3cspan style=\"color:#e5d9cc;\">â\x3c/span>';\n }\n modHtml += '\x3c/td>';\n\n var actionsHtml = isAdmin\n ? ('\x3cdiv class=\"odf-actions-cell\">' +\n '\x3cbutton class=\"odf-edit-btn\" onclick=\"odfEditFile(' + year + ',' + i + ')\" title=\"Editar\">âï¸\x3c/button>' +\n '\x3cbutton class=\"odf-delete-btn\" onclick=\"odfDeleteFile(' + year + ',' + i + ')\" title=\"Eliminar\">â\x3c/button>' +\n '\x3c/div>')\n : '';\n\n rowsHtml +=\n '\x3ctr>' +\n '\x3ctd class=\"odf-col-name\">\x3ca class=\"odf-file-link\" href=\"' + escHtml(f.link) + '\" target=\"_blank\" rel=\"noopener\">📄 ' + escHtml(f.name || '(sin nombre)') + '\x3c/a>\x3c/td>' +\n '\x3ctd class=\"odf-col-date odf-date-cell\">' + fmt(f.date) + '\x3c/td>' +\n authorHtml +\n modHtml +\n '\x3ctd class=\"odf-col-acts\">' + actionsHtml + '\x3c/td>' +\n '\x3c/tr>';\n });\n }\n\n html +=\n '\x3cdiv class=\"odf-year-block\">' +\n '\x3cdiv class=\"odf-year-header\">' +\n '\x3cspan class=\"odf-year-pill\">' + year + '\x3c/span>' +\n '\x3cdiv class=\"odf-year-line\">\x3c/div>' +\n '\x3c/div>' +\n '\x3cdiv class=\"odf-table-wrapper\">' +\n '\x3ctable class=\"odf-table\">' +\n '\x3cthead>\x3ctr>' +\n '\x3cth class=\"odf-col-name\">Nombre de archivo\x3c/th>' +\n '\x3cth class=\"odf-col-date\">Fecha\x3c/th>' +\n '\x3cth class=\"odf-col-author\">Subido por\x3c/th>' +\n '\x3cth class=\"odf-col-mod\">Modificado por\x3c/th>' +\n '\x3cth class=\"odf-col-acts\">\x3c/th>' +\n '\x3c/tr>\x3c/thead>' +\n '\x3ctbody>' + rowsHtml + '\x3c/tbody>' +\n '\x3c/table>' +\n '\x3c/div>' +\n '\x3c/div>';\n });\n\n app.innerHTML = html;\n}\n\nwindow.odfOpenModal = function() {\n if (!isAdmin) return;\n editTarget = null;\n document.getElementById('odf-modal-title').textContent = 'Agregar archivo';\n document.getElementById('odf-input-name').value = '';\n document.getElementById('odf-input-link').value = '';\n document.getElementById('odf-input-date').value = new Date().toISOString().split('T')[0];\n clearErrors();\n document.getElementById('odf-overlay').classList.remove('odf-hidden');\n};\n\nwindow.odfEditFile = function(year, idx) {\n if (!isAdmin) return;\n var f = data[year] && data[year][idx];\n if (!f) return;\n\n editTarget = { year: year, idx: idx };\n document.getElementById('odf-modal-title').textContent = 'Editar archivo';\n document.getElementById('odf-input-name').value = f.name || '';\n document.getElementById('odf-input-link').value = f.link || '';\n document.getElementById('odf-input-date').value = f.date || '';\n clearErrors();\n document.getElementById('odf-overlay').classList.remove('odf-hidden');\n};\n\nwindow.odfCloseModal = function() {\n document.getElementById('odf-overlay').classList.add('odf-hidden');\n};\n\nfunction clearErrors() {\n ['odf-err-name','odf-err-link','odf-err-date'].forEach(function(id) {\n document.getElementById(id).classList.add('odf-hidden');\n });\n ['odf-input-name','odf-input-link','odf-input-date'].forEach(function(id) {\n document.getElementById(id).classList.remove('odf-input-error');\n });\n}\n\nwindow.odfSaveFile = function() {\n if (!isAdmin) return;\n var name = document.getElementById('odf-input-name').value.trim();\n var link = document.getElementById('odf-input-link').value.trim();\n var date = document.getElementById('odf-input-date').value;\n var ok = true;\n\n clearErrors();\n\n if (!link || !link.startsWith('http')) {\n document.getElementById('odf-err-link').classList.remove('odf-hidden');\n document.getElementById('odf-input-link').classList.add('odf-input-error');\n ok = false;\n }\n if (!date) {\n document.getElementById('odf-err-date').classList.remove('odf-hidden');\n document.getElementById('odf-input-date').classList.add('odf-input-error');\n ok = false;\n }\n if (!ok) return;\n\n var currentUser = auth.currentUser ? auth.currentUser.email : 'admin';\n var fileYear = parseInt(date.split('-')[0]);\n if (!data[fileYear]) data[fileYear] = [];\n if (years.indexOf(fileYear) === -1) years.push(fileYear);\n\n if (editTarget !== null) {\n var oldYear = parseInt(editTarget.year);\n var oldIdx = editTarget.idx;\n var oldFile = data[oldYear][oldIdx] || {};\n var updatedFile = {\n name: name,\n date: date,\n link: link,\n createdBy: oldFile.createdBy || currentUser,\n createdAt: oldFile.createdAt || '',\n modifiedBy: currentUser,\n modifiedAt: new Date().toISOString()\n };\n\n if (oldYear === fileYear) {\n data[fileYear][oldIdx] = updatedFile;\n } else {\n data[oldYear].splice(oldIdx, 1);\n data[fileYear].push(updatedFile);\n }\n } else {\n data[fileYear].push({\n name: name,\n date: date,\n link: link,\n createdBy: currentUser,\n createdAt: new Date().toISOString(),\n modifiedBy: null,\n modifiedAt: null\n });\n }\n\n saveData(function() { odfCloseModal(); });\n};\n\nwindow.odfDeleteFile = function(year, idx) {\n if (!isAdmin) return;\n if (!confirm('¿Eliminar este archivo?')) return;\n var removed = data[year][idx];\n data[year].splice(idx, 1);
1565\n saveData(function() {\n if (removed) {\n trashRef.push({\n year: year,\n file: removed,\n deletedBy: auth.currentUser ? auth.currentUser.email : 'admin',\n deletedAt: new Date().toISOString()\n });\n }\n });\n};\n\n/* ================= PAPELERA / AUDITORÃA ================= */\nvar trashEntries = {};\n\n/* ===== Textos propios que no deben quedar en manos de la traducción automática ===== */\nfunction piCurrentLang() {\n return (document.documentElement.lang === 'en') ? 'en' : 'es';\n}\nfunction piApplyLangOverrides() {\n var lang = piCurrentLang();\n var trashLbl = document.getElementById('pi-trash-btn-label');\n if (trashLbl) trashLbl.textContent = (lang === 'en') ? 'View Recycle Bin' : 'Ver papelera';\n}\npiApplyLangOverrides();\nnew MutationObserver(piApplyLangOverrides).observe(document.documentElement, { attributes: true, attributeFilter: ['lang', 'class'] });\n\nfunction fmtDateTime(iso) {\n if (!iso) return 'â';\n var d = new Date(iso);\n if (isNaN(d.getTime())) return iso;\n return d.toLocaleDateString('es-AR') + ' ' + d.toLocaleTimeString('es-AR', { hour: '2-digit', minute: '2-digit' });\n}\n\nwindow.piOpenTrash = function() {\n if (!isAdmin) return;\n document.getElementById('pi-trash-overlay').classList.remove('odf-hidden');\n piLoadTrash();\n};\n\nwindow.piCloseTrash = function() {\n document.getElementById('pi-trash-overlay').classList.add('odf-hidden');\n};\n\ndocument.getElementById('pi-trash-overlay').addEventListener('click', function(e) {\n if (e.target === this) window.piCloseTrash();\n});\n\nfunction piLoadTrash() {\n var list = document.getElementById('pi-trash-list');\n list.innerHTML = '\x3cdiv class=\"odf-loading\">Cargando...\x3c/div>';\n trashRef.once('value').then(function(snap) {\n var val = snap.val() || {};\n var entries = Object.keys(val).map(function(k) { var e = val[k]; e._key = k; return e; });\n entries.sort(function(a, b) { return (b.deletedAt || '').localeCompare(a.deletedAt || ''); });\n trashEntries = {};\n entries.forEach(function(e) { trashEntries[e._key] = e; });\n renderTrashList(entries);\n }, function(err) {\n list.innerHTML = '\x3cp style=\"text-align:center;color:#b91c1c;padding:1.5rem 0;\">No fue posible cargar la información de la papelera. Intente nuevamente más tarde.\x3c/p>';\n console.error(err);\n });\n}\n\nfunction renderTrashList(entries) {\n var list = document.getElementById('pi-trash-list');\n if (entries.length === 0) {\n list.innerHTML = '\x3cp style=\"text-align:center;color:#6b7280;padding:1.5rem 0;\">La papelera se encuentra vacÃa. No hay archivos eliminados registrados.\x3c/p>';\n return;\n }\n var html =\n '\x3cdiv class=\"odf-table-wrapper\">' +\n '\x3ctable class=\"odf-table\">' +\n '\x3cthead>\x3ctr>' +\n '\x3cth class=\"odf-col-name\">Nombre del archivo\x3c/th>' +\n '\x3cth class=\"odf-col-date\">Año\x3c/th>' +\n '\x3cth class=\"odf-col-author\">Usuario responsable\x3c/th>' +\n '\x3cth class=\"odf-col-mod\">Fecha de eliminación\x3c/th>' +\n '\x3cth class=\"odf-col-acts\">\x3c/th>' +\n '\x3c/tr>\x3c/thead>\x3ctbody>';\n entries.forEach(function(e) {\n var f = e.file || {};\n html +=\n '\x3ctr>' +\n '\x3ctd class=\"odf-col-name\">' + escHtml(f.name || '(sin nombre)') + '\x3c/td>' +\n '\x3ctd class=\"odf-col-date odf-date-cell\">' + e.year + '\x3c/td>' +\n '\x3ctd class=\"odf-author-cell\">' + escHtml(shortUser(e.deletedBy)) + '\x3c/td>' +\n '\x3ctd class=\"odf-mod-cell\">' + fmtDateTime(e.deletedAt) + '\x3c/td>' +\n '\x3ctd class=\"odf-col-acts\">' +\n '\x3cbutton class=\"odf-btn-primary\" style=\"padding:0.35rem 0.9rem;font-size:0.8rem;\" onclick=\"piRestoreTrashItem(\\'' + e._key + '\\')\">Restaurar\x3c/button>' +\n '\x3c/td>' +\n '\x3c/tr>';\n });\n html += '\x3c/tbody>\x3c/table>\x3c/div>';\n list.innerHTML = html;\n}\n\nwindow.piRestoreTrashItem = function(key) {\n if (!isAdmin) return;\n var e = trashEntries[key];\n if (!e) return;\n var y = parseInt(e.year);\n if (!data[y]) data[y] = [];\n if (years.indexOf(y) === -1) years.push(y);\n data[y].push(e.file);
1565\n saveData(function() {\n trashRef.child(key).remove().then(function() { piLoadTrash(); });\n });\n};\n\n/* ================= GESTIÃN DE USUARIOS ================= */\nfunction piTempPassword() {\n var arr = new Uint8Array(24);\n crypto.getRandomValues(arr);\n return Array.prototype.map.call(arr, function(b) { return b.toString(36); }).join('').slice(0, 24) + 'Aa1!';\n}\n\nfunction piActionLabel(action) {\n if (action === 'created') return 'Cuenta creada';\n if (action === 'reset_resent') return 'Acceso reenviado';\n return 'Sin registro';\n}\n\nfunction bindPortalUsers() {\n usersRef.on('value', function(snapshot) {\n var val = snapshot.val() || {};\n var list = Object.keys(val).map(function(k) { var u = val[k]; u._key = k; return u; });\n list.sort(function(a, b) { return (b.createdAt || '').localeCompare(a.createdAt || ''); });\n renderPortalUsers(list);\n }, function(err) {\n var el = document.getElementById('pi-admin-users-list');\n if (el) el.innerHTML = '\x3cp style=\"text-align:center;color:#b91c1c;padding:1rem 0;\">No fue posible cargar el listado de usuarios.\x3c/p>';\n console.error(err);\n });\n}\n\nfunction renderPortalUsers(list) {\n var el = document.getElementById('pi-admin-users-list');\n if (!el) return;\n if (list.length === 0) {\n el.innerHTML = '\x3cp style=\"text-align:center;color:#6b7280;padding:1rem 0;\">TodavÃa no se registraron usuarios desde este panel.\x3c/p>';\n return;\n }\n var html =\n '\x3cdiv class=\"odf-table-wrapper\">' +\n '\x3ctable class=\"odf-table\">' +\n '\x3cthead>\x3ctr>' +\n '\x3cth class=\"odf-col-name\">Correo electrónico\x3c/th>' +\n '\x3cth class=\"odf-col-date\">Fecha de alta\x3c/th>' +\n '\x3cth class=\"odf-col-mod\">Ãltima acción\x3c/th>' +\n '\x3c/tr>\x3c/thead>\x3ctbody>';\n list.forEach(function(u) {\n html +=\n '\x3ctr>' +\n '\x3ctd class=\"odf-col-name\">' + escHtml(u.email || 'â') + '\x3c/td>' +\n '\x3ctd class=\"odf-col-date odf-date-cell\">' + fmtDateTime(u.createdAt) + '\x3c/td>' +\n '\x3ctd class=\"odf-mod-cell\">' + escHtml(piActionLabel(u.lastAction)) + ' · ' + fmtDateTime(u.lastActionAt) + '\x3c/td>' +\n '\x3c/tr>';\n });\n html += '\x3c/tbody>\x3c/table>\x3c/div>';\n el.innerHTML = html;\n}\n\nfunction piTrackExistingUser(email, nowIso) {\n return usersRef.orderByChild('email').equalTo(email).once('value').then(function(snap) {\n var val = snap.val();\n if (val) {\n var key = Object.keys(val)[0];\n return usersRef.child(key).update({ lastAction: 'reset_resent', lastActionAt: nowIso });\n }\n var fallbackKey = email.replace(/[.#$\\[\\]\\/]/g, '_');\n return usersRef.child(fallbackKey).set({\n email: email,\n createdAt: nowIso,\n lastAction: 'reset_resent',\n lastActionAt: nowIso\n });\n });\n}\n\nwindow.piAdminAddUser = function() {\n if (!isAdmin) return;\n var emailInput = document.getElementById('pi-admin-user-email');\n var msg = document.getElementById('pi-admin-user-msg');\n var btn = document.getElementById('pi-admin-user-btn');\n var email = emailInput.value.trim();\n var nowIso = new Date().toISOString();\n\n msg.textContent = '';\n\n if (!email || email.indexOf('@') === -1) {\n msg.textContent = 'Ingrese un correo electrónico válido.';\n msg.style.color = '#b91c1c';\n return;\n }\n\n btn.disabled = true;\n btn.textContent = 'Procesando...';\n\n var secondaryApp = firebase.apps.some(function(a) { return a.name === 'Secondary'; })\n ? firebase.app('Secondary')\n : firebase.initializeApp(firebase.app().options, 'Secondary');\n var secondaryAuth = secondaryApp.auth();\n\n secondaryAuth.createUserWithEmailAndPassword(email, piTempPassword())\n .then(function(cred) {\n var uid = cred.user.uid;\n return secondaryAuth.signOut()\n .then(function() { return auth.sendPasswordResetEmail(email); })\n .then(function() {\n return usersRef.child(uid).set({\n email: email,\n createdAt: nowIso,\n lastAction: 'created',\n lastActionAt: nowIso\n });\n });\n }
1565)\n .then(function() {\n msg.textContent = 'Cuenta creada correctamente. Se envió un correo electrónico a ' + email + ' para que establezca su contraseña.';\n msg.style.color = '#166534';\n emailInput.value = '';\n })\n .catch(function(error) {\n if (error && error.code === 'auth/email-already-in-use') {\n auth.sendPasswordResetEmail(email)\n .then(function() { return piTrackExistingUser(email, nowIso); })\n .then(function() {\n msg.textContent = 'Ya existe una cuenta registrada con este correo electrónico. Se reenvió el correo para restablecer la contraseña.';\n msg.style.color = '#166534';\n emailInput.value = '';\n })\n .catch(function(err2) {\n msg.textContent = 'No fue posible reenviar el correo electrónico: ' + (err2 && err2.message ? err2.message : 'error desconocido.');\n msg.style.color = '#b91c1c';\n });\n } else {\n msg.textContent = 'Ocurrió un error: ' + (error && error.message ? error.message : 'error desconocido.');\n msg.style.color = '#b91c1c';\n }\n })\n .finally(function() {\n btn.disabled = false;\n btn.textContent = 'Agregar y enviar acceso';\n });\n};\n\n\x3c/script>\n","margin":{"marginTop":0,"marginLeft":0,"marginRight":0,"marginBottom":0},"textAlign":"center","appearance":{"mobile":true,"desktop":true},"mobileMargin":{"marginTop":0,"marginLeft":0,"marginRight":0,"marginBottom":0}}},"seo":{"title":"","index":true},"globalSettings":[],"isTemplate":false},"files":{},"management":{"activePopupId":null,"previewMode":false,"screenshotMode":false,"funnelStepId":"25446598","url":"https://www.opanal.org/portal-interno","confirmedExplicitConsents":[],"isDesktop":null,"affiliateId":"%CONTACT_AFFILIATE_ID%","isMobile":"","affiliateLink":"https://systeme.io/?sa=sa0259689512b793c9b414d8f57668b2a117e56e01","agreement":"%AGREEMENT%","isFreemiumUser":"","captcha":"%CAPTCHA_OPEN_KEY%","visitorCountry":null},"optIn":{"customerFields":"%CUSTOMER_FIELDS%","fields":{},"availableCountries":"%AVAILABLE_COUNTRIES%","errors":{"common":[],"fields":{},"bookingFields":{},"paidBookingFields":{}},"bookingFields":{},"paidBookingFields":{},"success":false,"submitted":false,"customerCountry":"US","nextStepUrl":"https://www.opanal.org/default-funnel-step-thank-you-page/7602834","surveyResults":null,"submitedRecaptchas":[],"optInRecaptchaError":{},"bookingRedirectUrl":"","paidBookingRedirectUrl":""},"webinar":{"timeStamp":"%WEBINAR_SESSION_TIMESTAMP%","url":"%WEBINAR_SESSION_LINK%"},"webinarSession":{"timeStamp":"%WEBINAR_SESSION_TIMESTAMP%"},"payment":{"customerType":"%CUSTOMER_TYPE%","customerEmail":"%CUSTOMER_EMAIL%","paymentMethods":"%PAYMENT_METHODS%","isOnlyPersonalAvailable":"%IS_ONLY_PERSONAL_AVAILABLE%","offer":"%OFFER%","checkedPlanId":"%OFFER_PRICE_PLAN_ACTIVE%","customerPaymentMethod":"%CUSTOMER_PAYMENT_METHOD%","offerOwnerCountry":"%OFFER_OWNER_COUNTRY%","offerBumps":"%OFFER_BUMPS%","offerBump":"%OFFER_BUMP%","offerPricing":[],"checkedBumpsIds":[],"isOrderBumpChecked":false,"agreement":"%AGREEMENT%","couponCode":"","checkedCoupon":null,"pageId":"44408366","affiliateLink":"https://systeme.io/?sa=sa0259689512b793c9b414d8f57668b2a117e56e01","stripeAccountId":"%STRIPE_ACCOUNT_ID%","purchaseProcessId":"%PURCHASE_PROCESS_ID%","twoStepPaymentFormStepType":"STEP_OPT_IN","deadlineTime":"%DEADLINE_TIMESTAMP%","deadlineExpirationUrl":"%DEADLINE_EXPIRATION_URL%","downsellUrl":"%DOWNSELL_URL%","mercadoPagoPublicKey":"%MERCADO_PAGO_PUBLIC_KEY%","product":"%PRODUCT%","digitalProduct":null,"productQuantity":1,"shipping":null,"productActiveVariant":null,"cashOnDeliveryInstruction":"%CASH_ON_DELIVERY_INSTRUCTION%","xenditPublicKey":"%XENDIT_PUBLIC_KEY%","stripePaymentMethod":""},"offerThankYou":{"orderSummary":"%ORDER_SUMMARY%"},"lecture":{"lectureSessionId":null,"lectureSessionLoggingEnabled":"%LECTURE_SESSION_LOGGING_ENABLED%","lectureId":"%LECTURE_ID%"},"blog":{"blogPostListing":"%BLOG_POST_LISTING%","blogPostTitle":"%BLOG_POST_TITLE%","blogPostDescription":"%BLOG_POST_DESCRIPTION%","blogPostImageUrl":"%BLOG_POST_IMAGE_URL%","blogPostDateTs":"%BLOG_POST_DATE_TS%","blogPostCategories":"%BLOG_POST_CATEGORIES%","blogPath":"%BLOG_PATH%","blogLayoutPageId":"%BLOG_LAYOUT_PAGE_ID%","blogCategoryTitle":"%BLOG_CATEGORY_TITLE%","blogCategoryDescription":"%BLOG_CATEGORY_DESCRIPTION%","blogSearch":[]},"websiteBlog":{"post":null,"blogPath":null,"blogId":null},"websiteSettings":{"websiteLayouts":[],"websiteDraftTheme":null}}</script>
1565<script data-cookieconsent="ignore" charSet="UTF-8">window.initialI18nStore={"es":{"common":{"components":{"countdown":{"types":{"date":"Fecha y hora fijas","minute":"Retraso","daily":"Diario","deadline":"Igual que la configuración de fecha lÃmite del túnel"}},"button":{"actions":{"next_step_redirection":"URL de la siguiente etapa"}},"physical_product":{"quantity_label":"Cantidad"},"coupon":{"discount":"Ahorras"},"breadcrumbs":{"items":{"demo_blog_post_category_name":"CategorÃa","demo_blog_post_name":"Entrada de blog"}},"search":{"settings":{"placeholder":{"label":"Marcador de posición"},"open_dropdown":{"label":"Ver resultados"},"search_bar":{"title":"Barra de búsqueda"},"dropdown_title":{"title":"TÃtulo"},"dropdown_text":{"title":"Texto"},"dropdown_see_more":{"title":"Ver más"},"dropdown_group":{"title":"Configuración de los resultados"},"button":{"title":"Botón de búsqueda"}}},"website_layout_body":{"content_placeholder":"Contenido del sitio web"},"website_logo":{"settings":{"height":{"label":"Altura del logo"},"link":{"title":"Enlace","tooltip":"Elige el destino de redirección al hacer clic en el logo","homepage":"Página de inicio","custom_url":"URL personalizada"}}},"website_header_search":{"settings":{"open_search_results":{"label":"Configuración de búsqueda y resultados"},"search_results":{"label":"Configuración de búsqueda y resultados"}}}},"core":{"error":{"title":"¡Algo ha salido mal!"},"errors":{"no_connection":"Verifica tu conexión a Internet e intenta de nuevo","something_went_wrong":"Algo salió mal. Intenta de nuevo más tarde"},"file_manager":{"upload":{"drag_file":"Arrastrar un archivo o"}}},"validation":{"expiration_invalid":"La fecha de expiración no es válida","errors":{"form_field_should_not_be_empty":"Este valor no debe estar vacÃo"},"page":{"calendar":{"event_not_selected":"Selecciona un evento para ser desplegado en la página pública"},"paid_calendar":{"remove_payment_button":"El calendario de pago tiene un botón de pago integrado. Elimina el botón de pago innecesario","one_element":"Solo se puede insertar un calendario de pago a la página","paid_calendar_required":"Es necesario el calendario de pago"},"payment_button_required":"El botón de pago es necesario en las páginas de pago","search_results_unique":"Solo un elemento de resultados de búsqueda puede estar en la página","search_results_required":"El elemento \"resultados de búsqueda\" es obligatorio"},"password":{"mismatch":"Las contraseñas no coinciden"}},"entities":{"field":{"first_name":{"default_placeholder":"Nombre"},"email":{"default_placeholder":"Correo"}},"paid_calendar":{"example_warning":"Este es un evento de ejemplo. Por favor, selecciona un evento en la configuración de la página"},"member_access":{"create_account":{"default_headline":"Crea tu cuenta ahora"},"registration":{"button_text":"Clic aquÃ"},"confirm_registration":{"default_headline":"Confirmar el registro"}},"website_login":{"2fa":{"default_headline":"","default_sub_headline":"El código de verificación ha sido enviado a tu correo","verification_code_label":"Código de verificación","default_checkbox":"Confiar en este dispositivo","different_email":"Ingresa con una dirección de correo diferente"}}},"settings_options":{"checkbox_message":"Mensaje si la casilla no se marca"},"global":{"search":"Buscar","cancel":"Cancelar","new":"Nuevo"},"entity_settings":{"phone":{"title":"Teléfono"},"menu":{"item":{"about_placeholder":"Nosotros","how_it_works_placeholder":"Cómo funciona","member_stories_placeholder":"Historias de los miembros"}},"button":{"button_text":{"label":"Texto del botón"},"send_form":{"no_redirection":{"title":"Texto luego del registro exitoso"}}},"image":{"link":"Enlace"},"section":{"content_position":{"label":"Posición del contenido"}},"price_element":{"first_plan":"Plan gratuito","second_plan":"Plan Startup mensual","second_plan_annual":"Plan Startup anual","third_plan":"Plan Webinar mensual","third_plan_annual":"Plan Webinar anual","fourth_plan":"Plan Ilimitado mensual","fourth_plan_annual":"Plan Ilimitado anual","custom_plan":"Plan personalizado","show_custom_plan":"Mostrar tarjeta de plan personalizado"},"attach_file":{"header":"Adjuntar archivo","uploaded_state":"Personalizar el estado cargado\n\n","default_state":{"text":{"label":"Texto"}}},"websiteheadersearch":{"header":"Búsqueda"}},"settings_styles":{"size_and_position":{"label":"Tamaño y posición"},"primary_color":{"label":"Color primario"}},"website_theme_settings":{"group":{"form_field":{"border_color":"Borde del campo de formulario"},"primary":{"button_border_color":"Borde del botón principal"},"secondary":{"button_border_color":"Borde del botón secundario"},"content":{"background_color":"Fondo del contenido"},"ghost":{"button_border_color":"Borde del botón fantasma"}}},"website_settings":{"sidebar":{"page_settings":{"advanced":{"title":"Código personalizado","tracking_code":"Código personalizado (en \x3chead>)","tracking_code_info":"Este código se inserta en la etiqueta HTML. Ãsalo para pÃxeles de seguimiento, análisis y metaetiquetas. No lo uses para contenido visual en el encabezado"},"url_readonly_hint":"La URL de esta página se genera automáticamente y no se puede editar"},"logo":{"description":"Los logos reemplazan el tÃtulo del sitio web en todas las páginas. Para volver a mostrar el tÃtulo del sitio web, elimina la imagen","mobile_image":"Logo para móvil","text_color":"Color del texto del logo","add_text":"Agregar texto"},"website_header":{"sticky":"Encabezado fijo"},"new_theme":"Nuevo tema","language_switcher":{"text_color":"Color para el selector de idioma"},"blog":{"categories":{"no_results":"No se encontraron categorÃas"}}},"pages_management":{"unsaved_modal":{"title":"¿Descartar los cambios?","description":"Si sales ahora, los cambios en esta página serán eliminados de forma permanente ¿Deseas continuar?","save_button":"Guardar y salir de la página"}},"login":{"slug":{"code":"Código"}}},"website_styles_settings":{"buttons_and_links":{"style":{"filled":"Relleno","outlined":"Contorneado","title":"Estilo"},"primary":{"title":"Primario"},"secondary":{"title":"Secundario"}},"text_example":"Texto de ejemplo","colors":{"label":"Colores"}},"settings":{"0":"Configuración","sidebar":{"customize":"Personalizar"}},"website":{"page_types":{"website_login":"Página de inicio de sesión"}},"pages_management":{"utilities":"Herramientas","public_pages":{"tooltip":"Esta página puede editarse en la configuración de dominios personalizados"}},"1px":"1px","2px":"2px","3px":"3px","5px":"5px","Bottom":"Inferior","Center":"Centrar","Open in new window":"Abrir en una ventana nueva","Open in same window":"Abrir en la misma ventana","Repeat":"Repetir","Top":"Arriba","at":"en","border":"Borde","bottom":"Inferior","button":"Botón","column":"Columna","dashed":"Rayado","day":"DÃa","delay":"Retraso antes de visualizar el elemento","dotted":"Punteado","height":"Altura","language":"Idioma","month":"Mes","none":"Ninguno","padding":"Padding","placeholder":"Marc
1565ador de posición","redirect":"Redirigir","remove":"Eliminar","solid":"Sólido","style":"estilo","subscription":"suscripción","text":"Texto","top":"Arriba","type":"tipo","week":"semana","year":"año","INLINE":"En lÃnea","No Repeat":"No repetir","None":"Ninguno","POPUP":"Ventana emergente","Repeat Horizontally":"Repetir horizontalmente","Repeat Horizontally - Bottom":"Repetir horizontalmente - abajo","Repeat Horizontally - Top":"Repetir horizontalmente - arriba","Repeat Vertically":"Repetir verticalmente","10px":"10px","actions":{"view_live":"Ver página en vivo"}},"publisher":{"locale_name":{"english":"Inglés","french":"Francés","spanish":"Español","italian":"Italiano","portuguese":"Portugués","german":"Alemán","dutch":"Holandés","russian":"Ruso","japanese":"Japonés","arabic":"Ãrabe","turkish":"Turco","chinese":"Chino","swedish":"Sueco","romanian":"Rumano","czech":"Checo","hungarian":"Húngaro","slovak":"Eslovaco","danish":"Danés","indonesian":"Indonesio","polish":"Polaco","greek":"Griego","serbian":"Serbio","hindi":"Hindi","norwegian":"Noruego","thai":"Tailandés","slovene":"Esloveno","ukrainian":"Ucraniano","albania":"Albanés"},"validation":{"not_empty":"Este campo es necesario","email_invalid":"Debes ingresar una dirección de correo válida","check_card_data":"Tu tarjeta no pudo ser validada. Revisa el número de la tarjeta, la fecha de expiración y el código CVC","cvc_invalid":"El código CVC no es válido","expiration_invalid":"La fecha de expiración no es válida","identification_number_invalid":"Debes ingresar un número de identificación válido","card_number_invalid":"Debes ingresar un número de tarjeta válido","errors":{"form_field_should_not_be_empty":"Este valor no debe estar vacÃo"},"cardholder_name_invalid":"El nombre del titular de la tarjeta no es válido","page":{"calendar":{"event_not_selected":"Selecciona un evento para ser desplegado en la página pública"}},"password":{"mismatch":"Las contraseñas no coinciden"}},"components":{"preview":{"warning":"Este es el modo de vista previa. No utilices esta URL"},"entities":{"blog_post_content_placeholder":{"placeholder":"Espacio para el contenido de la entrada del blog"}},"payment_methods":{"square":{"consent_text":"Autorizo el almacenamiento de los datos de mi tarjeta para futuros pagos","consent_required":"Para continuar, debes aceptar el almacenamiento de los datos de la tarjeta"}},"search":{"settings":{"placeholder":{"label":"Marcador de posición"}}}},"entities":{"field":{"country":{"placeholder":"Selecciona un paÃs"}},"member_access":{"create_account":{"default_headline":"Crea tu cuenta ahora"},"registration":{"button_text":"Clic aquÃ"}},"login_button":{"default_text":"Iniciar sesión"},"registration_button":{"default_text":"Registro"},"website_login":{"2fa":{"default_sub_headline":"El código de verificación ha sido enviado a tu correo","verification_code_label":"Código de verificación","default_checkbox":"Confiar en este dispositivo","different_email":"Ingresa con una dirección de correo diferente"}}},"core":{"error":{"title":"¡Algo ha salido mal!"},"errors":{"no_connection":"Verifica tu conexión a Internet e intenta de nuevo","went_wrong_contact_support":"Algo salió mal. Contacta al servicio de soporte","something_went_wrong":"Algo salió mal. Intenta de nuevo más tarde","stripe_data_error":"Stripe no pudo recuperar la información de tu tarjeta de crédito. Contacta a nuestro servicio de soporte","stripe_invalid_request_error":"Tu cuenta de Stripe tiene capacidades restringidas y es posible que no todos los métodos de pago estén disponibles. Revisa la configuración del panel de Stripe","bad_request":"Algo salió mal. Verifica que todos los campos estén diligenciados correctamente"}},"settings_options":{"checkbox_message":"Mensaje si la casilla no se marca"},"global":{"search":"Buscar","cancel":"Cancelar","new":"Nuevo"},"entity_settings":{"phone":{"title":"Teléfono"},"menu":{"item":{"about_placeholder":"Nosotros","how_it_works_placeholder":"Cómo funciona","member_stories_placeholder":"Historias de los miembros"}},"button":{"button_text":{"label":"Texto del botón"}}},"page Not Found":"Página no encontrada","expiration":"Fecha de expiración","keywords":"Palabras clave","none":"Ninguno","subscription":"suscripción","text":"Texto","type":"tipo","website_public_page":{"captcha":{"retry_button_text":"Inténtalo de nuevo"}}}}}</script>
1565<script data-cookieconsent="ignore" charSet="UTF-8">window.initialLanguage="es"</script>
1565<script data-cookieconsent="ignore" src="https://d3fit27i5nzkqh.cloudfront.net/sales/runtime.07d322e8e6dc6bb9.js" async=""></script>
1565<script data-cookieconsent="ignore" src="https://d3fit27i5nzkqh.cloudfront.net/sales/page.b80ffe0bbf052e78.js" async=""></script>
1565<script data-cookieconsent="ignore" src="https://d3fit27i5nzkqh.cloudfront.net/sales/vendors.b83191bb6408f3dc.js" async=""></script>
1565</body></html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.