/* ============================================================
   Nidu PWA — Base: reset ligero, tipografía, accesibilidad,
   layout del shell (topbar / main / bottom-nav) y utilidades.

   Del prototipo se traen los keyframes y las utilidades de texto. NO se trae su
   shell: `.nidu-stage`, `.nidu-frame` y `.statusbar` son el mockup de teléfono
   que el prototipo dibuja para mostrarse en el navegador. Acá la app ES el
   teléfono, así que el marco lo pone el sistema operativo.
   ============================================================ */

*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; padding: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* La app queda clavada al ancho del teléfono: sin scroll ni rebote elástico
     horizontal. Antes solo se frenaba el eje Y, así que en iOS se podía
     arrastrar toda la pantalla de costado (rebote), corriendo el layout y
     dejando espacio muerto (reporte de campo 2/8). `overscroll-behavior: none`
     mata el bounce en ambos ejes; `overflow-x: hidden` corta cualquier ancho
     de más. Va en html Y body porque iOS rebota sobre el que scrollee. */
  overflow-x: hidden;
  overscroll-behavior: none;
}

body {
  font-family: var(--fuente);
  font-size: var(--fs-16);
  line-height: 1.5;
  color: var(--ink);
  background: var(--app-bg-fin);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
  overscroll-behavior: none;
  min-height: 100dvh;
}

img, svg { display: block; max-width: 100%; }
button, input, textarea, select { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: none; }
a { color: inherit; text-decoration: none; }
ul, ol { list-style: none; }
::selection { background: var(--green-soft); }

/* ----- Accesibilidad: foco visible por teclado ----- */
:focus-visible {
  outline: 3px solid var(--foco);
  outline-offset: 2px;
  border-radius: 6px;
}
/* No mostramos el anillo en click de ratón, solo teclado */
:focus:not(:focus-visible) { outline: none; }

.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

/* Salto al contenido para teclado / lectores */
.skip-link {
  position: absolute; left: 8px; top: 8px; z-index: 100;
  transform: translateY(-140%);
  background: var(--green); color: #fff; padding: 10px 16px;
  border-radius: var(--r-pill); font-weight: var(--fw-bold);
  transition: transform var(--dur-base) var(--ease-out);
}
.skip-link:focus { transform: none; }

/* ============================================================
   Shell de la app
   ============================================================ */
/* App shell: header (topbar) fijo arriba, main con scroll propio, nav como footer.
   Todo dentro de una columna de alto completo -> sin scroll doble ni sticky frágil. */
.app {
  position: relative;
  width: 100%;
  max-width: var(--app-max);
  height: 100dvh;
  margin: 0 auto;
  background: var(--app-bg);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* Capa ambiental de emojis 3D (prototipo). Va DETRÁS de todo (z-index 0) y no
   recibe eventos; la topbar, el contenido y la nav se apoyan encima con z-index
   propio. `perspective` en el contenedor es lo que hace que el translateZ del
   keyframe se lea como profundidad y no como un escalado. */
.bg-emojis {
  position: absolute; inset: 0; z-index: 0;
  pointer-events: none; overflow: hidden;
  perspective: 900px; perspective-origin: 50% 35%;
  transform-style: preserve-3d;
}
/* Se fueron dos cosas que costaban caro y no se veían:
   · `filter: drop-shadow(...)` — sobre un elemento en movimiento hay que
     recalcular el filtro en cada cuadro, y a 13-18 % de opacidad la sombra no
     se distingue. Era el ítem más caro de la capa, por nada.
   · `will-change: transform` — dejaba 24 capas de composición promovidas de
     forma permanente, en todas las pantallas. La promoción tiene sentido para
     algo puntual, no para un fondo que está siempre.
   La capa además bajó de 24 emojis a 10 (ver index.html). */
.bg-emojis span {
  position: absolute; left: var(--x); top: var(--y);
  font-size: var(--s); line-height: 1; opacity: var(--o);
  animation: emoji3d var(--d) ease-in-out infinite;
}

/* En teléfonos quedan QUIETOS. Es donde el costo se nota y donde el movimiento
   menos aporta: un fondo al 15 % que se mueve no se lee como profundidad, se
   lee como que el scroll va pesado. */
@media (pointer: coarse) {
  .bg-emojis span { animation: none; transform: rotate(var(--r)); }
}
.bg-emojis span:nth-child(2n)  { animation-delay: -1.4s; }
.bg-emojis span:nth-child(3n)  { animation-delay: -2.8s; }
.bg-emojis span:nth-child(5n)  { animation-delay: -4.2s; }
.bg-emojis span:nth-child(7n)  { animation-delay: -5.6s; }
@media (prefers-reduced-motion: reduce) {
  .bg-emojis span { animation: none; transform: rotate(var(--r)); }
}

/* El contenido va POR ENCIMA de la capa ambiental. */
.topbar, .bottomnav, #app, .offline-banner { position: relative; z-index: 1; }

/* En pantallas grandes la columna "flota" como una app enfocada */
@media (min-width: 768px) {
  body {
    background:
      radial-gradient(700px 420px at 100% -10%, #E7F1EE 0%, transparent 60%),
      radial-gradient(560px 360px at -10% 110%, #F5E4DC 0%, transparent 55%),
      var(--cream);
  }
  .app {
    height: calc(100dvh - 48px);
    margin: 24px auto;
    border-radius: 28px;
    box-shadow: var(--sh-lg);
    border: 1px solid var(--line);
  }
}

/* `perspective` acá es lo que le da profundidad real a `cardIn` y `popZ` de las
   tarjetas: sin un ancestro con perspectiva, el rotateX se ve como un aplastado.
   Es el equivalente del `.viewport` del prototipo. */
#app {
  flex: 1 1 auto;
  min-height: 0;
  /* Un solo `.screen` por render (`router.js` lo reemplaza entero cada vez),
     así que volverlo columna flex no cambia nada en el resto de las
     pantallas — es lo que le permite a `.screen:has(> .res-hero)` (Resolver,
     campo verde) crecer hasta el alto disponible en vez de achicarse al
     contenido. */
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  overflow-x: hidden;
  /* El scroll vertical de la app no encadena con el documento (nada de
     pull-to-refresh ni rebote hacia el fondo detrás del sheet). */
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding: var(--sp-4) var(--sp-4) calc(var(--safe-b) + var(--sp-6));
  outline: none;
  perspective: 1500px;
  perspective-origin: 50% 24%;
}

/* ============================================================
   Movimiento — keyframes COPIADOS del prototipo (`.dc.html`, bloque <style>).
   El prototipo no anima en 2D: casi todo entra con perspectiva y rotación en un
   eje, que es lo que le da la sensación de papel girando hacia vos. Un simple
   `translateY` (lo que había antes) se ve plano al lado.
   ============================================================ */

/* Entrada de pantalla, DIRECCIONAL: hacia adelante entra desde la derecha,
   al volver desde la izquierda. El router pone `.screen--back` según el orden
   de pestañas, igual que `_dirTo()` en el prototipo. */
/* ⚠️ El `to` termina en `transform: none` y NO en `rotateY(0) translateX(0)`.
   Se ven igual —las dos son la identidad— pero no son lo mismo para el layout:
   un `transform` que no es `none`, aunque no mueva nada, convierte al elemento
   en el bloque contenedor de sus descendientes posicionados. Y como estas
   animaciones corren con `fill-mode: both`, ese transform quedaba aplicado PARA
   SIEMPRE sobre `.screen`.
   Consecuencia: todo `position: sticky` de adentro se anclaba a `.screen` en vez
   de al contenedor que scrollea, así que se movía con el contenido en lugar de
   quedarse quieto. Se reportó el 29/7 como "el botón de guardar pendiente no
   queda fijo abajo y se mueve por toda la pantalla", y afectaba a las seis
   pantallas con CTA inferior. */
@keyframes slideR {
  from { opacity: 0; transform: perspective(1300px) rotateY(-14deg) translateX(46px); }
  to   { opacity: 1; transform: none; }
}
@keyframes slideL {
  from { opacity: 0; transform: perspective(1300px) rotateY(14deg) translateX(-46px); }
  to   { opacity: 1; transform: none; }
}
.screen { animation: slideR .34s var(--ease-out) both; }
.screen--back { animation-name: slideL; }

/* El ovillo estampado sobre el cambio de pantalla. Va por encima del contenido
   pero POR DEBAJO de la nav y la topbar (z-index 38, igual que el prototipo), y
   nunca recibe eventos: la pantalla de abajo se puede tocar mientras dura. */
.trans {
  position: absolute; inset: 0; z-index: 38;
  display: grid; place-items: center;
  pointer-events: none;
}
/* Acá había `.trans__mark { animation: transStamp 1.2s ... }`, pero ese
   @keyframes NO EXISTE en ningún archivo: era una referencia colgada que el
   navegador ignoraba. El dibujado lo hacen las animaciones internas del SVG
   (nmDraw/nmSpin/nmPop), así que la regla no hacía falta y se fue. */

/* La topbar cae desde arriba inclinada en X. */
@keyframes topIn {
  from { opacity: 0; transform: perspective(900px) rotateX(-24deg) translateY(-12px); }
  to   { opacity: 1; transform: perspective(900px) rotateX(0) translateY(0); }
}
.topbar { animation: topIn var(--dur-base) var(--ease-out) both; }

/* Tarjetas y notas: se levantan girando en X, como una hoja que se acuesta. */
@keyframes cardIn {
  from { opacity: 0; transform: perspective(950px) rotateX(20deg) translateY(26px) scale(.955); }
  to   { opacity: 1; transform: perspective(950px) rotateX(0) translateY(0) scale(1); }
}
@keyframes revealUp {
  from { opacity: 0; transform: translateY(16px); filter: blur(5px); }
  to   { opacity: 1; transform: none; filter: blur(0); }
}
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes popZ {
  0%   { opacity: 0; transform: perspective(700px) translateZ(-120px) scale(.7); }
  60%  { transform: perspective(700px) translateZ(30px) scale(1.04); }
  100% { opacity: 1; transform: perspective(700px) translateZ(0) scale(1); }
}
@keyframes floatZ {
  0%, 100% { transform: translateY(0) translateZ(0); }
  50%      { transform: translateY(-7px) translateZ(14px); }
}
@keyframes floaty {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-5px); }
}
@keyframes emoji3d {
  0%, 100% { transform: translateY(0) translateZ(0) rotate(var(--r)) rotateY(-16deg); }
  50%      { transform: translateY(-16px) translateZ(48px) rotate(var(--r)) rotateY(20deg); }
}

/* El FAB de la PWA se ancla a la derecha, no centrado como en el prototipo, así
   que su `fabPop` no arrastra el `translateX(-50%)` del original. */
@keyframes fabPop {
  0%   { transform: scale(.4); opacity: 0; }
  70%  { transform: scale(1.12); }
  100% { transform: scale(1); opacity: 1; }
}

/* Hoja inferior y toast */
@keyframes sheetUp { from { transform: translateY(102%); } to { transform: translateY(0); } }
@keyframes toastUp { from { opacity: 0; transform: translate(-50%, 20px); } to { opacity: 1; transform: translate(-50%, 0); } }

/* Celebración al vaciar la ruta: check dibujado + anillo + confeti + frase. */
@keyframes celebPop { 0% { transform: scale(0); } 60% { transform: scale(1.18); } 100% { transform: scale(1); } }
@keyframes checkDraw { to { stroke-dashoffset: 0; } }
@keyframes ringPulse { 0% { transform: scale(.7); opacity: .55; } 100% { transform: scale(1.9); opacity: 0; } }
@keyframes confetti {
  0%   { transform: translate(0, 0) rotate(0); opacity: 1; }
  10%  { opacity: 1; }
  100% { transform: translate(var(--tx), var(--ty)) rotate(var(--rot)); opacity: 0; }
}
@keyframes phraseIn {
  0%   { opacity: 0; transform: translateY(10px) scale(.9); }
  55%  { transform: translateY(0) scale(1.05); }
  100% { opacity: 1; transform: none; }
}

/* Esqueletos de carga */
@keyframes shimmer { 0% { background-position: -200px 0; } 100% { background-position: 200px 0; } }

/* El ovillo de marca: trazo que se dibuja, punto que aparece, giro de entrada. */
@keyframes nmDraw { to { stroke-dashoffset: 0; } }
@keyframes nmPop { 0% { transform: scale(0); } 60% { transform: scale(1.2); } 100% { transform: scale(1); } }
@keyframes nmSpin { from { transform: rotate(-90deg); } to { transform: rotate(0); } }

/* Halos a la deriva del splash y anillo de progreso del día (Perfil). */
@keyframes drift1 { 0%, 100% { transform: translate(0, 0) scale(1); } 50% { transform: translate(20px, -24px) scale(1.09); } }
@keyframes drift2 { 0%, 100% { transform: translate(0, 0) scale(1); } 50% { transform: translate(-22px, 18px) scale(1.11); } }
@keyframes drift3 { 0%, 100% { transform: translate(0, 0) scale(1); } 50% { transform: translate(16px, 22px) scale(1.07); } }
@keyframes pulseR { 0%, 100% { transform: translate(-50%, -50%) scale(1); } 50% { transform: translate(-50%, -50%) scale(1.06); } }
@keyframes ringGrow { from { stroke-dashoffset: var(--circ); } to { stroke-dashoffset: var(--off); } }

/* Perfil 7a: la curva se hunde (origen abajo), la foto rebota, el check aparece
   sobre el borde, las filas suben escalonadas, el halo del mark late y el ovillo
   de instalar se mece. Copiados del handoff (`Perfil NIDU.dc.html`). */
@keyframes niduBowl { from { transform: scaleY(.35); } to { transform: scaleY(1); } }
@keyframes niduAvIn { from { transform: scale(.72); opacity: 0; } to { transform: scale(1); opacity: 1; } }
@keyframes niduCheckPop { 0% { transform: scale(.3); opacity: 0; } 65% { transform: scale(1.18); opacity: 1; } 100% { transform: scale(1); opacity: 1; } }
@keyframes niduFila { from { opacity: 0; transform: translateX(-14px); } to { opacity: 1; transform: none; } }
@keyframes niduHalo { 0% { transform: scale(.7); opacity: .5; } 70%, 100% { transform: scale(1.45); opacity: 0; } }
@keyframes p7Mark { 0%, 100% { transform: rotate(-3.5deg); } 50% { transform: rotate(3.5deg); } }

/* El saludo entra desenfocándose hacia nítido: `revealUp`, no un fade. */
.greet { animation: revealUp .5s var(--ease-out) both; }

/* Reveal escalonado. El prototipo usa `cardIn` con 60ms entre elementos. */
.stagger > * { animation: cardIn var(--dur-base) var(--ease-out) both; }
.stagger > *:nth-child(1){ animation-delay: 0s; }
.stagger > *:nth-child(2){ animation-delay: .06s; }
.stagger > *:nth-child(3){ animation-delay: .12s; }
.stagger > *:nth-child(4){ animation-delay: .18s; }
.stagger > *:nth-child(5){ animation-delay: .24s; }
.stagger > *:nth-child(6){ animation-delay: .30s; }
.stagger > *:nth-child(7){ animation-delay: .36s; }
.stagger > *:nth-child(8){ animation-delay: .42s; }
/* El TABLERO es la excepción y por una razón concreta: cada nota lleva su propia
   `transform: rotate(--rot)` de papel torcido, y cualquier animación que anime
   `transform` se la pisa —la nota entraría derecha y saltaría a su ángulo al
   terminar—. En el prototipo las notas del tablero no tienen animación de
   entrada; solo la destacada, y con un fade, que no toca el transform. */
.noteboard > * { animation: none; }
.noteboard > .nota--feat { animation: fadeIn .45s var(--ease-out) .05s both; }

/* ----- Tipografía de pantalla (valores del prototipo) ----- */
.screen-head { padding: 4px 2px 12px; }
.screen-head--tall { padding: 4px 2px 16px; }
.screen-kicker {
  font-size: var(--fs-13); font-weight: var(--fw-x);
  letter-spacing: .04em; text-transform: uppercase;
  color: var(--green);
}
.screen-title {
  font-size: 25px; font-weight: var(--fw-black);
  letter-spacing: -.02em; line-height: 1.12; color: var(--ink);
}
.screen-sub {
  margin-top: var(--sp-2);
  font-size: var(--fs-14); font-weight: var(--fw-bold); color: var(--muted);
}
.section-label {
  font-size: var(--fs-10-5); font-weight: var(--fw-x);
  letter-spacing: .1em; text-transform: uppercase;
  color: var(--muted);
}
/* `.section-head` / `.section-title` / `.section-link` son de la PWA y siguen en
   uso en las pantallas que todavía no se portaron (ruta, agenda, compras…).
   Cuando esas pasen al markup del prototipo, se van con ellas. */
.section-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--sp-3); margin: var(--sp-6) 0 var(--sp-3);
}
.section-title { font-size: var(--fs-18); font-weight: var(--fw-x); color: var(--ink); }
.section-link {
  font-size: var(--fs-14); font-weight: var(--fw-bold); color: var(--green);
  padding: 4px 6px; border-radius: 8px;
}
.section-link:hover { color: var(--green-hover); }

/* ----- Utilidades ----- */
.stack { display: flex; flex-direction: column; }
.stack-2 > * + * { margin-top: var(--sp-2); }
.stack-3 > * + * { margin-top: var(--sp-3); }
.stack-4 > * + * { margin-top: var(--sp-4); }
.stack-col { display: flex; flex-direction: column; gap: 8px; }
.stack-col--9 { display: flex; flex-direction: column; gap: 9px; }
.row { display: flex; align-items: center; }
.gap-2 { gap: var(--sp-2); } .gap-3 { gap: var(--sp-3); } .gap-4 { gap: var(--sp-4); }
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3); }
.mt-2{margin-top:var(--sp-2);} .mt-4{margin-top:var(--sp-4);} .mt-6{margin-top:var(--sp-6);}
.text-2 { color: var(--ink-2); } .text-sm { font-size: var(--fs-14); }
.hidden { display: none !important; }
/* Texto que actúa como link, sin caja de botón: para una salida secundaria
   discreta (p. ej. "¿no te conecta? pedí un código") que no compite con la
   acción principal de la pantalla. */
.link-btn {
  background: none; border: none; padding: 0; margin: 0; font: inherit;
  color: var(--ink-2); text-decoration: underline; cursor: pointer;
}
.link-btn:hover, .link-btn:focus-visible { color: var(--ink); }

/* ============================================================
   Respeto por preferencias de movimiento
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}
