/* =====================================================================
   flow/assets/css/style.css
   Sistema visual de FLOW — mobile-first, adaptado a escritorio dentro
   de un contenedor tipo "viewport de app" centrado.
   ===================================================================== */

:root{
  --primary:#1858E0;
  --primary-dark:#0F3FAE;
  --primary-soft:#E7EFFE;
  --violet:#6C3FD9;
  --orange:#F5760F;
  --orange-dark:#D9600A;
  --orange-soft:#FFE9D8;
  --surface:#FFFFFF;
  --bg:#F4F6FC;
  --ink:#161B26;
  --muted:#6B7280;
  --border:#E6E9F0;
  --green:#22B573;
  --green-dark:#149963;
  --green-soft:#E7F7EC;
  --gold:#F5B400;
  --silver:#AEB8C4;
  --bronze:#D98B4A;
  --radius-lg:24px;
  --radius-md:16px;
  --radius-sm:12px;
  /* Degradado de cabecera compartido por Mi Camino y Perfil (Ronda 16):
     misma dirección/paradas en ambas pantallas para que se sientan parte
     del mismo sistema visual. */
  --header-gradient:linear-gradient(160deg,#1858E0 0%,#3B4FDB 55%,#6C3FD9 100%);
  font-family:'Segoe UI',Roboto,-apple-system,'Helvetica Neue',Arial,sans-serif;
}
/* Tipografía "Manrope" (Google Fonts, cargada en el <head> de index.php e
   insignia.php) para cifras y títulos — el resto del texto sigue en la
   fuente del sistema, sin depender de que la fuente externa cargue a
   tiempo (fallback a system-ui/sans-serif si la red la bloquea). */
.num,.title-num{font-family:'Manrope',system-ui,sans-serif;}

*{box-sizing:border-box;}
html,body{margin:0; padding:0; height:100%;}
body{
  background:#0F1420;
  color:var(--ink);
  -webkit-tap-highlight-color:transparent;
}
button,input{font-family:inherit;}
h1,h2,h3,p{margin:0;}
a{color:inherit; text-decoration:none;}

/* ---------------------------------------------------------------------
   Contenedor "viewport de app": en mobile ocupa toda la pantalla; en
   escritorio queda centrado dentro de un marco con fondo decorativo,
   preservando la identidad mobile-first sin verse "estirado".
   --------------------------------------------------------------------- */
.app-shell{
  position:relative;
  display:flex; flex-direction:column;
  max-width:480px;
  margin:0 auto;
  min-height:100dvh;
  background:var(--surface);
  overflow:hidden;
  box-shadow:none;
}
/* Contenedor de las 4 pantallas apiladas (Ingreso/Bienvenida/Mi Camino/
   Medallas). El bottom nav vive FUERA de screens-wrap, como hermano, para
   poder compartirse entre Mi Camino y Medallas sin duplicar el markup. */
.screens-wrap{flex:1; position:relative; overflow:hidden;}
@media (min-width:600px){
  body{
    background:
      radial-gradient(900px 600px at 15% -10%, rgba(24,88,224,.18), transparent 60%),
      radial-gradient(760px 520px at 105% 10%, rgba(245,118,15,.15), transparent 60%),
      #10131F;
    display:flex; align-items:center; justify-content:center; padding:40px 0;
  }
  .app-shell{
    /* Causa real del bug de escritorio: al convertir body en un
       contenedor flex para centrar la tarjeta, .app-shell pasa de ser
       una caja de bloque normal (donde "width:auto" llena el ancho
       disponible hasta max-width) a un ITEM flex, cuyo ancho "auto" se
       calcula por defecto según el contenido intrínseco ("shrink-to-fit").
       Como todo el contenido real de .app-shell son las .screen, que
       son position:absolute (no aportan ancho intrínseco a su
       contenedor), ese cálculo colapsaba a ~0px — de ahí la línea
       vertical casi invisible que reportó el usuario. Fijar un ancho
       explícito (100%, acotado por max-width:480px ya heredado de la
       regla base) resuelve el colapso sin afectar el layout mobile,
       donde este bloque ni siquiera se aplica. */
    width:100%;
    min-height:min(860px, 92vh);
    height:min(860px, 92vh);
    border-radius:36px;
    box-shadow:0 40px 90px -20px rgba(0,0,0,.55), 0 0 0 10px rgba(255,255,255,.04);
  }
}

.screen{
  position:absolute; inset:0;
  display:flex; flex-direction:column;
  background:var(--surface);
  animation:screen-in .28s ease both;
}
.screen[hidden]{display:none;}
@keyframes screen-in{from{opacity:0; transform:translateY(8px);} to{opacity:1; transform:translateY(0);}}

/* ============ SCREEN: INGRESO ============ */
#screen-ingreso{
  align-items:center; justify-content:center; padding:0 32px; text-align:center;
  background:#fff;
}
.ingreso-blob{position:absolute; border-radius:50%; pointer-events:none;}
.ingreso-blob-a{width:340px; height:340px; top:-120px; right:-120px; background:radial-gradient(circle,rgba(24,88,224,.10),transparent 70%);}
.ingreso-blob-b{width:300px; height:300px; bottom:-100px; left:-120px; background:radial-gradient(circle,rgba(245,118,15,.10),transparent 70%);}

.mark{width:60px; height:60px; border-radius:18px; background:linear-gradient(150deg,var(--primary),var(--primary-dark)); display:flex; align-items:center; justify-content:center; margin-bottom:16px; box-shadow:0 10px 22px rgba(24,88,224,.35); position:relative; z-index:2;}
.mark svg{width:30px; height:30px;}
.logo-institucional{width:auto; height:44px; margin-bottom:18px; position:relative; z-index:2;}
.wordmark{font-size:25px; font-weight:800; color:var(--ink); letter-spacing:-.6px; position:relative; z-index:2;}
.wordmark span{color:var(--orange);}
.wordmark-sub{font-size:15px; letter-spacing:-.2px; color:var(--muted); font-weight:700;}
.wordmark-sub span{color:var(--orange);}
.subtitle{font-size:13px; color:var(--muted); margin:7px 0 30px; position:relative; z-index:2;}

.form-ingreso{width:100%; position:relative; z-index:2;}
.field{width:100%; text-align:left; margin-bottom:15px;}
.field label{font-size:11.5px; font-weight:700; color:var(--muted); text-transform:uppercase; letter-spacing:.4px; display:block; margin-bottom:7px;}
.input-wrap{width:100%; padding:14px 16px; border-radius:14px; border:1.6px solid var(--border); background:#FBFCFE; display:flex; align-items:center; gap:10px; transition:border-color .15s, box-shadow .15s;}
.input-wrap:focus-within{border-color:var(--primary); background:#fff; box-shadow:0 0 0 4px var(--primary-soft);}
.input-wrap input{border:none; outline:none; background:transparent; font-size:14.5px; color:var(--ink); width:100%;}
.input-wrap input::placeholder{color:#9BA3AF;}
.hint{font-size:10.5px; color:var(--muted); margin-top:6px; line-height:1.5; text-align:left;}
.form-error{background:#FDECEC; color:#B3261E; font-size:12.5px; font-weight:600; padding:10px 14px; border-radius:12px; margin-bottom:14px; text-align:left;}
.form-ingreso.shake{animation:shake .35s ease;}
@keyframes shake{0%,100%{transform:translateX(0);}20%{transform:translateX(-6px);}40%{transform:translateX(6px);}60%{transform:translateX(-4px);}80%{transform:translateX(4px);}}

/* Honeypot anti-bot: oculto para personas, visible/rellenable solo para bots automatizados. */
.hp-field{position:absolute; left:-9999px; top:-9999px; width:1px; height:1px; overflow:hidden;}

.btn{border:none; cursor:pointer; font-weight:700; border-radius:28px; padding:15px; font-size:14.5px; width:100%; display:flex; align-items:center; justify-content:center; gap:8px; transition:transform .12s ease, filter .15s;}
.btn:active{transform:scale(.97);}
.btn-primary{background:linear-gradient(120deg,var(--primary),var(--primary-dark)); color:#fff; box-shadow:0 10px 22px rgba(24,88,224,.32); margin-top:8px;}
.btn-primary:disabled{opacity:.7; cursor:not-allowed;}
.btn-secondary{border:1.6px solid var(--primary); color:var(--primary); background:transparent;}
.btn-spinner{width:16px; height:16px; border-radius:50%; border:2.4px solid rgba(255,255,255,.5); border-top-color:#fff; animation:spin .8s linear infinite;}
.footnote{font-size:10.5px; color:var(--muted); margin-top:24px; position:relative; z-index:2;}

/* ============ SCREEN: BIENVENIDA ============ */
#screen-bienvenida{align-items:center; justify-content:flex-end; padding:0 26px 40px; text-align:center; background:linear-gradient(180deg,#EAF1FF 0%, #F7FAFF 45%, #FFFFFF 100%);}
.bienvenida-mascot{width:190px; height:230px; margin-bottom:6px; transform-origin:50% 100%;}
.bienvenida-mascot svg,.mascot-camino svg{width:100%; height:100%; display:block;}
/* Gesto de bienvenida: salto de entrada + balanceo suave en bucle, al
   estilo de los personajes de Duolingo — se activa una sola vez, al
   mostrar la mascota por primera vez (ver irABienvenida() en app.js). */
.bienvenida-mascot.animada{
  animation: bienvenida-entrada .85s cubic-bezier(.34,1.56,.64,1) both,
             bienvenida-idle 3.6s ease-in-out .9s infinite;
}
@keyframes bienvenida-entrada{
  0%{transform:translateY(46px) scale(.72) rotate(-6deg); opacity:0;}
  55%{transform:translateY(-16px) scale(1.06) rotate(4deg); opacity:1;}
  78%{transform:translateY(5px) scale(.98) rotate(-2deg);}
  100%{transform:translateY(0) scale(1) rotate(0deg);}
}
@keyframes bienvenida-idle{
  0%,100%{transform:translateY(0) rotate(0deg);}
  50%{transform:translateY(-7px) rotate(1.5deg);}
}
@media (prefers-reduced-motion: reduce){
  .bienvenida-mascot.animada{animation:none;}
}
/* Ronda 17 — "vida propia" de la mascota: respiración sutil + parpadeo
   periódico, pensados para vivir dentro del propio SVG (MASCOT_SALUDO/
   MASCOT_SALTO en app.js) mediante los grupos ".mascot-resp"/
   ".mascot-ojos" y una animación CSS de transform sobre ellos.
   RETIRADA en la corrección post-Ronda 17 (segunda vuelta): tanto la
   primera versión (transform-box:fill-box) como el intento posterior
   (transform-box:view-box) provocaron, en dispositivos reales (Chrome
   Android incluido, no solo Firefox), que el grupo ".mascot-resp"
   (brazos/torso/cabeza/casco) se separara visualmente de
   ".mascot-piernas" — el muñeco se veía "sin cuerpo", con las piezas
   apiladas sueltas en vez de superpuestas. El cálculo del origen de
   transformación de un <g> anidado dentro de un <svg> con <defs>/
   degradados hermanos resulta demasiado inconsistente entre motores de
   renderizado reales para un detalle puramente decorativo. Se optó por
   la opción más robusta: el muñeco vuelve a ser estático (sin
   respiración ni parpadeo). Las clases ".mascot-resp"/".mascot-ojos"
   se conservan en el marcado SVG (agrupan el cuerpo y los ojos por
   claridad) pero ya no llevan ninguna animación ni transform-box. */
.mascot-resp,.mascot-ojos{animation:none;}
.speech{background:#fff; border-radius:20px; padding:14px 18px; box-shadow:0 10px 24px rgba(20,30,60,.1); border:1px solid var(--border); margin-bottom:14px; position:relative;}
.speech:after{content:''; position:absolute; bottom:-8px; left:50%; transform:translateX(-50%) rotate(45deg); width:14px; height:14px; background:#fff; border-right:1px solid var(--border); border-bottom:1px solid var(--border);}
.speech h2{font-size:18px; color:var(--ink); font-weight:800; margin-bottom:3px;}
.speech p{font-size:12px; color:var(--muted);}
.spinner-row{display:flex; align-items:center; gap:10px; margin-top:4px;}
.spinner-row[hidden]{display:none;}
.spinner,.spinner-row .spinner{width:20px; height:20px; border-radius:50%; border:3px solid var(--primary-soft); border-top-color:var(--primary); animation:spin 1s linear infinite;}
.spinner-row span:last-child{font-size:11.5px; color:var(--muted); font-weight:600;}
@keyframes spin{to{transform:rotate(360deg);}}
.bienvenida-confirmar{width:100%; display:flex; flex-direction:column; gap:10px; margin-top:4px;}
.bienvenida-confirmar[hidden]{display:none;}
.btn-text-muted{background:none; border:none; color:var(--muted); font-weight:700; font-size:12.5px; padding:8px; cursor:pointer;}

/* ============ SCREEN: MI CAMINO ============ */
/* Nota: la ilustración de colinas/cielo (fondo decorativo de versiones
   anteriores) se retiró en la Ronda 16 — el nuevo lenguaje visual usa la
   cabecera con degradado azul-violeta + la tarjeta clara del camino en
   su lugar (ver .camino-header / .camino-wrap más abajo). */
/* Cabecera con degradado azul-violeta (Ronda 16): agrupa el topbar y la
   tarjeta de progreso general sobre el mismo fondo, con dos círculos
   decorativos translúcidos (mismo recurso que la cabecera de Perfil). El
   camino en sí vive debajo, en una tarjeta clara que se monta encima con
   un solape sutil (ver .camino-wrap) — así la pantalla se lee en dos
   planos, como en el lienzo de diseño aprobado. */
.camino-header{position:relative; flex-shrink:0; background:var(--header-gradient); padding:0 0 22px; overflow:hidden; z-index:2;}
.camino-header:before{content:''; position:absolute; top:-60px; right:-40px; width:220px; height:220px; border-radius:50%; background:rgba(255,255,255,.08); pointer-events:none;}
.camino-header:after{content:''; position:absolute; top:90px; left:-60px; width:160px; height:160px; border-radius:50%; background:rgba(255,255,255,.06); pointer-events:none;}
.topbar{display:flex; align-items:center; justify-content:space-between; padding:18px 18px 0; position:relative; z-index:2; gap:8px;}
.topbar-mark{width:40px; height:40px; border-radius:13px; background:#fff; box-shadow:0 6px 14px rgba(10,20,50,.18); display:flex; align-items:center; justify-content:center; flex-shrink:0; overflow:hidden;}
.topbar-mark img{width:26px; height:26px; object-fit:contain;}
.topbar-titles{display:flex; flex-direction:column; flex:1; min-width:0; line-height:1.25;}
.topbar-eyebrow{font-size:10.5px; font-weight:700; color:rgba(255,255,255,.72); text-transform:uppercase; letter-spacing:.5px;}
.topbar .title{font-size:16.5px; font-weight:800; color:#fff; max-width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-family:'Manrope',system-ui,sans-serif;}
.hours{background:rgba(255,255,255,.16); border:1px solid rgba(255,255,255,.28); color:#fff; font-size:11.5px; font-weight:800; padding:7px 12px; border-radius:100px; flex-shrink:0; font-family:'Manrope',system-ui,sans-serif;}
.topbar-actions{display:flex; align-items:center; gap:6px; flex-shrink:0;}
.voz-toggle{width:32px; height:32px; border-radius:50%; background:rgba(255,255,255,.16); border:1px solid rgba(255,255,255,.28); color:#fff; display:flex; align-items:center; justify-content:center; flex-shrink:0; cursor:pointer; font-size:14px; padding:0; line-height:1;}
.voz-toggle.muted{opacity:.55;}

/* Tarjeta de progreso general: "X de Y cursos completados" + barra —
   sustituye al fondo decorativo de colinas que tenía esta pantalla antes
   del rediseño. */
.camino-progreso{position:relative; z-index:2; margin:16px 18px 0; background:rgba(255,255,255,.14); border:1px solid rgba(255,255,255,.22); border-radius:20px; padding:14px 16px;}
.camino-progreso[hidden]{display:none;}
.camino-progreso-top{display:flex; align-items:center; justify-content:space-between; margin-bottom:9px; gap:10px;}
.camino-progreso-top span:first-child{font-size:11.5px; font-weight:700; color:rgba(255,255,255,.88);}
.camino-progreso-pct{font-size:11.5px; font-weight:800; color:#fff;}
.camino-progreso-barra{height:8px; border-radius:100px; background:rgba(255,255,255,.22); overflow:hidden;}
.camino-progreso-rellena{height:100%; border-radius:100px; background:linear-gradient(90deg,#FFC53D,var(--orange)); transition:width .4s ease;}

.lb-avatar{width:38px; height:38px; border-radius:50%; display:flex; align-items:center; justify-content:center; font-size:12px; font-weight:800; color:#fff; position:relative; border:2.5px solid #fff; box-shadow:0 3px 8px rgba(20,30,60,.18);}
.lb-avatar.gold{background:linear-gradient(150deg,#FFD35C,var(--gold));}
.lb-avatar.silver{background:linear-gradient(150deg,#D7DEE8,var(--silver));}
.lb-avatar.bronze{background:linear-gradient(150deg,#E4A876,var(--bronze));}
.lb-avatar.other{background:linear-gradient(150deg,#B9C6E8,var(--primary));}
.lb-avatar.yo{outline:2.5px solid var(--orange);}
.lb-crown{position:absolute; top:-11px; left:50%; transform:translateX(-50%); font-size:12px;}

/* ============ SCREEN: RANKING (Top 5/15/25 elegible) ============ */
.ranking-wrap{flex:1; overflow-y:auto; padding:14px 18px 24px;}
.ranking-tabs{display:flex; gap:8px; margin-bottom:14px;}
.ranking-tab{flex:1; text-align:center; font-size:12px; font-weight:800; color:var(--muted); background:var(--bg); border:1px solid var(--border); border-radius:100px; padding:9px 4px; cursor:pointer; transition:background .15s, color .15s, border-color .15s;}
.ranking-tab.active{background:linear-gradient(120deg,var(--primary),var(--primary-dark)); border-color:transparent; color:#fff; box-shadow:0 6px 14px rgba(24,88,224,.25);}
.ranking-intro{font-size:12px; color:var(--muted); margin:0 0 16px; line-height:1.5;}
.ranking-list{display:flex; flex-direction:column; gap:8px;}
.ranking-item{display:flex; align-items:center; gap:12px; background:#fff; border:1px solid var(--border); border-radius:16px; padding:10px 14px;}
.ranking-item.yo{border-color:var(--orange); background:#FFF7EF;}
.ranking-puesto{width:22px; text-align:center; font-size:13px; font-weight:800; color:var(--muted); flex-shrink:0;}
.ranking-item .lb-avatar{width:34px; height:34px; font-size:11px; flex-shrink:0;}
.ranking-nombre{flex:1; font-size:12.5px; font-weight:700; color:var(--ink); min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
.ranking-pts{font-size:11.5px; color:var(--muted); font-weight:700; flex-shrink:0;}
.ranking-yo{margin-top:14px; padding-top:14px; border-top:1px dashed var(--border);}
.ranking-yo:not([hidden]){display:flex; align-items:center; gap:12px; background:#fff; border:1.5px solid var(--orange); border-radius:16px; padding:10px 14px;}

/* Tarjeta clara que "monta" sobre la cabecera con degradado, con las
   esquinas superiores redondeadas — el camino en sí vive acá, siempre
   sobre fondo claro para que los nodos y sus degradados de color
   resalten con más contraste que sobre el degradado azul-violeta. */
.camino-wrap{flex:1; position:relative; overflow:hidden; z-index:1; background:var(--bg); border-radius:22px 22px 0 0; margin-top:-16px; box-shadow:0 -10px 24px rgba(20,30,60,.05);}
.camino-scroll{height:100%; overflow-y:auto; position:relative; scroll-snap-type:y proximity; -webkit-overflow-scrolling:touch; padding-top:14px;}
.pathsvg{position:absolute; inset:0; width:100%; z-index:1; pointer-events:none;}
.path-locked{fill:none; stroke:#D7DEEA; stroke-width:9; stroke-linecap:round; stroke-dasharray:2 16;}
.path-done{fill:none; stroke:url(#gradDone); stroke-width:10; stroke-linecap:round;}

.nodes-layer{position:relative; z-index:2; min-height:640px;}
.node-btn{position:absolute; width:56px; height:56px; border-radius:50%; display:flex; align-items:center; justify-content:center; transform:translate(-50%,-50%); box-shadow:0 10px 20px rgba(20,30,60,.22); border:3px solid #fff; color:#fff; font-size:19px; font-weight:800; cursor:pointer; scroll-snap-align:center;}
.node-btn.culminado{background:linear-gradient(150deg,#33C583,var(--green-dark));}
.node-btn.bloqueado{background:#EDEFF5; color:#9AA2B1; box-shadow:0 4px 10px rgba(20,30,60,.08);}
.node-btn.actual{background:linear-gradient(150deg,var(--primary),var(--primary-dark)); box-shadow:0 0 0 6px rgba(24,88,224,.16), 0 12px 22px rgba(15,63,174,.35); animation:pulse-actual 1.8s ease-in-out infinite; font-size:24px;}
.node-btn.en_curso{background:linear-gradient(150deg,#FFB35C,var(--orange));}
.node-btn.preview{background:#fff; border:2.5px dashed #B9C6E8; color:var(--primary); box-shadow:0 4px 12px rgba(20,30,60,.08);}
@keyframes pulse-actual{0%,100%{box-shadow:0 0 0 6px rgba(24,88,224,.16), 0 12px 22px rgba(15,63,174,.35);}50%{box-shadow:0 0 0 10px rgba(24,88,224,.10), 0 12px 22px rgba(15,63,174,.35);}}
.node-label{position:absolute; font-size:10px; font-weight:800; color:var(--ink); white-space:nowrap; transform:translate(-50%,0); background:rgba(255,255,255,.9); padding:2px 8px; border-radius:100px; pointer-events:none;}
.node-label.muted{color:var(--muted); font-weight:700;}
.node-label.actual{background:var(--primary-soft); color:var(--primary-dark);}
.node-label.preview{color:var(--primary); background:rgba(255,255,255,.9);}

/* Nota (corrección post-Ronda 17, segunda vuelta): las reglas
   ".camino-banner" (franjas de color por categoría, estilo Duolingo,
   introducidas en la Ronda 17) se retiraron por completo, junto con el
   código que las generaba en renderNodos() (assets/js/app.js) — el
   usuario las vio en un dispositivo real y pidió quitarlas. */

/* Textura decorativa de fondo del camino: un par de manchas suaves de
   color, fijas dentro de la tarjeta clara, para que la pantalla no se
   sienta gris/plana — inspirado en el estilo de Duolingo, sin usar
   ninguna imagen ni dependencia nueva (solo degradados radiales). */
.camino-wrap:before, .camino-wrap:after{content:''; position:absolute; border-radius:50%; pointer-events:none; z-index:-1;}
.camino-wrap:before{top:60px; right:-70px; width:220px; height:220px; background:radial-gradient(circle, rgba(24,88,224,.07), transparent 70%);}
.camino-wrap:after{bottom:120px; left:-80px; width:260px; height:260px; background:radial-gradient(circle, rgba(108,63,217,.06), transparent 70%);}

/* Escudo institucional en el casco de la mascota: mismo símbolo patrio
   que el favicon (assets/img/icon-32.png), con un pequeño "respiro"
   animado para que se sienta vivo y alegre en vez de un sello rígido —
   sin alterar el propio símbolo, solo el marco que lo rodea. Se define
   con transform-box:fill-box para que el pulso quede centrado en el
   escudo tanto en la pose de saludo como en la de salto, sin necesitar
   una regla distinta para cada una. */
.casco-escudo{
  transform-box:fill-box;
  transform-origin:center;
  animation:casco-escudo-pulso 2.4s ease-in-out infinite;
}
@keyframes casco-escudo-pulso{
  0%,100%{transform:scale(1);}
  50%{transform:scale(1.12);}
}

/* Tamaño del muñeco del camino — corrección post-Ronda-17 (reporte real:
   "el muñeco se muestra mal / tapa el camino"). Diagnóstico: el
   contenedor medía 96x120px y se posicionaba con un offset vertical fijo
   (antes 108px, ver MASCOT_OFFSET_Y en app.js) casi idéntico al espaciado
   entre nodos (antes 110px, ver "spacing" en renderNodos): el resultado
   era que el muñeco SIEMPRE invadía el nodo y el banner de categoría de
   la fila anterior, sin importar el navegador — no era un bug de
   renderizado sino un conflicto geométrico de diseño. Se corrigió en
   conjunto (no alcanza con tocar solo uno de los tres números):
     1. Se redujo el muñeco a 80x100px (mismo ratio 0.8 que su viewBox
        160x200, no se deforma).
     2. Se subió el "spacing" entre nodos de 110 a 140px en renderNodos.
     3. Se recalculó MASCOT_OFFSET_Y a 84px en app.js.
   Con estos tres valores el muñeco queda parado sobre su nodo sin que su
   cabeza llegue a la fila anterior. z-index:4 se mantiene por debajo del
   z-index:5 de .camino-banner (ver arriba) como resguardo adicional. */
.mascot-camino{position:absolute; width:80px; height:100px; z-index:4; filter:drop-shadow(0 14px 14px rgba(20,30,60,.28)); background-repeat:no-repeat; background-position:center; background-size:contain; pointer-events:none; transform:translateX(-50%);}
.mascot-camino.mirando-izquierda{transform:translateX(-50%) scaleX(-1);}
.mascot-camino.caminando{animation:caminar-bob .32s ease-in-out infinite;}
.mascot-camino.caminando.mirando-izquierda{animation:caminar-bob-izq .32s ease-in-out infinite;}
@keyframes caminar-bob{0%,100%{transform:translateX(-50%) translateY(0) rotate(0deg);}50%{transform:translateX(-50%) translateY(-6px) rotate(-3deg);}}
@keyframes caminar-bob-izq{0%,100%{transform:translateX(-50%) scaleX(-1) translateY(0) rotate(0deg);}50%{transform:translateX(-50%) scaleX(-1) translateY(-6px) rotate(3deg);}}

/* Globo de diálogo: aparece sobre el muñeco cuando llega a un círculo de
   vista previa (todavía sin curso real detrás, así que no hay ficha de
   detalle que abrir) — deja el gesto de "tocar un círculo" con reacción
   siempre, incluso antes de tener cursos asignados. */
.mascot-globo{
  position:absolute; transform:translate(-50%,-100%); max-width:190px;
  background:#fff; color:var(--ink); font-size:11.5px; font-weight:800; text-align:center;
  padding:9px 14px; border-radius:14px; box-shadow:0 10px 22px rgba(20,30,60,.2);
  border:1px solid var(--border); opacity:0; pointer-events:none; z-index:6;
  transition:opacity .22s ease, transform .22s ease;
}
.mascot-globo.visible{opacity:1; transform:translate(-50%,-108%);}
.mascot-globo:after{content:''; position:absolute; bottom:-6px; left:50%; transform:translateX(-50%) rotate(45deg); width:11px; height:11px; background:#fff; border-right:1px solid var(--border); border-bottom:1px solid var(--border);}

.scroll-rail{position:absolute; right:6px; top:14px; bottom:14px; width:4px; border-radius:4px; background:rgba(20,30,60,.08); z-index:8;}
.scroll-thumb{position:absolute; left:0; width:4px; height:22%; top:0; border-radius:4px; background:linear-gradient(180deg,#5B93E8,#0a58ca); transition:top .05s linear;}
.swipe-hint{position:absolute; left:50%; transform:translateX(-50%); bottom:6px; z-index:8; display:flex; flex-direction:column; align-items:center; gap:2px; opacity:.7; transition:opacity .3s; pointer-events:none;}
.swipe-hint span{font-size:8.5px; color:var(--ink); font-weight:700; background:rgba(255,255,255,.85); padding:2px 8px; border-radius:100px;}
.swipe-hint.oculto{opacity:0;}
.fade-top{position:absolute; top:0; left:0; right:0; height:26px; background:linear-gradient(180deg,rgba(233,241,255,1),rgba(233,241,255,0)); z-index:6; pointer-events:none;}
.fade-bottom{position:absolute; bottom:0; left:0; right:0; height:34px; background:linear-gradient(0deg,rgba(255,255,255,1),rgba(255,255,255,0)); z-index:6; pointer-events:none;}

.bottomnav{flex-shrink:0; height:66px; padding-bottom:env(safe-area-inset-bottom, 0); background:rgba(255,255,255,.96); backdrop-filter:blur(8px); border-top:1px solid var(--border); display:flex; align-items:stretch; justify-content:space-around; position:relative; z-index:10;}
.bottomnav[hidden]{display:none;}
.navtab{flex:1; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:3px; background:none; border:none; cursor:pointer; color:var(--muted); padding:6px 4px;}
.navtab svg{width:20px; height:20px;}
.navtab span{font-size:9.5px; font-weight:700;}
.navtab.active{color:var(--primary);}
.navtab:active{opacity:.65;}

/* ============ CONFETI (medalla nueva desbloqueada) ============ */
.confeti-contenedor{position:fixed; inset:0; pointer-events:none; z-index:999; overflow:hidden;}
.confeti-pieza{position:absolute; top:-24px; width:8px; height:14px; border-radius:2px; opacity:0; animation-name:confeti-caida; animation-timing-function:ease-in; animation-fill-mode:forwards;}
@keyframes confeti-caida{
  0%{transform:translateY(0) rotate(0deg); opacity:1;}
  100%{transform:translateY(760px) rotate(var(--giro,360deg)); opacity:0;}
}

/* ============ SCREEN: PERFIL (Ronda 16 — sustituye a "Medallas") ============
   Centraliza Resumen / Logros / Historial bajo una sola pestaña del nav
   inferior. Cabecera con degradado + avatar de iniciales, igual que la
   de Mi Camino, para que ambas pantallas se sientan del mismo sistema. */
.screen-perfil{background:var(--bg);}
/* Corrección post-Ronda 17 (tercera vuelta): el usuario insistió en que
   la cabecera degradada seguía viéndose "por encima" de las tarjetas de
   estadísticas. Las dos vueltas anteriores habían ampliado el colchón
   de espacio pero mantenían el truco de solape (.perfil-stats con
   margin-top NEGATIVO, para que las tarjetas "se asomen" sobre el borde
   inferior de la cabecera) — un recurso visual válido en sí, pero
   frágil: depende de que el alto real de la cabecera (nombre en una o
   dos líneas, métricas de Manrope vs. su reserva) nunca varíe más de
   lo previsto, y es fácil de percibir como "un bloque tapando al otro"
   aunque técnicamente ningún texto quede cortado. Se retiró el solape
   por completo: ahora la cabecera termina con un padding normal y las
   tarjetas empiezan más abajo, con un espacio en blanco real entre
   ambas — dos bloques claramente separados, sin ningún margen negativo
   de por medio (ver también .perfil-stats más abajo). */
.perfil-header{position:relative; flex-shrink:0; background:var(--header-gradient); padding:24px 20px 24px; overflow:hidden; display:flex; flex-direction:column; align-items:center; text-align:center; z-index:2;}
.perfil-header:before{content:''; position:absolute; top:-50px; right:-30px; width:180px; height:180px; border-radius:50%; background:rgba(255,255,255,.08); pointer-events:none;}
.perfil-avatar{width:72px; height:72px; border-radius:50%; background:linear-gradient(150deg,#FFC53D,var(--orange)); border:4px solid rgba(255,255,255,.7); box-shadow:0 10px 22px rgba(10,20,50,.2); display:flex; align-items:center; justify-content:center; position:relative; z-index:1; flex-shrink:0;}
.perfil-avatar span{font-size:22px; font-weight:800; color:#fff; font-family:'Manrope',system-ui,sans-serif;}
.perfil-nombre{margin-top:11px; font-size:17px; font-weight:800; color:#fff; font-family:'Manrope',system-ui,sans-serif; position:relative; z-index:1;}
.perfil-cargo{font-size:11.5px; font-weight:600; color:rgba(255,255,255,.8); margin-top:2px; position:relative; z-index:1;}
.perfil-cargo[hidden]{display:none;}
.perfil-chip{display:inline-flex; align-items:center; gap:5px; background:rgba(255,255,255,.18); border:1px solid rgba(255,255,255,.28); padding:6px 12px; border-radius:100px; margin-top:11px; font-size:11.5px; font-weight:800; color:#fff; position:relative; z-index:1; font-family:'Manrope',system-ui,sans-serif;}

.perfil-wrap{flex:1; overflow-y:auto; padding:0 18px 24px;}

/* Tarjeta de estadísticas (4 columnas) + "Camino a próxima medalla":
   se usa tal cual en la sub-pestaña Resumen, y solo la segunda (próxima
   medalla) se repite en Logros — misma plantilla, IDs distintos.
   margin-top POSITIVO a propósito (no negativo): ver la nota junto a
   .perfil-header — se retiró el solape con la cabecera, este bloque
   ahora empieza limpio, después de un espacio en blanco real. */
.perfil-stats{position:relative; display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:8px; margin:18px 0 0; z-index:2;}
.perfil-stat-tile{background:#fff; border-radius:14px; padding:12px 6px; text-align:center; box-shadow:0 4px 12px rgba(20,30,60,.06);}
.perfil-stat-tile .n{font-size:15px; font-weight:800; color:var(--ink); font-family:'Manrope',system-ui,sans-serif;}
.perfil-stat-tile .l{font-size:8.5px; font-weight:700; color:var(--muted); margin-top:2px; text-transform:uppercase; letter-spacing:.2px;}

.proximo-nivel-card{background:#fff; border-radius:18px; padding:16px 18px; box-shadow:0 8px 20px rgba(20,30,60,.06); margin-top:16px;}
.proximo-nivel-top{display:flex; align-items:center; justify-content:space-between; margin-bottom:9px; gap:10px;}
.proximo-nivel-top span:first-child{font-size:11.5px; font-weight:700; color:var(--muted);}
.proximo-nivel-pts{font-size:11.5px; font-weight:800; color:var(--orange-dark); font-family:'Manrope',system-ui,sans-serif;}
.proximo-nivel-barra{height:9px; border-radius:100px; background:var(--bg); overflow:hidden;}
.proximo-nivel-rellena{height:100%; border-radius:100px; background:linear-gradient(90deg,#FFC53D,var(--orange)); transition:width .4s ease;}

/* Avance por categoría (sub-pestaña Resumen): proporción real de horas
   culminadas sobre las horas asignadas al funcionario en cada categoría
   de curso presente en su propio camino — ver renderAvanceCategorias()
   en app.js. */
.categorias-titulo{font-size:11px; font-weight:800; color:var(--muted); text-transform:uppercase; letter-spacing:.3px; margin:18px 0 12px;}
.categoria-item{margin-bottom:12px;}
.categoria-item:last-child{margin-bottom:0;}
.categoria-top{display:flex; justify-content:space-between; margin-bottom:5px; gap:8px;}
.categoria-top span:first-child{font-size:11.5px; font-weight:700; color:var(--ink); min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
.categoria-top span:last-child{font-size:11px; font-weight:800; color:var(--muted); flex-shrink:0; font-family:'Manrope',system-ui,sans-serif;}
.categoria-barra{height:7px; border-radius:100px; background:var(--border); overflow:hidden;}
.categoria-barra-rellena{height:100%; border-radius:100px; background:var(--primary);}
.categorias-vacio{font-size:11.5px; color:var(--muted); line-height:1.6;}

/* Sub-pestañas Resumen / Logros / Historial */
.perfil-subtabs{position:relative; display:flex; gap:22px; margin:24px 0 0; border-bottom:1px solid var(--border); z-index:2;}
.perfil-subtab{padding:0 0 10px; font-size:12.5px; font-weight:700; color:var(--muted); background:none; border:none; border-bottom:2.5px solid transparent; cursor:pointer;}
.perfil-subtab.active{font-weight:800; color:var(--primary-dark); border-bottom-color:var(--primary);}
.perfil-subview{padding-top:18px;}
.perfil-subview[hidden]{display:none;}

/* Sub-pestaña Logros: subtítulo + tarjeta de próxima medalla + grilla de
   4 medallas + actividad reciente + compartir logro. */
.logros-subtitulo{font-size:12px; font-weight:600; color:var(--muted); margin-bottom:16px;}

.medallas-list{display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:8px; margin:20px 0 18px;}
.medalla-card{position:relative; background:#fff; border:1.5px solid var(--border); border-radius:16px; padding:12px 6px; text-align:center; opacity:.55; transition:opacity .2s, border-color .2s;}
.medalla-card.conseguida{opacity:1; border-color:var(--tier-color, var(--gold)); box-shadow:0 8px 16px rgba(20,30,60,.1);}
.medalla-card.proximo{opacity:.9; border-style:dashed; border-color:var(--primary);}
.medalla-icono{width:40px; height:40px; margin:0 auto 8px; border-radius:50%; background:radial-gradient(circle at 35% 30%, #fff, var(--tier-color, var(--border)) 72%); display:flex; align-items:center; justify-content:center; font-size:18px;}
.medalla-card:not(.conseguida):not(.proximo) .medalla-icono{background:#EDEFF5; filter:grayscale(1); opacity:.8;}
.medalla-info{min-width:0;}
.medalla-nombre{font-size:10.5px; font-weight:800; color:var(--ink); overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
.medalla-meta{font-size:8.5px; color:var(--muted); font-weight:700; margin-top:2px;}
.medalla-card.proximo .medalla-meta{color:var(--primary-dark);}
.medalla-check{position:absolute; top:7px; right:7px; width:16px; height:16px; border-radius:50%; background:var(--green); color:#fff; font-weight:800; font-size:9px; display:flex; align-items:center; justify-content:center; line-height:1;}
/* Colores por posición del nivel (1º a 4º) — mismo criterio de la imagen
   PNG dinámica (insignia_imagen.php), aplicado acá vía variable CSS para
   no depender del ícono libre que carga el admin. */
.medalla-card[data-orden="1"]{--tier-color:var(--primary);}
.medalla-card[data-orden="2"]{--tier-color:var(--bronze);}
.medalla-card[data-orden="3"]{--tier-color:var(--silver);}
.medalla-card[data-orden="4"]{--tier-color:var(--gold);}

.actividad-card{background:#fff; border-radius:18px; padding:16px 18px; box-shadow:0 8px 20px rgba(20,30,60,.06); margin-bottom:18px;}
.racha-meses-titulo{font-size:11px; color:var(--muted); font-weight:800; text-transform:uppercase; letter-spacing:.3px; margin-bottom:14px;}
.racha-meses{display:flex; align-items:flex-end; gap:8px; height:64px;}
.racha-mes{flex:1; display:flex; flex-direction:column; align-items:center; justify-content:flex-end; height:100%; gap:6px;}
.racha-mes-barra{width:100%; max-width:22px; border-radius:6px 6px 3px 3px; background:linear-gradient(180deg,#5CC9F5,var(--primary)); min-height:4px; transition:height .3s ease;}
.racha-mes.sin-horas .racha-mes-barra{background:var(--border);}
.racha-mes-label{font-size:9px; color:var(--muted); font-weight:700;}

.racha-compartir{display:flex; align-items:center; justify-content:center; gap:8px; background:linear-gradient(120deg,var(--orange),var(--orange-dark)); box-shadow:0 10px 22px rgba(245,118,15,.3); color:#fff;}
.racha-compartir-opciones{display:flex; justify-content:center; gap:12px; margin-top:12px;}
.racha-compartir-opciones[hidden]{display:none;}
.racha-red{width:38px; height:38px; border-radius:50%; display:flex; align-items:center; justify-content:center; font-size:16px; font-weight:800; color:#fff;}
.racha-red-whatsapp{background:#25D366;}
.racha-red-facebook{background:#1877F2;}
.racha-red-twitter{background:#111;}

/* Sub-pestaña Historial: lista de cursos culminados (mismos datos que el
   resumen imprimible de flow/resumen.php, pero navegable dentro de la
   app — ver renderHistorial() en app.js). */
.historial-list{display:flex; flex-direction:column; gap:10px;}
.historial-item{display:flex; align-items:center; gap:12px; background:#fff; border-radius:16px; padding:12px 14px; box-shadow:0 4px 12px rgba(20,30,60,.05);}
.historial-check{width:38px; height:38px; border-radius:12px; background:linear-gradient(150deg,#33C583,var(--green-dark)); color:#fff; display:flex; align-items:center; justify-content:center; flex-shrink:0; font-weight:800;}
.historial-info{flex:1; min-width:0;}
.historial-nombre{font-size:12.5px; font-weight:800; color:var(--ink); overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
.historial-meta{font-size:10.5px; color:var(--muted); font-weight:600; margin-top:2px;}
.historial-codigo{font-size:9px; color:var(--muted); font-family:'Courier New',monospace; margin-top:2px;}
.historial-horas{font-size:11.5px; font-weight:800; color:var(--ink); flex-shrink:0; font-family:'Manrope',system-ui,sans-serif;}
.historial-vacio{font-size:12px; color:var(--muted); text-align:center; padding:30px 10px; line-height:1.6;}
.historial-btn-resumen{background:linear-gradient(120deg,var(--primary),var(--primary-dark)); color:#fff; box-shadow:0 10px 22px rgba(24,88,224,.3); margin-top:18px;}
.medallas-nota{font-size:10.5px; color:var(--muted); line-height:1.6; margin:18px 0 0;}

/* ---------------------------------------------------------------------
   Bottom sheet de detalle rápido de curso
   --------------------------------------------------------------------- */
.sheet-backdrop{position:fixed; inset:0; background:rgba(15,20,40,.35); z-index:40;}
.sheet-backdrop[hidden]{display:none;}
.sheet{
  position:absolute; left:0; right:0; bottom:0; background:#fff; border-radius:26px 26px 0 0;
  box-shadow:0 -12px 30px rgba(18,39,74,.18); padding:20px 22px 26px; z-index:50;
  transform:translateY(100%); transition:transform .32s cubic-bezier(.32,.72,0,1);
  max-width:480px; margin:0 auto;
}
.sheet.open{transform:translateY(0);}
.sheet .handle{width:36px; height:4px; background:var(--border); border-radius:4px; margin:0 auto 14px;}
.sheet h3{font-size:15px; color:var(--ink); margin-bottom:2px; font-weight:800; font-family:'Manrope',system-ui,sans-serif;}
.sheet-close{position:absolute; top:16px; right:18px; font-size:12px; color:var(--muted); cursor:pointer; background:none; border:none;}

/* Cabecera de la ficha: badge con ícono + chip de categoría + título —
   el color del badge cambia según el estado del curso (mismos colores
   que los nodos del camino). */
.sheet-head{display:flex; align-items:flex-start; gap:14px; margin-bottom:16px;}
.sheet-badge{width:48px; height:48px; border-radius:16px; display:flex; align-items:center; justify-content:center; flex-shrink:0; color:#fff; font-size:20px; box-shadow:0 8px 18px rgba(20,30,60,.18);}
.sheet-badge.culminado{background:linear-gradient(150deg,#33C583,var(--green-dark));}
.sheet-badge.actual,.sheet-badge.en_curso{background:linear-gradient(150deg,var(--primary),var(--primary-dark));}
.sheet-badge.bloqueado{background:linear-gradient(150deg,#B9C2D4,#8A93A6);}
.sheet-badge.meta{background:linear-gradient(150deg,#FFC53D,var(--gold));}
.sheet-head-text{flex:1; min-width:0; padding-top:2px;}
.sheet-categoria{display:inline-block; font-size:9.5px; font-weight:800; color:var(--primary-dark); background:var(--primary-soft); padding:3px 9px; border-radius:100px; text-transform:uppercase; letter-spacing:.3px; margin-bottom:6px;}
.sheet-categoria[hidden]{display:none;}

/* Grilla de 3 datos (duración/puntos/fecha o estado) */
.sheet-stats{display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:10px; margin-bottom:16px;}
.sheet-stat{background:var(--bg); border-radius:14px; padding:11px 6px; text-align:center;}
.sheet-stat.destacado{background:var(--orange-soft);}
.sheet-stat .n{font-size:15px; font-weight:800; color:var(--ink); font-family:'Manrope',system-ui,sans-serif;}
.sheet-stat.destacado .n{color:var(--orange-dark);}
.sheet-stat .l{font-size:8.5px; font-weight:700; color:var(--muted); text-transform:uppercase; margin-top:2px;}
.sheet-stat.destacado .l{color:var(--orange-dark);}

.sheet-banner{display:flex; align-items:center; gap:8px; border-radius:14px; padding:12px 14px; margin-bottom:16px; font-size:12px; font-weight:700;}
.sheet-banner[hidden]{display:none;}
.sheet-banner.exito{background:#EFFAF4; border:1px solid #CFEEDF; color:#0F7A4E;}
.sheet-banner.info{background:var(--primary-soft); border:1px solid #CBDBFC; color:var(--primary-dark);}
.sheet-cta{background:linear-gradient(120deg,var(--primary),var(--primary-dark)); color:#fff; box-shadow:0 10px 22px rgba(24,88,224,.3);}

/* Mascota reactiva, asomada arriba de la ficha de curso — la pose y el
   emoji cambian según el estado del nodo (ver reaccionMascotSheet() en
   app.js). */
.sheet-mascot{position:absolute; top:-58px; left:22px; width:74px; height:92px; z-index:2; pointer-events:none; filter:drop-shadow(0 10px 16px rgba(20,30,60,.28)); visibility:hidden;}
/* Con la ficha cerrada, ".sheet" descansa justo al pie de la pantalla
   (fuera de vista) — pero como esta mascota decorativa se asoma -58px
   por ENCIMA del propio borde de la ficha, quedaría igual visible sobre
   el bottom nav si no se ocultara explícitamente mientras está cerrada. */
.sheet.open .sheet-mascot{visibility:visible;}
.sheet-mascot svg{width:100%; height:100%; display:block;}
.sheet-mascot-reaccion{position:absolute; top:-8px; right:-10px; width:32px; height:32px; border-radius:50%; background:#fff; box-shadow:0 4px 10px rgba(20,30,60,.18); display:flex; align-items:center; justify-content:center; font-size:17px;}
.sheet-mascot.pop{animation:sheet-mascot-pop .5s cubic-bezier(.34,1.56,.64,1) both;}
@keyframes sheet-mascot-pop{
  0%{transform:scale(.4) translateY(22px); opacity:0;}
  70%{transform:scale(1.08) translateY(-4px); opacity:1;}
  100%{transform:scale(1) translateY(0); opacity:1;}
}
@media (prefers-reduced-motion: reduce){
  .sheet-mascot.pop{animation:none;}
}

@media (max-width:360px){
  .perfil-stats{gap:6px;}
  .perfil-stat-tile{padding:10px 4px;}
  .medallas-list{gap:6px;}
}
