/* ==========================================================================
   Componentes
   ========================================================================== */

/* ------------------------- Botones ------------------------- */

.btn {
  --btn-bg: var(--green);
  --btn-sh: var(--green-dark);
  --btn-fg: #fff;
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 15px 22px;
  min-height: 52px;
  border-radius: var(--r-md);
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-weight: 900;
  font-size: var(--fs-md);
  letter-spacing: .6px;
  text-transform: uppercase;
  box-shadow: 0 4px 0 var(--btn-sh);
  transition: transform .09s var(--ease-out), box-shadow .09s var(--ease-out),
              background .18s, opacity .18s, filter .18s;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  overflow: hidden;
}
.btn:hover:not(:disabled) { filter: brightness(1.05); }
.btn:active:not(:disabled) { transform: translateY(4px); box-shadow: 0 0 0 var(--btn-sh); }
.btn:disabled { opacity: .45; cursor: not-allowed; box-shadow: 0 4px 0 var(--btn-sh); }
.btn--block { display: flex; width: 100%; }
.btn--lg { min-height: 58px; font-size: var(--fs-lg); border-radius: var(--r-lg); }
.btn--sm { min-height: 40px; padding: 9px 14px; font-size: var(--fs-sm); border-radius: var(--r-sm); }

.btn--brand  { --btn-bg: var(--brand);  --btn-sh: var(--brand-dark); }
.btn--blue   { --btn-bg: var(--blue);   --btn-sh: var(--blue-dark); }
.btn--purple { --btn-bg: var(--purple); --btn-sh: var(--purple-dark); }
.btn--red    { --btn-bg: var(--red);    --btn-sh: var(--red-dark); }
.btn--gold   { --btn-bg: var(--gold);   --btn-sh: var(--gold-dark); --btn-fg: #4A3500; }
.btn--dark   { --btn-bg: var(--ink);    --btn-sh: #050C18; }

.btn--ghost {
  background: var(--card);
  color: var(--ink-2);
  box-shadow: 0 2px 0 var(--line), inset 0 0 0 2px var(--line);
}
.btn--ghost:active:not(:disabled) { box-shadow: inset 0 0 0 2px var(--line); }

.btn--flat {
  background: transparent; color: var(--ink-3);
  box-shadow: none; text-transform: none; letter-spacing: 0;
  font-weight: 800;
}
.btn--flat:active:not(:disabled) { transform: scale(.96); box-shadow: none; }

.btn__shine {
  position: absolute; top: 0; left: -140%;
  width: 60%; height: 100%;
  background: linear-gradient(100deg, transparent, rgba(255,255,255,.42), transparent);
  transform: skewX(-18deg);
  pointer-events: none;
}
.btn--shiny .btn__shine { animation: shine 3.4s var(--ease-in-out) infinite; }

/* Botón icónico redondo */
.icon-btn {
  width: 42px; height: 42px;
  display: grid; place-items: center;
  border-radius: var(--r-full);
  background: var(--card);
  color: var(--ink-2);
  box-shadow: var(--sh-1);
  font-size: 18px;
  transition: transform .12s var(--spring), background .2s;
  flex: none;
}
.icon-btn:active { transform: scale(.9); }
.icon-btn--plain { background: transparent; box-shadow: none; }

/* ------------------------- Tarjetas ------------------------- */

.card {
  background: var(--card);
  border-radius: var(--r-lg);
  padding: var(--s5);
  box-shadow: var(--sh-1);
  border: 2px solid var(--line-2);
}
.card--tight { padding: var(--s4); }
.card--flat { box-shadow: none; }
.card--accent { border-color: var(--brand); background: var(--brand-soft); }

.tile {
  position: relative;
  border-radius: var(--r-lg);
  padding: var(--s4);
  background: var(--card);
  border: 2px solid var(--line);
  box-shadow: 0 3px 0 var(--line);
  transition: transform .12s var(--spring), border-color .18s, box-shadow .18s;
  text-align: left;
  width: 100%;
}
.tile:active { transform: translateY(3px); box-shadow: 0 0 0 var(--line); }

/* ------------------------- Barra superior ------------------------- */

.topbar {
  height: var(--topbar-h);
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: 0 var(--s4);
  background: var(--card);
  border-bottom: 2px solid var(--line-2);
  z-index: 20;
}

.stat {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-weight: 900;
  font-size: var(--fs-md);
  padding: 6px 4px;
  border-radius: var(--r-sm);
  transition: transform .12s var(--spring);
  -webkit-tap-highlight-color: transparent;
}
.stat:active { transform: scale(.92); }
.stat__icon { font-size: 20px; line-height: 1; filter: drop-shadow(0 2px 2px rgba(0,0,0,.12)); }
.stat--streak { color: var(--brand); }
.stat--gem    { color: var(--blue); }
.stat--heart  { color: var(--red); }
.stat--xp     { color: var(--gold-dark); }
.stat--off { opacity: .38; filter: grayscale(1); }

/* ------------------------- Tabbar ------------------------- */

.tabbar {
  height: calc(var(--tabbar-h) + var(--safe-b));
  padding-bottom: var(--safe-b);
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  background: var(--card);
  border-top: 2px solid var(--line-2);
  z-index: 20;
}

.tab {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  color: var(--ink-3);
  font-size: 10px;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: .3px;
  position: relative;
  transition: color .2s;
  -webkit-tap-highlight-color: transparent;
}
.tab__ico {
  font-size: 23px;
  line-height: 1;
  transition: transform .28s var(--spring);
}
.tab:active .tab__ico { transform: scale(.86); }
.tab.is-active { color: var(--brand); }
.tab.is-active .tab__ico { transform: translateY(-2px) scale(1.14); }
.tab.is-active::before {
  content: '';
  position: absolute; top: 0; left: 50%;
  transform: translateX(-50%);
  width: 30px; height: 3px;
  border-radius: 0 0 4px 4px;
  background: var(--brand);
  animation: tabPop .3s var(--spring);
}
.tab__dot {
  position: absolute;
  top: 8px; right: 50%;
  margin-right: -20px;
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--red);
  border: 2px solid var(--card);
  animation: pulseDot 1.8s ease-in-out infinite;
}

/* ------------------------- Barras de progreso ------------------------- */

.pbar {
  position: relative;
  height: 16px;
  border-radius: var(--r-full);
  background: var(--line);
  overflow: hidden;
  flex: 1;
}
.pbar__fill {
  height: 100%;
  border-radius: var(--r-full);
  background: linear-gradient(90deg, var(--green), #6BE08A);
  width: 0;
  transition: width .65s var(--ease-out);
  position: relative;
}
.pbar__fill::after {
  content: '';
  position: absolute;
  top: 3px; left: 8px; right: 8px;
  height: 4px;
  border-radius: 99px;
  background: rgba(255,255,255,.42);
}
.pbar--sm { height: 10px; }
.pbar--brand .pbar__fill { background: linear-gradient(90deg, var(--brand), var(--brand-2)); }
.pbar--blue .pbar__fill  { background: linear-gradient(90deg, var(--blue), #67D2FF); }
.pbar--gold .pbar__fill  { background: linear-gradient(90deg, var(--gold-dark), var(--gold)); }
.pbar--red .pbar__fill   { background: linear-gradient(90deg, var(--red), #FF8080); }

.ring {
  --p: 0;
  --ring-c: var(--brand);
  width: 62px; height: 62px;
  border-radius: 50%;
  display: grid; place-items: center;
  background: conic-gradient(var(--ring-c) calc(var(--p) * 1%), var(--line) 0);
  transition: --p .8s var(--ease-out);
  flex: none;
}
.ring__inner {
  width: 78%; height: 78%;
  border-radius: 50%;
  background: var(--card);
  display: grid; place-items: center;
  font-weight: 900; font-size: var(--fs-sm);
}

/* ------------------------- Chips y píldoras ------------------------- */

.chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 13px;
  border-radius: var(--r-full);
  background: var(--line-2);
  color: var(--ink-2);
  font-size: var(--fs-sm);
  font-weight: 800;
  white-space: nowrap;
}
.chip--brand  { background: var(--brand-soft);  color: var(--brand); }
.chip--green  { background: var(--green-soft);  color: var(--green-dark); }
.chip--blue   { background: var(--blue-soft);   color: var(--blue-dark); }
.chip--purple { background: var(--purple-soft); color: var(--purple-dark); }
.chip--gold   { background: var(--gold-soft);   color: var(--gold-dark); }
.chip--red    { background: var(--red-soft);    color: var(--red-dark); }
.chip--outline{ background: transparent; box-shadow: inset 0 0 0 2px var(--line); }

.badge-count {
  min-width: 22px; height: 22px;
  padding: 0 6px;
  border-radius: var(--r-full);
  background: var(--red);
  color: #fff;
  font-size: 11px; font-weight: 900;
  display: grid; place-items: center;
}

/* ------------------------- Opciones (quiz) ------------------------- */

.opt {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--s3);
  width: 100%;
  padding: 15px 16px;
  border-radius: var(--r-md);
  background: var(--card);
  border: 2px solid var(--line);
  box-shadow: 0 4px 0 var(--line);
  text-align: left;
  font-weight: 700;
  font-size: var(--fs-md);
  line-height: 1.4;
  color: var(--ink);
  transition: transform .1s var(--ease-out), border-color .18s,
              background .18s, box-shadow .1s, color .18s;
  -webkit-tap-highlight-color: transparent;
}
.opt:active:not(.is-locked) { transform: translateY(4px); box-shadow: 0 0 0 var(--line); }

.opt__key {
  flex: none;
  width: 28px; height: 28px;
  border-radius: 8px;
  display: grid; place-items: center;
  background: var(--line-2);
  color: var(--ink-3);
  font-size: var(--fs-sm);
  font-weight: 900;
  transition: background .18s, color .18s;
}
.opt__body { flex: 1; }
.opt__hint { display: block; font-size: var(--fs-sm); font-weight: 700; color: var(--ink-3); margin-top: 2px; }
.opt__mark { flex: none; font-size: 19px; opacity: 0; transform: scale(.4); transition: all .28s var(--spring); }

.opt.is-selected {
  border-color: var(--blue);
  background: var(--blue-soft);
  box-shadow: 0 4px 0 var(--blue-dark);
  color: var(--blue-dark);
}
.opt.is-selected .opt__key { background: var(--blue); color: #fff; }

.opt.is-correct {
  border-color: var(--green);
  background: var(--green-soft);
  box-shadow: 0 4px 0 var(--green-dark);
  color: var(--green-dark);
}
.opt.is-correct .opt__key { background: var(--green); color: #fff; }
.opt.is-correct .opt__mark { opacity: 1; transform: scale(1); }

.opt.is-wrong {
  border-color: var(--red);
  background: var(--red-soft);
  box-shadow: 0 4px 0 var(--red-dark);
  color: var(--red-dark);
  animation: shake .42s var(--ease-out);
}
.opt.is-wrong .opt__key { background: var(--red); color: #fff; }
.opt.is-wrong .opt__mark { opacity: 1; transform: scale(1); }

.opt.is-locked { cursor: default; }
.opt.is-dim { opacity: .5; }

/* Opciones tipo tarjeta grande (onboarding) */
.opt--card {
  flex-direction: row;
  padding: 18px;
  gap: 14px;
}
.opt--card .opt__emoji {
  font-size: 30px; flex: none;
  width: 50px; height: 50px;
  display: grid; place-items: center;
  border-radius: var(--r-md);
  background: var(--line-2);
  transition: background .2s, transform .3s var(--spring);
}
.opt--card.is-selected .opt__emoji { background: rgba(255,255,255,.7); transform: rotate(-6deg) scale(1.06); }

/* ------------------------- Fichas (match / order / banco) ------------------------- */

.token {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 11px 15px;
  border-radius: var(--r-md);
  background: var(--card);
  border: 2px solid var(--line);
  box-shadow: 0 3px 0 var(--line);
  font-weight: 800; font-size: var(--fs-sm);
  color: var(--ink);
  transition: transform .12s var(--spring), opacity .2s, border-color .2s, background .2s;
  -webkit-tap-highlight-color: transparent;
}
.token:active { transform: translateY(3px); box-shadow: 0 0 0 var(--line); }
.token.is-used { opacity: .28; pointer-events: none; }
.token.is-sel { border-color: var(--blue); background: var(--blue-soft); color: var(--blue-dark); box-shadow: 0 3px 0 var(--blue-dark); }
.token.is-ok  { border-color: var(--green); background: var(--green-soft); color: var(--green-dark); box-shadow: 0 3px 0 var(--green-dark); }
.token.is-ko  { border-color: var(--red); background: var(--red-soft); color: var(--red-dark); animation: shake .4s; }

.slot {
  min-height: 48px;
  border-radius: var(--r-md);
  border: 2px dashed var(--line);
  background: var(--line-2);
  display: flex; align-items: center; gap: 8px;
  padding: 8px 12px;
  font-weight: 800; font-size: var(--fs-sm);
  color: var(--ink-3);
  transition: border-color .2s, background .2s;
}
.slot.is-filled { border-style: solid; border-color: var(--blue); background: var(--blue-soft); color: var(--blue-dark); }

.order-item {
  display: flex; align-items: center; gap: 12px;
  padding: 13px 14px;
  border-radius: var(--r-md);
  background: var(--card);
  border: 2px solid var(--line);
  box-shadow: 0 3px 0 var(--line);
  font-weight: 700; font-size: var(--fs-sm); line-height: 1.35;
  cursor: grab;
  transition: transform .22s var(--spring), box-shadow .2s, border-color .2s, background .2s;
}
.order-item__num {
  width: 26px; height: 26px; flex: none;
  border-radius: 8px;
  display: grid; place-items: center;
  background: var(--brand-soft); color: var(--brand);
  font-weight: 900; font-size: var(--fs-sm);
}
.order-item__grip { margin-left: auto; color: var(--ink-3); font-size: 18px; flex: none; }
.order-item.is-drag { opacity: .35; }
.order-item.is-ok { border-color: var(--green); background: var(--green-soft); box-shadow: 0 3px 0 var(--green-dark); }
.order-item.is-ko { border-color: var(--red); background: var(--red-soft); box-shadow: 0 3px 0 var(--red-dark); }

/* ------------------------- Campos ------------------------- */

.field { display: flex; flex-direction: column; gap: 7px; }
.field__label { font-size: var(--fs-sm); font-weight: 900; color: var(--ink-2); }
.field__hint  { font-size: var(--fs-xs); font-weight: 700; color: var(--ink-3); }

.input, .textarea {
  width: 100%;
  padding: 14px 15px;
  border-radius: var(--r-md);
  border: 2px solid var(--line);
  background: var(--card);
  color: var(--ink);
  font-weight: 700;
  font-size: var(--fs-md);
  transition: border-color .2s, box-shadow .2s, background .2s;
  -webkit-appearance: none;
  appearance: none;
}
.input::placeholder, .textarea::placeholder { color: var(--ink-3); font-weight: 600; }
.input:focus, .textarea:focus {
  outline: none;
  border-color: var(--blue);
  box-shadow: 0 0 0 4px rgba(28,176,246,.16);
}
.textarea { min-height: 108px; resize: vertical; line-height: 1.5; font-size: var(--fs-md); }

.range {
  -webkit-appearance: none; appearance: none;
  width: 100%; height: 12px;
  border-radius: 99px;
  background: var(--line);
  outline: none;
}
.range::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 30px; height: 30px;
  border-radius: 50%;
  background: var(--brand);
  border: 4px solid #fff;
  box-shadow: 0 3px 8px rgba(255,107,26,.5);
  cursor: grab;
  transition: transform .15s var(--spring);
}
.range::-webkit-slider-thumb:active { transform: scale(1.2); }
.range::-moz-range-thumb {
  width: 26px; height: 26px; border-radius: 50%;
  background: var(--brand); border: 4px solid #fff;
  box-shadow: 0 3px 8px rgba(255,107,26,.5); cursor: grab;
}

/* ------------------------- Globo del mentor ------------------------- */

.speech {
  position: relative;
  background: var(--card);
  border: 2px solid var(--line);
  border-radius: var(--r-lg);
  padding: 14px 16px;
  font-size: var(--fs-md);
  font-weight: 700;
  line-height: 1.5;
  color: var(--ink);
  box-shadow: var(--sh-1);
  flex: 1;
}
.speech::before, .speech::after {
  content: '';
  position: absolute;
  left: -10px; top: 22px;
  border: 10px solid transparent;
  border-right-color: var(--line);
  border-left: 0;
}
.speech::after {
  left: -7px;
  border-right-color: var(--card);
}
.speech--green { background: var(--green-soft); border-color: var(--green); }
.speech--green::before { border-right-color: var(--green); }
.speech--green::after  { border-right-color: var(--green-soft); }
.speech--red { background: var(--red-soft); border-color: var(--red); }
.speech--red::before { border-right-color: var(--red); }
.speech--red::after  { border-right-color: var(--red-soft); }

/* ------------------------- Mascota ------------------------- */

.mascot {
  --m-size: 88px;
  width: var(--m-size);
  height: var(--m-size);
  flex: none;
  position: relative;
  animation: bob 3.2s var(--ease-in-out) infinite;
  transform-origin: 50% 90%;
}
.mascot svg { width: 100%; height: 100%; overflow: visible; }

/* La caja es cuadrada pero el viewBox es 100x108, así que el dibujo sale
   siempre al 92,6% del ancho. Los tamaños de abajo están elegidos para que el
   ARTE caiga donde tiene que caer, no la caja:

     --sm  64px → 59px de Chispa   · mensajes normales
     base  88px → 81px             · pantallas con sitio
     --md  96px → 89px             · consejos, resultados, momentos clave
     --lg 130px → 120px            · modales de celebración
     --xl 170px → 157px            · retratos a pantalla completa           */
.mascot--sm { --m-size: 64px; }
.mascot--md { --m-size: 96px; }
.mascot--lg { --m-size: 130px; }
.mascot--xl { --m-size: 170px; }

/* Los gestos de una sola pasada se encadenan con el reposo en vez de
   sustituirlo. Escritos como una sola animación, al terminar dejaban a Chispa
   quieta para siempre: el bob de .mascot desaparecía y no volvía nunca. */
.mascot.is-happy  { animation: jump .7s var(--spring), bob 3.2s var(--ease-in-out) .7s infinite; }
.mascot.is-sad    { animation: droop .7s var(--ease-out), bob 3.2s var(--ease-in-out) .7s infinite; }
.mascot.is-party  { animation: party .9s var(--spring), bob 3.2s var(--ease-in-out) .9s infinite; }
.mascot.is-wow    { animation: wowPop .55s var(--spring), bob 3.2s var(--ease-in-out) .55s infinite; }
.mascot.is-money  { animation: cash 1.1s var(--spring), bob 3.2s var(--ease-in-out) 1.1s infinite; }
/* Estas dos ya son continuas: no hay nada que encadenar. */
.mascot.is-think  { animation: tilt 2.4s var(--ease-in-out) infinite; }
/* is-neutral no redefine nada: su animación es el bob de reposo de .mascot */

/* Entrada. Solo cuando se pide con la clase, para no animar las veintitantas
   mascotas que ya viven en pantallas que se repintan a cada paso.

   Va en el CONTENEDOR y no en la mascota: puestas en el mismo elemento, la
   entrada sustituía a la animación del ánimo —is-party, is-happy— y Chispa no
   llegaba a celebrar nunca en el sitio donde más falta hacía. Así se componen:
   el padre entra, la mascota gesticula. */
.chispa-dice.is-entrando,
.mascot.is-entrando { animation: mascotEntra .42s var(--spring) both; }
/* Si la entrada la lleva el contenedor, la mascota conserva su propio gesto. */
.chispa-dice.is-entrando > .mascot { animation-delay: .42s; }

@keyframes mascotEntra {
  0%   { opacity: 0; transform: translateY(10px) scale(.8) }
  60%  { opacity: 1; transform: translateY(0)    scale(1.06) }
  100% { opacity: 1; transform: translateY(0)    scale(1) }
}

.m-eye { transform-origin: center; animation: blink 4.6s infinite; }
.m-spark { animation: sparkle 2.2s var(--ease-in-out) infinite; transform-origin: center; }
.m-arm-l { transform-origin: 30px 62px; }
.m-arm-r { transform-origin: 70px 62px; }
.mascot.is-happy .m-arm-l { animation: waveL .7s var(--ease-out); }
.mascot.is-happy .m-arm-r { animation: waveR .7s var(--ease-out); }

/* Lo que lleva en la mano tiene que moverse con el brazo. Sin esto, al saludar
   el brazo sube y la herramienta se queda flotando donde estaba. */
.m-hold-l { transform-origin: 30px 62px; }
.m-hold-r { transform-origin: 70px 62px; }
.mascot.is-happy .m-hold-l { animation: waveL .7s var(--ease-out); }
.mascot.is-happy .m-hold-r { animation: waveR .7s var(--ease-out); }

/* ------------------------- Toasts ------------------------- */

.toast {
  pointer-events: auto;
  display: flex; align-items: center; gap: 10px;
  padding: 12px 16px;
  border-radius: var(--r-md);
  background: var(--ink);
  color: #fff;
  font-weight: 800;
  font-size: var(--fs-sm);
  box-shadow: var(--sh-3);
  animation: toastIn .38s var(--spring);
  max-width: 100%;
}
.toast.is-out { animation: toastOut .3s var(--ease-in-out) forwards; }
.toast--green { background: var(--green-dark); }
.toast--red   { background: var(--red-dark); }
.toast--gold  { background: var(--gold-dark); color: #3B2C00; }
.toast--blue  { background: var(--blue-dark); }
.toast__ico { font-size: 18px; }

/* ------------------------- Modales / sheets ------------------------- */

.modal {
  position: relative;
  width: min(420px, 100%);
  max-height: 86vh;
  overflow-y: auto;
  background: var(--card);
  border-radius: var(--r-xl);
  padding: var(--s6);
  box-shadow: var(--sh-pop);
  text-align: center;
  animation: modalIn .42s var(--spring);
  display: flex; flex-direction: column; gap: var(--s4);
}

.sheet {
  position: relative;
  width: 100%;
  max-width: var(--phone-w);
  margin: 0 auto;
  max-height: 88vh;
  overflow-y: auto;
  background: var(--card);
  border-radius: var(--r-xl) var(--r-xl) 0 0;
  padding: var(--s5) var(--s5) calc(var(--s6) + var(--safe-b));
  box-shadow: var(--sh-pop);
  animation: sheetIn .38s var(--ease-out);
  display: flex; flex-direction: column; gap: var(--s4);
}
.sheet__grip {
  width: 44px; height: 5px;
  border-radius: 99px;
  background: var(--line);
  margin: -6px auto 2px;
  flex: none;
}

/* ------------------------- «Tu idea es tuya» -------------------------

   La promesa que se hace justo antes de pedirle la idea al usuario
   (js/core/promesa.js). Se ve una vez en la vida, así que tiene que
   transmitir en tres segundos: Chispa protegiendo, tres frases cortas y un
   botón. Nada de párrafos ni de letra pequeña.

   Vive dentro de un .modal normal: aquí solo va lo que ese modal no trae.
   ------------------------------------------------------------------------ */

/* El gap del modal es de 16px y aquí sobra: son seis bloques seguidos y con
   ese aire la ventana no cabía de una vez en un teléfono. */
.promesa { gap: var(--s3); }

.promesa__escena {
  position: relative;
  display: grid;
  place-items: center;
  padding: 4px 0 2px;
}

/* El halo que la envuelve. Es el único recurso "protector" del conjunto: dos
   anillos que se abren despacio, sin brillos ni destellos, porque lo que se
   quiere transmitir es calma y no fiesta. */
.promesa__aura {
  position: absolute;
  width: 146px; height: 146px;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 46%,
              rgba(255,154,60,.30) 0%,
              rgba(255,154,60,.14) 42%,
              rgba(255,154,60,0) 70%);
  animation: promesaAura 4.4s var(--ease-in-out) infinite;
  pointer-events: none;
}
.promesa__aura::before,
.promesa__aura::after {
  content: '';
  position: absolute; inset: 16px;
  border-radius: 50%;
  border: 2px solid var(--brand);
  opacity: .18;
  animation: promesaAnillo 4.4s var(--ease-out) infinite;
}
.promesa__aura::after { animation-delay: 1.4s; }

@keyframes promesaAura {
  0%,100% { transform: scale(1);    opacity: .9 }
  50%     { transform: scale(1.06); opacity: 1 }
}
@keyframes promesaAnillo {
  0%   { transform: scale(.86);  opacity: .26 }
  70%  { transform: scale(1.14); opacity: 0 }
  100% { transform: scale(1.14); opacity: 0 }
}

/* Chispa va por encima del halo, no dentro de él. */
.promesa__chispa { position: relative; z-index: 1; }

/* El escudo se inyecta DENTRO del svg de Chispa, en el mismo viewBox, y
   colgando de .m-hold-r. Así cae exactamente en su mano y saluda con el brazo
   al entrar; pegado por fuera con position:absolute se quedaba flotando
   mientras el brazo se movía sin nada. */
.promesa__escudo { animation: promesaLatido 3.4s var(--ease-in-out) infinite; }
@keyframes promesaLatido {
  0%,100% { transform: translateY(0) }
  50%     { transform: translateY(-2.2px) }
}

.promesa__titulo { margin: 0; }

.promesa__texto {
  margin: 0;
  font-size: var(--fs-md);
  line-height: 1.65;
  font-weight: 700;
  color: var(--ink-2);
}

/* Las tres promesas. Una tarjeta y no tres, para que se lean como un bloque
   entero y no como una lista de condiciones. */
.promesa__lista {
  display: flex; flex-direction: column; gap: 2px;
  background: var(--brand-soft);
  border: 2px solid rgba(255,107,26,.22);
  border-radius: var(--r-lg);
  padding: var(--s3) var(--s4);
  text-align: left;
}
.promesa__fila {
  display: flex; align-items: center; gap: 12px;
  padding: 7px 0;
}
.promesa__fila + .promesa__fila { border-top: 2px solid rgba(255,107,26,.14); }
.promesa__fila__ico { font-size: 21px; flex: none; line-height: 1; }
.promesa__fila__t {
  font-size: var(--fs-sm); font-weight: 900; color: var(--ink);
  line-height: 1.35;
}
.promesa__fila__p {
  display: block;
  font-size: var(--fs-xs); font-weight: 700; color: var(--ink-2);
  line-height: 1.45; margin-top: 1px;
}

.promesa__cierre {
  margin: 2px 0 0;
  font-size: var(--fs-sm);
  font-weight: 900;
  color: var(--brand-dark);
  line-height: 1.5;
}

/* En oscuro, --brand-soft es un marrón muy bajo: el borde y el texto de cierre
   necesitan subir de tono o el bloque desaparece contra la tarjeta. */
html[data-theme="dark"] .promesa__lista { border-color: rgba(255,154,60,.30); }
html[data-theme="dark"] .promesa__fila + .promesa__fila { border-top-color: rgba(255,154,60,.18); }
html[data-theme="dark"] .promesa__cierre { color: var(--brand-2); }

/* En un teléfono corto —un 360x640 sigue siendo de lo más común en Android— el
   contenido pasaba del tope del modal y el botón quedaba por debajo del
   pliegue: había que desplazarse para poder continuar, que es exactamente la
   sensación de trámite que esta ventana viene a evitar.

   Se cede en la escena y en los huecos, no en el mensaje: las tres promesas y
   la frase de cierre se leen enteras igual. */
@media (max-height: 720px) {
  .promesa { gap: var(--s2); padding: var(--s4); }
  .promesa__escena { padding: 0; }
  .promesa__escena .mascot { --m-size: 72px; }
  .promesa__aura { width: 112px; height: 112px; }
  .promesa__aura::before, .promesa__aura::after { inset: 12px; }
  .promesa__texto { font-size: var(--fs-sm); line-height: 1.55; }
  .promesa__lista { padding: var(--s2) var(--s3); }
  .promesa__fila { padding: 5px 0; }
  .promesa__fila__ico { font-size: 19px; }
}

/* Y en las pantallas de verdad pequeñas —un 320x568 todavía se ve— se encoge
   lo decorativo hasta donde haga falta. Chispa sigue ahí, que es lo que hace
   que esto se sienta un gesto y no un aviso, pero sin su halo y a media talla. */
@media (max-height: 620px) {
  .promesa { gap: var(--s1); padding: var(--s3); }
  .promesa__escena .mascot { --m-size: 58px; }
  .promesa__aura { width: 88px; height: 88px; }
  .promesa__aura::before, .promesa__aura::after { display: none; }
  .promesa__fila { padding: 3px 0; }
  .promesa__cierre { font-size: var(--fs-xs); }
}

/* ------------------------- Insignias ------------------------- */

.badge {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  text-align: center;
}
.badge__disc {
  width: 66px; height: 66px;
  border-radius: 50%;
  display: grid; place-items: center;
  font-size: 30px;
  background: linear-gradient(160deg, var(--gold), var(--gold-dark));
  box-shadow: 0 4px 0 rgba(0,0,0,.14), inset 0 -4px 8px rgba(0,0,0,.16);
  position: relative;
  transition: transform .3s var(--spring);
}
.badge__disc::after {
  content: '';
  position: absolute; inset: 5px;
  border-radius: 50%;
  border: 2px dashed rgba(255,255,255,.4);
}
.badge:active .badge__disc { transform: scale(.92) rotate(-8deg); }
.badge.is-locked .badge__disc {
  background: var(--line);
  filter: grayscale(1);
  opacity: .55;
  box-shadow: none;
}
.badge__name {
  font-size: var(--fs-xs); font-weight: 900; line-height: 1.2;
  overflow-wrap: anywhere; max-width: 100%;
}

/* ------------------------- Separadores ------------------------- */

.sep {
  display: flex; align-items: center; gap: 12px;
  color: var(--ink-3); font-size: var(--fs-xs);
  font-weight: 900; text-transform: uppercase; letter-spacing: 1px;
}
.sep::before, .sep::after {
  content: ''; flex: 1; height: 2px; background: var(--line); border-radius: 2px;
}

/* ------------------------- Métricas ------------------------- */

.metric {
  display: flex; flex-direction: column; gap: 2px;
  padding: 12px;
  border-radius: var(--r-md);
  background: var(--card-2);
  border: 2px solid var(--line-2);
  min-width: 0;
}
.metric__label { font-size: 10px; font-weight: 900; text-transform: uppercase; letter-spacing: .5px; color: var(--ink-3); }
.metric__value { font-size: var(--fs-xl); font-weight: 900; line-height: 1.1; white-space: nowrap; }
.metric__delta { font-size: var(--fs-xs); font-weight: 900; }
.metric__delta.up   { color: var(--green-dark); }
.metric__delta.down { color: var(--red); }

/* minmax(0,1fr) y no 1fr: con 1fr las columnas no bajan de su min-content
   y el grid desborda en pantallas estrechas (p. ej. nombres de insignias largos). */
.grid-2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s3); }
.grid-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s3); }
.grid-4 { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--s3); }

/* ------------------------- Lista de comprobación ------------------------- */

.check {
  display: flex; align-items: flex-start; gap: 11px;
  padding: 12px 13px;
  border-radius: var(--r-md);
  background: var(--card);
  border: 2px solid var(--line);
  text-align: left;
  width: 100%;
  transition: background .2s, border-color .2s;
}
.check__box {
  width: 24px; height: 24px; flex: none;
  border-radius: 8px;
  border: 2px solid var(--line);
  display: grid; place-items: center;
  color: transparent;
  font-size: 14px; font-weight: 900;
  transition: all .25s var(--spring);
  margin-top: 1px;
}
.check.is-done { background: var(--green-soft); border-color: var(--green); }
.check.is-done .check__box { background: var(--green); border-color: var(--green); color: #fff; transform: scale(1.05); }
.check.is-done .check__text { text-decoration: line-through; color: var(--ink-3); }
.check__text { font-size: var(--fs-sm); font-weight: 700; line-height: 1.45; }

/* ------------------------- Skeleton / carga ------------------------- */

.dots { display: inline-flex; gap: 5px; align-items: center; }
.dots i {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--ink-3);
  animation: dotBounce 1.1s infinite var(--ease-in-out);
}
.dots i:nth-child(2) { animation-delay: .14s; }
.dots i:nth-child(3) { animation-delay: .28s; }

/* ------------------------- Scroll horizontal ------------------------- */

.hscroll {
  display: flex; gap: var(--s3);
  overflow-x: auto;
  padding: 2px var(--s5) 6px;
  margin: 0 calc(var(--s5) * -1);
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}
.hscroll::-webkit-scrollbar { display: none; }
.hscroll > * { scroll-snap-align: start; flex: none; }

/* ------------------------- Lectura en voz alta ------------------------- */

.speak-btn {
  display: inline-flex; align-items: center; gap: 6px;
  flex: none;
  padding: 7px 12px;
  border-radius: var(--r-full);
  border: 2px solid var(--line-2);
  background: var(--card);
  color: var(--ink-2);
  font-size: var(--fs-xs); font-weight: 900;
  letter-spacing: .4px; text-transform: uppercase;
  cursor: pointer;
  /* 44px de alto real: es un control que se pulsa con el pulgar. */
  min-height: 40px;
  transition: transform .12s var(--ease-out), background .2s, border-color .2s, color .2s;
  -webkit-tap-highlight-color: transparent;
}
.speak-btn:active { transform: scale(.94); }
.speak-btn.is-on {
  background: var(--brand-soft);
  border-color: var(--brand);
  color: var(--brand);
}
.speak-btn.is-on .speak-btn__ico { animation: pulseSoft 1.1s var(--ease-in-out) infinite; }
.speak-btn__ico { font-size: 16px; line-height: 1; }

.speak-btn--sm {
  min-height: 32px;
  padding: 4px 9px;
  border-width: 2px;
}
.speak-btn--sm .speak-btn__ico { font-size: 14px; }

/* Fila de encabezado de pregunta: el texto crece, el botón no. */
.q-head-row {
  display: flex; align-items: flex-start; gap: 10px;
}
.q-head-row > .grow { min-width: 0; }

/* ------------------------- Chispa habla -------------------------

   La mascota y la burbuja dejan de ser dos hermanos sueltos y pasan a ser un
   componente. Chispa se mete un poco por debajo de la burbuja —con margen
   negativo, no con position:absolute— para que se lea como un personaje que
   asoma y no como un icono pegado al lado.

   El margen negativo es la clave de que no tape nada: al reflujo, la burbuja
   simplemente crece hacia la derecha y el texto nunca queda debajo del
   dibujo. Con position:absolute sí lo habría tapado en pantallas estrechas. */

.chispa-dice {
  display: flex;
  align-items: flex-start;
  gap: 12px;
}
.chispa-dice .mascot {
  /* Se apoya un poco más abajo: la cola de la burbuja cae a la altura de su
     cara, que es donde la mirada la busca. */
  margin-top: 6px;
  /* Solapa el borde de la burbuja sin invadir su texto: el padding-left de
     .chispa-dice__voz le devuelve exactamente ese espacio. */
  margin-right: -14px;
  z-index: 1;
}
.chispa-dice__voz {
  padding-left: 26px;
  min-width: 0;      /* sin esto, un texto largo desborda la fila en móvil */
}
.chispa-dice--grande { gap: 14px; }

/* A 360 px el solape se reduce: hay que repartir el ancho, no lucirlo. */
@media (max-width: 380px) {
  .chispa-dice { gap: 8px; }
  .chispa-dice .mascot { margin-right: -10px; }
  .chispa-dice__voz { padding-left: 20px; }
  /* Chispa cede primero, porque el texto es lo que hay que poder leer. */
  .chispa-dice .mascot--md { --m-size: 80px; }
  .chispa-dice .mascot--sm { --m-size: 56px; }
}

/* Los dieciséis sitios que ya componían la fila a mano reciben el mismo trato
   sin tocar ni una línea de JavaScript: el selector reconoce el patrón
   —una mascota seguida de una burbuja— y lo compone igual que .chispa-dice.

   Se hace así a propósito. Reescribir los dieciséis para que llamaran al
   componente eran dieciséis oportunidades de romper una pantalla, y el
   resultado en pantalla es idéntico. UI.chispaDice() queda para el código
   nuevo, que sí nace usándolo. */

.mascot + .speech {
  padding-left: 26px;
  min-width: 0;
}
.mascot:has(+ .speech) {
  margin-top: 6px;
  margin-right: -14px;
  z-index: 1;
}

@media (max-width: 380px) {
  .mascot + .speech { padding-left: 20px; }
  .mascot:has(+ .speech) { margin-right: -10px; }
  /* En pantallas estrechas Chispa cede ancho antes que el texto. */
  .row > .mascot--sm:has(+ .speech) { --m-size: 56px; }
}
