/* =========================================================================
   Componentes premium reutilizables
   ========================================================================= */

/* ---------- TOPBAR ---------- */
.topbar{
  display:flex; align-items:center; gap:6px;
  padding:var(--safe-t) 8px 0; height:calc(var(--topbar-h) + var(--safe-t));
  background:linear-gradient(180deg, rgba(5,7,15,.94), rgba(5,7,15,.55));
  border-bottom:1px solid var(--stroke);
  backdrop-filter:blur(14px); -webkit-backdrop-filter:blur(14px);
  z-index:20;
  isolation:isolate;
  contain:layout style;
  transform:translateZ(0);
  position:relative;
  overflow:hidden;
}
.app.orbital-shell .topbar{background:linear-gradient(180deg,rgba(5,7,15,.84),rgba(5,7,15,.52))}
.app.orbital-shell .subbar{background:rgba(5,7,15,.5)}
.app.orbital-shell .topbar::after{content:'';position:absolute;inset:0;z-index:0;pointer-events:none;opacity:.26;background-image:radial-gradient(circle,rgba(125,225,255,.9) 0 1px,transparent 1.5px),radial-gradient(circle,rgba(255,210,100,.75) 0 1px,transparent 1.5px);background-size:118px 42px,173px 46px;animation:orbitalHudDust 18s linear infinite}
.app.orbital-shell .topbar>*{position:relative;z-index:1}
@keyframes orbitalHudDust{from{background-position:0 0,0 0}to{background-position:118px 0,-173px 0}}
.avatar{
  position:relative; width:36px; height:36px; flex:0 0 36px; border-radius:11px;
  background:var(--g-primary); box-shadow:var(--glow-blue);
  border:1.5px solid rgba(255,255,255,.28);
}
.avatar-face{
  position:absolute; inset:6px; border-radius:8px;
  background:radial-gradient(circle at 50% 34%, #fff 0 26%, transparent 27%), linear-gradient(180deg,#5D8BFF,#2E6BFF);
}
.avatar b{
  position:absolute; bottom:-6px; left:50%; transform:translateX(-50%);
  font-size:11px; padding:1px 7px; border-radius:99px;
  background:var(--bg-1); border:1px solid var(--c-neon); color:var(--c-neon);
  box-shadow:0 0 10px rgba(57,255,136,.45);
}
.res-strip{ flex:1; display:flex; gap:3px; overflow:hidden; min-width:0; }
.topbar-right{ display:flex; gap:6px; }
.icon-btn{
  width:32px; height:32px; border-radius:10px; font-size:16px;
  background:var(--glass); border:1px solid var(--stroke); color:var(--tx-mid);
  transition:transform var(--t-fast) var(--ease-back), background var(--t-fast);
}
.icon-btn:active{ transform:scale(.9); background:rgba(46,107,255,.25); }

/* ---------- CHIP DE RECURSO ---------- */
.res{
  display:flex; align-items:center; gap:2px; flex:1 1 0; min-width:0;
  height:28px; padding:0 3px; border-radius:99px;
  background:rgba(10,14,28,.85); border:1px solid var(--stroke);
  position:relative;
}
.res.hard{ flex:1.15 1 0; border-color:rgba(85,230,255,.42); }
.res .ico{ width:15px; height:15px; flex:0 0 15px; border-radius:4px; display:grid; place-items:center; font-size:9.5px; }
.res .val{
  flex:1 1 auto; min-width:0; font-size:11px; font-weight:800; letter-spacing:-0.2px;
  white-space:nowrap; text-align:center; font-variant-numeric:tabular-nums;
}
.res .plus{
  display:none;
}
.res.flash::after{
  content:""; position:absolute; inset:0; background:var(--c-neon); opacity:.35;
  animation:resFlash .5s var(--ease-out) forwards;
}
@keyframes resFlash{ to{ opacity:0 } }
/*
 * El icono del recurso da un salto con el destello. El velo solo tiñe el chip
 * y se pierde entre el resto de la barra; el salto es lo que hace que el ojo
 * vaya justo a la moneda que acaba de subir, que es el objetivo.
 */
.res.flash .ico{ animation:resIco .5s var(--ease-back); }
@keyframes resIco{ 0%,100%{ transform:scale(1) } 38%{ transform:scale(1.42) } }

/* ---------- ONDA DE TOQUE (la pone `tap()` en cualquier pulsable) ---------- */
/*
 * `position:absolute` es OBLIGATORIO, no una preferencia de maquetación: la
 * onda mide hasta 1,25 veces el lado mayor del pulsable, así que si cae en el
 * flujo deforma la caja que la contiene. Ya pasó una vez —una regla posterior
 * con la misma especificidad la puso en `relative` y todos los botones del
 * juego se estiraban al pulsarlos—, de ahí el `!important`: esto no es
 * estética, es la diferencia entre un efecto y un fallo de diseño.
 */
.tap-onda{
  position:absolute !important; border-radius:50%; pointer-events:none; z-index:6;
  flex:0 0 auto; margin:0;
  /* Transparente ya al 70 % del radio: se apaga antes del borde y por eso no
     necesita que el pulsable recorte su contenido. */
  background:radial-gradient(circle,
    rgba(255,255,255,.40), rgba(180,255,215,.16) 45%, transparent 70%);
  animation:tapOnda .44s var(--ease-out) forwards;
}
@keyframes tapOnda{
  from{ transform:scale(.28); opacity:.95; }
  to  { transform:scale(1);   opacity:0;   }
}

/* ---------- SUBBAR (energía / poder) ---------- */
.subbar{
  display:flex; align-items:center; gap:8px; padding:0 10px;
  height:var(--subbar-h); font-size:12px; color:var(--tx-mid);
  border-bottom:1px solid rgba(139,146,255,.10);
  background:rgba(5,7,15,.5); z-index:19;
  isolation:isolate;
  contain:layout style;
  transform:translateZ(0);
}
.pill{
  display:flex; align-items:center; gap:6px; padding:3px 10px; border-radius:99px;
  background:var(--glass); border:1px solid var(--stroke); font-size:11.5px; white-space:nowrap;
}
.pill.hot{ border-color:var(--stroke-hot); color:var(--c-neon); box-shadow:0 0 12px rgba(57,255,136,.18) inset; }
.pill.power{ border-color:rgba(255,211,78,.4); color:var(--gold); }
/* Las píldoras de dato NO se encogen: son cifras y a medias no dicen nada.
   El chip de objetivo es el único elástico y absorbe lo que sobre; `min-width:0`
   es imprescindible, porque un hijo flexible no baja de su contenido sin él y
   los puntos suspensivos nunca llegaban a aplicarse. */
.subbar > .pill{ flex:0 0 auto; }
.subbar > #pill-goal{
  flex:1 1 auto; min-width:0; margin-left:auto;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
/* Sin objetivo pendiente el chip se queda vacío: un borde flotando sin texto. */
.subbar > #pill-goal:empty{ display:none; }

/* ---------- NAVBAR ---------- */
.navbar{
  /* minmax(0,1fr) y no 1fr: con `1fr` las pestañas no pueden encogerse por
     debajo de su contenido y la barra se sale del marco en pantallas justas. */
  display:grid; grid-auto-flow:column; grid-auto-columns:minmax(0,1fr);
  padding-bottom:var(--safe-b); height:calc(var(--nav-h) + var(--safe-b));
  background:linear-gradient(0deg, rgba(5,7,15,.98), rgba(10,14,28,.82));
  border-top:1px solid var(--stroke);
  backdrop-filter:blur(16px); -webkit-backdrop-filter:blur(16px);
  z-index:20;
}
.nav-item{
  position:relative; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:3px;
  min-width:0; overflow:hidden;
  color:var(--tx-lo); font-size:10.5px; letter-spacing:.6px; text-transform:uppercase;
  transition:color var(--t-fast);
}
.nav-item > span:last-child{ max-width:100%; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.nav-item .nico{ font-size:21px; line-height:1; transition:transform var(--t-mid) var(--ease-back); filter:grayscale(1) opacity(.6); }
.nav-item.active{ color:var(--c-white); }
.nav-item.active .nico{ transform:translateY(-3px) scale(1.18); filter:none; }
.nav-item.active::before{
  content:""; position:absolute; top:0; left:50%; transform:translateX(-50%);
  width:38px; height:3px; border-radius:0 0 4px 4px; background:var(--g-action); box-shadow:var(--glow-neon);
}
.nav-item.active::after{
  content:""; position:absolute; inset:6px 10px; border-radius:14px; z-index:-1;
  background:radial-gradient(60% 60% at 50% 30%, rgba(57,255,136,.16), transparent 70%);
}

/* ---------- BADGE ---------- */
.badge{
  position:absolute; top:6px; right:calc(50% - 24px);
  min-width:17px; height:17px; padding:0 4px; border-radius:99px;
  background:var(--g-danger); color:#fff; font-size:10px; font-weight:800; line-height:17px; text-align:center;
  box-shadow:0 0 10px rgba(255,77,109,.7); animation:badgePop .4s var(--ease-back);
}
.badge.dot{ min-width:9px; height:9px; padding:0; right:calc(50% - 20px); }
@keyframes badgePop{ from{transform:scale(0)} to{transform:scale(1)} }

/* ---------- BOTONES ---------- */
.btn{
  position:relative; display:inline-flex; align-items:center; justify-content:center; gap:7px;
  padding:11px 18px; border-radius:var(--r-md); overflow:hidden;
  font-size:14px; font-weight:800; letter-spacing:.8px; text-transform:uppercase; color:#fff;
  background:var(--g-primary); box-shadow:var(--sh-2), inset 0 1px 0 rgba(255,255,255,.28);
  transition:transform var(--t-fast) var(--ease-back), filter var(--t-fast);
}
.btn:active{ transform:scale(.955); filter:brightness(1.15); }
.btn::after{
  content:""; position:absolute; top:0; left:-60%; width:35%; height:100%;
  background:linear-gradient(90deg, transparent, rgba(255,255,255,.42), transparent);
  transform:skewX(-22deg); animation:sheen 3.4s ease-in-out infinite;
}
/*
 * BARRIDO POR `transform`, NO POR `left`.
 *
 * Animar `left` obliga a recalcular MAQUETADO en cada fotograma, y esto vive en
 * `.btn::after`: lo lleva TODOS los botones del juego, a la vez y para siempre.
 * `transform` lo resuelve el compositor sin tocar el maquetado ni repintar.
 *
 * La cuenta, porque no es un cambio de unidad: `left` va en % del PADRE y
 * `translateX` en % del PROPIO elemento. El recorrido era de -60% a 130% del
 * padre —190%— y el elemento mide el 35% del padre, así que 190/35 = 542,86%
 * de su propio ancho. El `left:-60%` de arriba se queda como posición inicial.
 *
 * El `skewX` va DESPUÉS del `translateX`: las transformaciones se aplican de
 * derecha a izquierda, así que primero se inclina y luego se desplaza en
 * horizontal, que es exactamente lo que hacía `left`. Al revés, el
 * desplazamiento saldría inclinado.
 */
@keyframes sheen{
  0%,72%{ transform:translateX(0) skewX(-22deg) }
  100%  { transform:translateX(542.86%) skewX(-22deg) }
}
.btn.action{ background:var(--g-action); color:#032312; box-shadow:var(--glow-neon), inset 0 1px 0 rgba(255,255,255,.4); }
.btn.premium{ background:var(--g-premium); color:#2A1300; }
.btn.danger{ background:var(--g-danger); }
.btn.ghost{ background:var(--glass); border:1px solid var(--stroke); color:var(--tx-hi); box-shadow:none; }
.btn.ghost::after{ display:none; }
.btn.sm{ padding:7px 12px; font-size:12px; border-radius:10px; }
.btn.xs{ padding:5px 9px; font-size:11px; border-radius:8px; }
.btn.wide{ width:100%; }
.btn.big{ padding:16px 26px; font-size:18px; border-radius:var(--r-lg); }
.btn[disabled]{ filter:grayscale(.85) brightness(.6); pointer-events:none; }
.btn .sub{ font-size:10px; opacity:.85; font-weight:700; letter-spacing:.3px; text-transform:none; }

/* ---------- PANELES / CARDS ---------- */
.panel{
  position:relative; border-radius:var(--r-lg); padding:14px;
  background:var(--panel); border:1px solid var(--stroke);
  backdrop-filter:blur(12px); -webkit-backdrop-filter:blur(12px);
  box-shadow:var(--sh-2);
}
.panel::before{
  content:""; position:absolute; inset:0; border-radius:inherit; pointer-events:none;
  background:var(--g-panel); opacity:.75;
}
.panel > *{ position:relative; }
.panel-title{
  display:flex; align-items:center; gap:8px; margin:0 0 10px;
  font-size:13px; letter-spacing:2px; text-transform:uppercase; color:var(--tx-mid);
}
.panel-title::before{ content:""; width:3px; height:14px; border-radius:2px; background:var(--g-action); box-shadow:var(--glow-neon); }

.card{
  position:relative; border-radius:var(--r-md); padding:10px;
  background:var(--panel-soft); border:1px solid var(--stroke);
  transition:transform var(--t-fast) var(--ease-back), border-color var(--t-fast);
  overflow:hidden;
}
.card:active{ transform:scale(.975); }
.card.locked{ filter:grayscale(.7) brightness(.62); }
.card.sel{ border-color:var(--c-neon); box-shadow:var(--glow-neon); }

/* Rarezas */
.r-common   { --rc:var(--r-common); }
.r-rare     { --rc:var(--r-rare); }
.r-epic     { --rc:var(--r-epic); }
.r-legendary{ --rc:var(--r-legendary); }
.r-mythic   { --rc:var(--r-mythic); }
.rar{ border-color:color-mix(in srgb, var(--rc) 55%, transparent); }
.rar::before{
  content:""; position:absolute; inset:0; border-radius:inherit; pointer-events:none;
  background:linear-gradient(160deg, color-mix(in srgb, var(--rc) 30%, transparent), transparent 62%);
}
.rar.shine::after{
  content:""; position:absolute; top:-120%; left:-45%; width:45%; height:340%;
  background:linear-gradient(90deg,transparent,rgba(255,255,255,.30),transparent);
  transform:rotate(18deg); animation:cardShine 3.6s ease-in-out infinite;
}
/* Ver la nota de `sheen`: `left` maqueta, `transform` no. 170% del padre
   sobre un elemento del 45% = 377,78% de su ancho. */
@keyframes cardShine{
  0%,66%{ transform:translateX(0) rotate(18deg) }
  100%  { transform:translateX(377.78%) rotate(18deg) }
}

/* ---------- BARRAS ---------- */
/* `overflow:hidden` va en el RELLENO, no en la barra. Estaba en `.bar`, que
   mide 9 px, y recortaba por arriba y por abajo su propia etiqueta de 10 px:
   toda barra con label salía con el texto cercenado (perfil, misiones, logros,
   héroes, gacha, eventos, ligas). El recorte redondeado sólo lo necesita `i`. */
.bar{ position:relative; height:9px; border-radius:99px; background:rgba(255,255,255,.08); border:1px solid rgba(255,255,255,.06); }
.bar i{ display:block; height:100%; width:0; border-radius:99px; overflow:hidden; background:var(--g-action); box-shadow:0 0 10px rgba(57,255,136,.5); transition:width var(--t-slow) var(--ease-out); }
.bar.blue i{ background:var(--g-primary); box-shadow:var(--glow-blue); }
.bar.gold i{ background:linear-gradient(90deg,#FF8A00,#FFD34E); box-shadow:0 0 12px rgba(255,211,78,.55); }
.bar.hp   i{ background:linear-gradient(90deg,#B3123E,#FF4D6D); box-shadow:0 0 10px rgba(255,77,109,.5); }
.bar.lg{ height:14px; }
/* La etiqueta se centra sobre la barra sin depender de su altura: con `inset:0`
   dentro de una caja de 9 px la caja de línea no cabía. */
.bar .lbl{
  position:absolute; left:0; right:0; top:50%; transform:translateY(-50%);
  display:grid; place-items:center; line-height:1;
  font-size:10px; font-weight:800; letter-spacing:.6px; color:#fff; text-shadow:0 1px 3px #000;
  pointer-events:none;
}
/* `.bar i` ya recorta (`overflow:hidden`), así que la banda ancha de aquí abajo
   no se sale de la barra. */
/*
 * RAYAS DE LA BARRA DE PROGRESO.
 *
 * Iban por `background-position`, que repinta el degradado repetido en cada
 * fotograma. Y no hay una barra en pantalla: en las listas de mejoras y en la
 * cola de obra hay varias a la vez, todas repintándose de fondo.
 *
 * Ahora la banda es más ancha que su caja (200%) y se DESPLAZA con
 * `transform`. El patrón se repite cada 16 px en horizontal, así que recorrer
 * un múltiplo exacto y reiniciar es indistinguible del desplazamiento de
 * fondo — con la diferencia de que esto lo resuelve el compositor sin repintar.
 */
.bar.striped i::after{
  content:""; position:absolute; top:0; bottom:0; left:0; width:200%;
  background:repeating-linear-gradient(115deg, rgba(255,255,255,.16) 0 8px, transparent 8px 16px);
  animation:stripes 1s linear infinite;
  will-change:transform;
}
/* De -32 a 0, no de 0 a -32: el original desplazaba el fondo hacia la DERECHA
   (`background-position:32px`), y hay que conservar el sentido o las rayas
   correrían al revés. Con la banda al 200% de ancho, la caja queda cubierta en
   los dos extremos del recorrido. */
@keyframes stripes{ from{ transform:translateX(-32px) } to{ transform:translateX(0) } }

/* ---------- POPUPS ---------- */
.popup-bg{
  position:absolute; inset:0; pointer-events:auto;
  background:rgba(3,5,12,.78); backdrop-filter:blur(6px); -webkit-backdrop-filter:blur(6px);
  display:grid; place-items:center;
  /* El margen respeta la muesca y la barra de gestos: sin ellas, en un móvil
     con notch el diálogo se metía debajo del reloj del sistema. */
  padding:calc(18px + var(--safe-t)) 18px calc(18px + var(--safe-b));
  animation:fadeIn var(--t-mid) var(--ease-out);
  /* El velo tambien entra por opacidad: mismo motivo que `.popup` de abajo. */
  will-change:opacity;
}
.popup-bg.out{ animation:fadeOut var(--t-mid) var(--ease-out) forwards; }
@keyframes fadeIn{ from{opacity:0} to{opacity:1} }
@keyframes fadeOut{ to{opacity:0} }
.popup{
  /*
   * ANCHO RELATIVO AL HUECO, NO A LA PANTALLA.
   *
   * Era `min(94vw, 430px)` dentro de un contenedor que YA lleva 18 px de margen
   * a cada lado. En un móvil de 375 px eso pide 352 px de diálogo en 339 px de
   * hueco: el margen se lo comía el propio diálogo y quedaba pegado a los dos
   * bordes —justo lo que se veía en la pantalla de victoria—. Con `100%` mide
   * lo que le dejan, así que el margen se respeta en cualquier ancho.
   *
   * Lo mismo en vertical: `86vh` no descuenta el margen ni la muesca, y con un
   * diálogo alto (el resultado de misión, con botín y tres botones) el borde
   * superior tocaba la barra de estado.
   */
  width:min(100%,430px); max-height:100%; display:flex; flex-direction:column;
  border-radius:var(--r-xl); overflow:hidden;
  background:linear-gradient(170deg,#141C3A,#0A0E1C 60%);
  border:1px solid var(--stroke); box-shadow:var(--sh-3), 0 0 60px rgba(46,107,255,.22);
  animation:popIn var(--t-slow) var(--ease-back);
  /*
   * TODOS los carteles emergentes pasan por aqui. Sin capa propia, `popIn`
   * (transform + opacity) repintaba el cuadro Y lo que asomaba por detras en
   * cada fotograma de la entrada — con la base y sus animaciones debajo, eso
   * era el parpadeo reportado al abrir cualquier menu de edificio. Con
   * `will-change` la entrada es solo del compositor, y `contain:paint` impide
   * que nada de dentro invalide fuera del cuadro.
   */
  will-change:transform, opacity;
  contain:paint;
}
@keyframes popIn{ from{opacity:0; transform:translateY(28px) scale(.9)} to{opacity:1; transform:none} }
.popup-head{
  display:flex; align-items:center; gap:10px; padding:14px 16px;
  background:var(--g-panel); border-bottom:1px solid var(--stroke);
}
.popup-head h3{ margin:0; font-size:16px; letter-spacing:1.4px; text-transform:uppercase; flex:1; }
.popup-close{ width:30px; height:30px; border-radius:9px; background:var(--glass); border:1px solid var(--stroke); font-size:16px; color:var(--tx-mid); }
.popup-body{ padding:16px; overflow-y:auto; }
/* Sin `safe-b` aquí: ahora lo aporta el margen de `.popup-bg`, y sumarlo dos
   veces dejaba una banda vacía bajo los botones en móviles con barra de gestos. */
.popup-foot{ padding:12px 16px; display:flex; gap:10px; border-top:1px solid var(--stroke); }

/* ---------- TOAST ---------- */
.toast{
  pointer-events:none; display:flex; align-items:center; gap:9px;
  padding:9px 16px; border-radius:99px; font-size:13px; font-weight:700;
  background:rgba(10,14,28,.94); border:1px solid var(--stroke); box-shadow:var(--sh-2);
  animation:toastIn .3s var(--ease-back), toastOut .35s var(--ease-out) 2.1s forwards;
}
.toast.good{ border-color:var(--stroke-hot); color:var(--c-neon); }
.toast.bad{ border-color:rgba(255,77,109,.5); color:var(--bad); }
@keyframes toastIn{ from{opacity:0; transform:translateY(-18px) scale(.9)} }
@keyframes toastOut{ to{opacity:0; transform:translateY(-14px)} }

/* ---------- TABS ---------- */
.tabs{ display:flex; gap:6px; padding:8px 10px; overflow-x:auto; scrollbar-width:none; }
.tabs::-webkit-scrollbar{ display:none; }
.tab{
  flex:0 0 auto; padding:7px 14px; border-radius:99px; font-size:12px; font-weight:700;
  letter-spacing:.7px; text-transform:uppercase; color:var(--tx-lo);
  background:var(--glass); border:1px solid var(--stroke);
  transition:all var(--t-fast) var(--ease-out);
}
.tab.active{ color:#04210F; background:var(--g-action); border-color:transparent; box-shadow:var(--glow-neon); }

/* ---------- LOOT / RECOMPENSAS ---------- */
.loot-grid{ display:flex; flex-wrap:wrap; gap:8px; justify-content:center; }
.loot{
  display:flex; flex-direction:column; align-items:center; gap:3px;
  width:66px; padding:8px 4px; border-radius:12px;
  background:var(--panel-soft); border:1px solid var(--stroke);
}
.loot .ico{ font-size:22px; }
.loot .amt{ font-size:11.5px; font-weight:800; }
.loot.pop{ animation:lootPop .45s var(--ease-back) backwards; }
@keyframes lootPop{ from{opacity:0; transform:scale(.4) translateY(14px)} }
.reward-celebration{position:relative;overflow:hidden;border-radius:16px;padding:8px 4px 2px;background:radial-gradient(circle at 50% 8%,rgba(255,211,78,.16),transparent 46%),linear-gradient(180deg,rgba(18,28,64,.5),transparent 70%)}
.reward-orb{position:relative;z-index:2;width:66px;height:66px;margin:0 auto 8px;left:0;display:grid;place-items:center;border-radius:50%;background:radial-gradient(circle at 35% 28%,#fff7b0 0,#ffd34e 24%,#ff8a2b 58%,#ad2f82 100%);box-shadow:0 0 22px rgba(255,190,52,.72),0 0 52px rgba(255,95,180,.25);animation:rewardOrb .9s var(--ease-back),rewardPulse 1.8s ease-in-out 1s infinite;overflow:hidden}
.reward-orb img{width:58px;height:58px;object-fit:cover;border-radius:18px;filter:drop-shadow(0 0 8px rgba(85,230,255,.9))}
.reward-rays{position:absolute;z-index:0;left:50%;top:42%;width:560px;height:560px;transform:translate(-50%,-50%);opacity:.42;background:repeating-conic-gradient(from 0deg,rgba(255,211,78,.72) 0 4deg,transparent 4deg 14deg);-webkit-mask-image:radial-gradient(circle,transparent 0 12%,#000 20% 46%,transparent 72%);mask-image:radial-gradient(circle,transparent 0 12%,#000 20% 46%,transparent 72%);animation:rewardRays 12s linear infinite}
.reward-congrats{position:relative;z-index:2;left:0;margin:0 auto 7px;font-size:18px;font-weight:950;letter-spacing:1.2px;text-transform:uppercase;color:#ffe783;text-shadow:0 0 12px rgba(255,194,53,.72);animation:rewardCongrats .55s var(--ease-back)}
.reward-celebration>.txt-dim,.reward-celebration>.loot-grid{position:relative;z-index:2}
@keyframes rewardCongrats{from{opacity:0;transform:translateY(-10px) scale(.85)}to{opacity:1;transform:translateY(0) scale(1)}}
@keyframes rewardOrb{from{opacity:0;transform:scale(.2) rotate(-18deg)}to{opacity:1;transform:scale(1) rotate(0)}}
@keyframes rewardPulse{50%{filter:brightness(1.2);transform:scale(1.07)}}
@keyframes rewardRays{to{transform:translate(-50%,-50%) rotate(360deg)}}

/* ---------- FLY (partículas de recurso hacia el HUD) ---------- */
.fly{
  position:absolute; width:24px; height:24px; border-radius:50%;
  display:grid; place-items:center; font-size:14px;
  background:radial-gradient(circle,#fff,var(--c-neon)); box-shadow:var(--glow-neon);
  will-change:transform,opacity;
}

/* ---------- COST ---------- */
.cost{ display:inline-flex; align-items:center; gap:4px; font-size:12.5px; font-weight:800; }
.cost.no{ color:var(--bad); }

/* ---------- STAT ROW ---------- */
.stat{ display:flex; align-items:center; gap:8px; padding:6px 0; font-size:12.5px; border-bottom:1px dashed rgba(139,146,255,.14); }
.stat:last-child{ border-bottom:0; }
.stat .k{ color:var(--tx-mid); flex:1; }
.stat .v{ font-weight:800; }
.stat .up{ color:var(--c-neon); font-size:11.5px; }

/* ---------- TIMER ---------- */
.timer{ display:inline-flex; align-items:center; gap:4px; font-size:11.5px; color:var(--warn); font-variant-numeric:tabular-nums; }

/* ---------- EMPTY ---------- */
.empty{ text-align:center; padding:30px 16px; color:var(--tx-lo); font-size:13px; }

/* =========================================================================
   MOVIMIENTO DE INTERFAZ
   Nada aquí es decorativo por capricho: la entrada escalonada dirige la mirada
   de arriba abajo, el brillo marca lo que es reclamable y el confeti sella la
   recompensa. Todo respeta `prefers-reduced-motion`.
   ========================================================================= */

/* Entrada escalonada del contenido de cada pantalla */
.stagger > *{
  animation:cardIn .40s var(--ease-back) backwards;
  animation-delay:calc(var(--i, 0) * 42ms);
}
@keyframes cardIn{ from{ opacity:0; transform:translateY(16px) scale(.97) } }

/* Latido de "esto se puede reclamar" */
.pulse-ready{ animation:pulseReady 1.5s ease-in-out infinite; }
@keyframes pulseReady{
  0%,100%{ box-shadow:0 0 0 0 rgba(57,255,136,.42) }
  60%{ box-shadow:0 0 0 12px rgba(57,255,136,0) }
}

/* Barrido de luz sobre lo destacado */
.sheen{ position:relative; overflow:hidden; }
.sheen::after{
  content:""; position:absolute; top:-60%; left:-45%; width:38%; height:220%;
  background:linear-gradient(90deg,transparent,rgba(255,255,255,.30),transparent);
  transform:rotate(16deg); animation:sheenPass 3.2s ease-in-out infinite;
}
/* 175% del padre sobre un elemento del 38% = 460,53% de su ancho. */
@keyframes sheenPass{
  0%,62%{ transform:translateX(0) rotate(16deg) }
  100%  { transform:translateX(460.53%) rotate(16deg) }
}

/* Confeti de recompensa */
.confetti{
  position:absolute; width:10px; height:14px; border-radius:2px;
  will-change:transform,opacity; pointer-events:none;
}

/* ---------- ORBES DE PRODUCCIÓN (base) ---------- */
.orb-layer{ position:absolute; inset:0; pointer-events:none; }
.orb{
  position:absolute; width:46px; height:46px; margin:-23px 0 0 -23px;
  border-radius:50%; pointer-events:auto; cursor:pointer;
  display:grid; place-items:center; font-size:20px;
  background:radial-gradient(circle at 35% 30%, #FFFFFF, var(--c-neon) 45%, #0B7A3E 100%);
  box-shadow:0 0 14px rgba(57,255,136,.65);
  border:2px solid rgba(255,255,255,.55);
  transform:translate3d(0,0,0);
  will-change:transform;
  animation:orbIn .35s var(--ease-back) backwards, orbFloat 2.8s ease-in-out infinite .35s;
}
.orb::after{
  content:""; position:absolute; inset:-8px; border-radius:50%;
  border:1.5px solid rgba(57,255,136,.45); animation:orbRing 2.2s ease-out infinite;
  will-change:transform, opacity;
}
@keyframes orbIn{ from{ opacity:0; transform:translate3d(0,20px,0) scale(.2) } }
@keyframes orbFloat{ 0%,100%{ transform:translate3d(0,0,0) } 50%{ transform:translate3d(0,-8px,0) } }
@keyframes orbRing{ 0%{ transform:scale(.75); opacity:.85 } 100%{ transform:scale(1.3); opacity:0 } }
.orb.pop{ animation:orbPop .24s var(--ease-out) forwards; }
@keyframes orbPop{ to{ transform:scale(1.6); opacity:0 } }

/* ---------- AMBIENTE DE LA BASE ---------- */
.sky-traffic{ position:absolute; inset:0; overflow:hidden; pointer-events:none; }
.dropship{
  position:absolute; width:34px; height:9px; border-radius:6px;
  background:linear-gradient(90deg, rgba(107,160,255,.25), rgba(107,160,255,.85));
  box-shadow:0 0 14px rgba(107,160,255,.6);
  animation:fly linear infinite;
}
.dropship::after{
  content:""; position:absolute; right:-16px; top:3px; width:16px; height:3px;
  background:linear-gradient(90deg, rgba(57,255,136,.9), transparent);
}
@keyframes fly{ from{ transform:translateX(-60px) } to{ transform:translateX(calc(100vw + 60px)) } }

@media (prefers-reduced-motion: reduce){
  .stagger > *, .pulse-ready, .sheen::after, .orb, .orb::after, .dropship{ animation:none !important; }
}

/* =========================================================================
   ICONOGRAFÍA VECTORIAL (ver src/ui/icons.js)
   Sustituye a los emojis del sistema, que se dibujaban distinto en cada
   aparato y no se podían tematizar.
   ========================================================================= */
.ic{
  display:inline-block; vertical-align:-0.18em;
  width:1.15em; height:1.15em;
  flex:0 0 auto;
  /* Sin esto, un icono dentro de un botón captura el clic y el `event.target`
     deja de ser el botón. */
  pointer-events:none;
}
/* En contenedores que ya fijan un tamaño (celdas de rejilla, fichas de
   recurso) el icono ocupa el hueco completo en vez de escalar con la fuente.
   Se dimensiona por ALTURA con `aspect-ratio`: fijar ancho y alto al mismo
   porcentaje deformaba el icono cuando la caja no era cuadrada (los rótulos de
   edificio salían a 36x33). */
.ri .ic, .bimg .ic, .skin-prev .ic, .league-badge .ic, .tn-ico .ic{
  width:auto; height:62%; aspect-ratio:1/1; vertical-align:middle;
}
/* La ficha de recurso mide 16 px: con `1em` (10 px) el icono quedaba flotando
   en medio de la pastilla y no se distinguía una moneda de una célula. */
.res .ico .ic{ width:100%; height:100%; }
/* Píldoras de la subbarra: el texto es de 11,5 px y el icono se quedaba corto. */
.pill .ic{ width:1.35em; height:1.35em; }
/* Botones: un poco más grande que el texto, que va en mayúsculas. */
.btn .ic{ width:1.25em; height:1.25em; margin-right:.15em; }
/* Filas de lista y estadísticas. */
.stat .k .ic, .rt .ic, .cost .ic{ width:1.2em; height:1.2em; }

/* El coste dentro de un botón (subtítulo de "+1", "x10"…) va en línea y
   compacto: antes se le quitaban las etiquetas con una expresión regular para
   dejarlo en texto plano, lo que ahora borraría el SVG del icono. */
.btn .sub .cost{ display:inline-flex; align-items:center; gap:2px; margin:0 3px 0 0; }
.btn .sub .cost .ic{ width:1.1em; height:1.1em; }
.btn .sub{ display:inline-flex; align-items:center; flex-wrap:wrap; justify-content:center; }

/* ---------- ICONOS SOBRE SUPERFICIE DORADA ---------- */
/* Los iconos con identidad cromática dorada —estrella, gema, trofeo, moneda—
   desaparecían sobre el degradado premium: dorado sobre dorado. No basta con
   cambiar un icono suelto; son ocho sitios y cualquier botón `premium` nuevo
   tendría el mismo problema. Oscurecerlos deja la SILUETA, que es lo único que
   se lee a 16-32 px, y funciona con cualquier icono presente o futuro. */
.btn.premium .ic{ filter:brightness(.22) saturate(.5); }
.vip-badge{ display:grid; place-items:center; isolation:isolate; }
.vip-badge .ic{ width:56%; height:56%; filter:none !important; }
/* `speedup` ya viene en currentColor (hereda la tinta oscura del botón), así
   que no necesita el filtro y con él se empastaría. */
.btn.premium .ic--ink{ filter:none; }

/* ---------- CUENTA (Ajustes) ---------- */
.cuenta-registrada{
  display:flex; align-items:center; gap:10px;
  padding:9px 10px; margin-bottom:8px; border-radius:12px;
  background:rgba(57,255,136,.08); border:1px solid rgba(57,255,136,.30);
}
.cuenta-ico{ flex:0 0 auto; color:var(--c-neon); display:grid; place-items:center; }
.cuenta-txt{ min-width:0; display:flex; flex-direction:column; }
.cuenta-txt b{ font-size:13px; }
.cuenta-txt span{ font-size:11px; color:var(--tx-lo); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.cuenta-nota{ margin:0 0 10px; font-size:11.5px; line-height:1.5; color:var(--tx-lo); }
.cuenta-registrar{ display:flex; align-items:center; justify-content:center; gap:8px; margin-bottom:10px; }

/* ---------- PRÓXIMAMENTE ---------- */
/* Sistemas que existen pero esperan servidor (ranking, arena, clan). Se pintan
   como una promesa, no como un error: sin candado, sin gris apagado y con el
   acento del juego, para que se lea "viene" y no "roto". */
.prox{ text-align:center; padding:26px 18px; }
.prox-sello{
  display:inline-flex; align-items:center; gap:7px;
  padding:5px 12px; border-radius:999px; margin-bottom:14px;
  font-size:10.5px; font-weight:800; letter-spacing:2.5px;
  color:var(--c-neon); background:rgba(57,255,136,.10);
  border:1px solid rgba(57,255,136,.32);
}
.prox-titulo{ margin:0 0 8px; font-size:18px; font-weight:900; letter-spacing:.5px; }
.prox-texto{ margin:0 auto; max-width:34ch; font-size:13px; line-height:1.6; color:var(--tx-mid); }
.prox-nota{
  margin:14px auto 0; max-width:34ch; padding-top:12px;
  border-top:1px solid var(--stroke);
  font-size:11.5px; line-height:1.5; color:var(--tx-lo);
}
.prox-nota .ic{ color:var(--c-neon); vertical-align:-3px; }

/* Cuenta atrás de apertura. Cajas separadas D·H·M·S: un bloque de texto
   corrido ("16d 20h") se lee como una imagen fija; separado y con los segundos
   corriendo se ve que algo está en marcha. */
.prox-cd{ margin:18px 0 4px; }
.prox-cd .timer{ display:flex; justify-content:center; gap:8px; }
.prox-cd .timer > span:last-child{ display:flex; gap:8px; }
.prox-cd-seg{
  display:flex; flex-direction:column; align-items:center; gap:3px;
  min-width:54px; padding:8px 6px; border-radius:12px;
  background:var(--panel-soft); border:1px solid var(--stroke);
}
.prox-cd-seg b{
  font-size:22px; font-weight:900; line-height:1;
  /* Cifras de ancho fijo: sin esto el contador tiembla al pasar de 1 a 2. */
  font-variant-numeric:tabular-nums;
  color:var(--c-neon); text-shadow:0 0 14px rgba(57,255,136,.45);
}
.prox-cd-seg i{ font-style:normal; font-size:9.5px; letter-spacing:1.2px; color:var(--tx-lo); text-transform:uppercase; }
.prox-cd-ya{ font-size:17px; font-weight:900; color:var(--c-neon); }

/* =========================================================================
   CELEBRACIÓN DE SUBIDA DE NIVEL  (ui/celebra.js)
   Todo vive en `#fx-layer`, que está por encima de las pantallas y no recibe
   toques: la fiesta nunca puede tapar un botón ni comerse una pulsación.
   Todas las piezas se posicionan por su centro con `translate(-50%,-50%)`,
   porque el módulo entrega el punto central, no la esquina.
   ========================================================================= */
.cel-flash, .cel-anillo, .cel-rayos, .cel-cartel{
  position:absolute; transform:translate(-50%,-50%); pointer-events:none;
}

/* Golpe de luz que marca el instante exacto. */
.cel-flash{
  width:150px; height:150px; border-radius:50%;
  background:radial-gradient(circle, var(--c) 0%, rgba(255,255,255,.55) 22%, transparent 62%);
  /*
   * SIN `mix-blend-mode`. Lo tenia en `screen`, que es EXACTAMENTE el fallo que
   * ya se corrigio en `.cel-pantalla` (ver su bloque, mas abajo) y que aqui
   * quedo sin tocar.
   *
   * Una mezcla obliga al navegador a recomponer y repintar todo el contexto de
   * apilamiento que hay debajo en cada fotograma de la animacion. En Chrome de
   * escritorio no se nota; en el WebView de Android, con el mapa de la isla
   * entero debajo, se ve como un parpadeo de la pantalla completa cada vez que
   * algo sube de nivel — que es lo reportado.
   *
   * Sobre fondo oscuro, un degradado radial claro se ve practicamente igual
   * mezclado que sin mezclar: la diferencia era todo coste.
   */
  animation:celFlash .62s var(--ease-out) forwards;
  /* Se promete al compositor lo que va a cambiar: sin esto, Android decide capa
     a mitad de la animacion y ese cambio de decision tambien se ve. */
  will-change:transform, opacity;
}
@keyframes celFlash{
  0%{ opacity:0; transform:translate(-50%,-50%) scale(.2) }
  18%{ opacity:1; transform:translate(-50%,-50%) scale(1.05) }
  100%{ opacity:0; transform:translate(-50%,-50%) scale(1.7) }
}

/* Onda de choque. Se abre y se afina: si mantuviera el grosor parecería un aro
   sólido alejándose en vez de una onda perdiendo fuerza. */
.cel-anillo{
  width:60px; height:60px; border-radius:50%;
  border:3px solid var(--c); box-shadow:0 0 18px var(--c);
  animation:celAnillo .8s var(--ease-out) forwards;
  /* Anima `border-width` (repinta por fotograma) y lleva sombra: con capa
     propia ese repintado queda en su textura de ~200 px y no toca la capa
     entera. Ver el porque completo en `.cel-flash`. */
  will-change:transform,opacity;
}
@keyframes celAnillo{
  from{ opacity:.95; transform:translate(-50%,-50%) scale(.3); border-width:3px }
  to{ opacity:0; transform:translate(-50%,-50%) scale(3.4); border-width:.5px }
}

/* Abanico de rayos girando. El giro es lo que lo separa de un destello: quieto
   se lee como una calcomanía encima del objeto. */
.cel-rayos{
  width:230px; height:230px; border-radius:50%;
  background:conic-gradient(from 0deg,
    var(--c) 0deg 7deg, transparent 7deg 45deg,
    var(--c) 45deg 52deg, transparent 52deg 90deg,
    var(--c) 90deg 97deg, transparent 97deg 135deg,
    var(--c) 135deg 142deg, transparent 142deg 180deg,
    var(--c) 180deg 187deg, transparent 187deg 225deg,
    var(--c) 225deg 232deg, transparent 232deg 270deg,
    var(--c) 270deg 277deg, transparent 277deg 315deg,
    var(--c) 315deg 322deg, transparent 322deg 360deg);
  /*
   * SIN MASCARA Y SIN MEZCLA. Llevaba las dos, y las dos son de lo mas caro que
   * se le puede pedir a un WebView:
   *
   *  · `mask-image` obliga a renderizar el elemento en una textura aparte y
   *    aplicarle la mascara — y aqui el elemento GIRA, asi que ese paso se
   *    repite en cada fotograma de la animacion.
   *  · `mix-blend-mode` ademas fuerza a recomponer todo lo que hay debajo.
   *
   * Se quita la mascara sin sustituirla: el `border-radius:50%` ya recorta el
   * disco, y los rayos saliendo del centro se leen igual de bien que con el
   * hueco. Cualquier apano para recuperarlo —otra mezcla, un pseudo-elemento
   * encima— cuesta mas de lo que aporta.
   */
  opacity:.55;
  animation:celRayos .95s var(--ease-out) forwards;
  will-change:transform, opacity;
}
@keyframes celRayos{
  from{ opacity:0; transform:translate(-50%,-50%) scale(.25) rotate(0deg) }
  25%{ opacity:.6 }
  to{ opacity:0; transform:translate(-50%,-50%) scale(1.25) rotate(115deg) }
}

/* Cartel. Sale de golpe, sube y se va. Lleva sombra dura porque aterriza sobre
   cualquier fondo del juego y tiene que leerse en todos. */
.cel-cartel{
  display:flex; flex-direction:column; align-items:center; gap:1px;
  text-align:center; white-space:nowrap;
  animation:celCartel 1.15s var(--ease-out) forwards;
  /* Texto con doble sombra en movimiento: promovido, se rasteriza una vez y
     el compositor solo lo desplaza y funde. */
  will-change:transform,opacity;
}
.cel-cartel b{
  font-size:26px; font-weight:900; letter-spacing:1.5px; color:#fff;
  text-shadow:0 0 16px var(--c), 0 0 34px var(--c), 0 3px 6px rgba(0,0,0,.95);
}
.cel-cartel span{
  font-size:11px; letter-spacing:2.4px; text-transform:uppercase; color:var(--c);
  text-shadow:0 2px 5px rgba(0,0,0,.95);
}
@keyframes celCartel{
  0%{ opacity:0; transform:translate(-50%,-50%) scale(.55) }
  18%{ opacity:1; transform:translate(-50%,-62%) scale(1.12) }
  32%{ transform:translate(-50%,-64%) scale(1) }
  75%{ opacity:1; transform:translate(-50%,-95%) scale(1) }
  100%{ opacity:0; transform:translate(-50%,-125%) scale(.96) }
}

/* Halo de pantalla, sólo en las subidas grandes. Entra por los BORDES: un velo
   sobre el centro taparía justo lo que el jugador está mirando. */
.cel-pantalla{
  position:absolute; inset:0; pointer-events:none;
  background:radial-gradient(120% 80% at 50% 50%, transparent 45%, var(--c) 130%);
  /*
   * SIN `mix-blend-mode`. Tenía `screen`, y una mezcla a pantalla completa
   * obliga al navegador a recomponer y REPINTAR todo el contexto de
   * apilamiento en cada fotograma de la animación: sobre el mapa de la base
   * eso se veía como un parpadeo de la pantalla entera, teñido del color del
   * edificio (rojo en el arsenal). Reportado tal cual: «parpadea toda la
   * pantalla y se pone roja».
   *
   * Sobre un fondo oscuro, `screen` con este degradado y una capa translúcida
   * normal se ven prácticamente igual; la diferencia era todo coste. Se sube
   * un poco la opacidad para compensar lo que aportaba la mezcla.
   *
   * Sólo se anima `opacity`: es lo único que el compositor resuelve sin
   * repintar. `will-change` la sube a su propia capa y `contain` le impide
   * invalidar nada de alrededor.
   */
  opacity:0;
  will-change:opacity;
  contain:strict;
  animation:celPantalla .85s var(--ease-out) forwards;
}
@keyframes celPantalla{
  0%{ opacity:0 } 22%{ opacity:.62 } 100%{ opacity:0 }
}

@media (prefers-reduced-motion: reduce){
  .cel-flash, .cel-anillo, .cel-rayos, .cel-pantalla{ display:none !important; }
  .cel-cartel{ animation-duration:.01s; }
}

/* =========================================================================
   INVITACIÓN DIRECTA DE ARENA
   Una persona concreta esperando respuesta: ocupa el centro y pide decisión,
   a diferencia del aviso de presencia, que sólo informa y se va solo.
   Sólo se animan `transform` y `opacity`.
   ========================================================================= */
.arena-invitacion{
  position:fixed; left:50%; bottom:calc(var(--safe-b, 0px) + 86px);
  transform:translate(-50%, 24px);
  z-index:8500;
  display:flex; flex-direction:column; gap:8px;
  padding:12px 16px;
  min-width:min(86vw, 320px);
  border-radius:var(--r-lg, 18px);
  background:linear-gradient(135deg, rgba(13,18,34,.97), rgba(20,28,52,.97));
  border:1.5px solid #FFD34E;
  opacity:0;
  transition:transform .28s var(--ease-back, ease-out), opacity .22s linear;
}
.arena-invitacion.ai-dentro{ transform:translate(-50%, 0); opacity:1; }
.arena-invitacion.ai-fuera{ transform:translate(-50%, 16px); opacity:0; }
.arena-invitacion .ai-ico{ font-size:22px; line-height:1; color:#FFD34E; }
.arena-invitacion .ai-txt{ display:flex; flex-direction:column; gap:2px; }
.arena-invitacion .ai-txt b{ font-size:14px; color:#FFD34E; }
.arena-invitacion .ai-txt span{ font-size:11.5px; color:var(--tx-mid); }
.arena-invitacion .ai-acciones{ display:flex; gap:8px; }
.arena-invitacion .ai-acciones .btn{ flex:1; }

/* ==================================================================== */
/* CARTEL DEL PREMIO POR REGISTRARSE                                     */
/* ==================================================================== */
/*
 * Se usa en DOS sitios con fondos distintos —la pantalla de acceso, que es
 * oscura y a pantalla completa, y el panel de Cuenta de Ajustes— así que no
 * lleva fondo opaco propio: un velo dorado translúcido funciona sobre los dos
 * y no obliga a tener dos versiones del mismo componente.
 */
.premio-registro{
  display:flex; align-items:center; gap:10px;
  padding:9px 12px; border-radius:12px;
  background:linear-gradient(135deg, rgba(255,211,78,.16), rgba(255,211,78,.06));
  border:1px solid rgba(255,211,78,.38);
  /*
   * El resplandor va HACIA DENTRO (`inset`) y no como sombra exterior: el
   * cartel va pegado al botón, y una sombra por fuera se derramaría sobre él y
   * ensuciaría el borde blanco del botón de Google.
   */
  box-shadow:inset 0 0 18px rgba(255,211,78,.10);
  animation:premioLate 2.6s ease-in-out infinite;
}
.premio-registro .pr-ico{
  flex:0 0 auto; display:grid; place-items:center;
  width:34px; height:34px; border-radius:9px;
  background:rgba(255,211,78,.16);
  color:var(--gold);
}
.premio-registro .pr-txt{ flex:1 1 auto; min-width:0; display:flex; flex-direction:column; line-height:1.25; }
.premio-registro .pr-txt b{
  font-size:14px; font-weight:900; letter-spacing:.02em; color:var(--gold);
}
.premio-registro .pr-txt em{
  font-style:normal; font-size:11px; color:var(--tx-lo);
}
.premio-registro .pr-regalo{ flex:0 0 auto; color:var(--gold); opacity:.75; }

/*
 * Latido MUY contenido —un 1,5 % de escala— y lento.
 *
 * Es un adorno junto a la acción principal de la pantalla, no un reclamo: con
 * una animación marcada compite con el botón por la atención justo cuando el
 * jugador va a pulsarlo, que es el momento en que menos conviene distraerlo.
 */
@keyframes premioLate{
  0%, 100%{ transform:scale(1);      border-color:rgba(255,211,78,.38); }
  50%     { transform:scale(1.015);  border-color:rgba(255,211,78,.62); }
}
@media (prefers-reduced-motion: reduce){
  .premio-registro{ animation:none; }
}

/* ==================================================================== */
/* SALA DE ARENA CON CÓDIGO                                              */
/* ==================================================================== */
/*
 * El código se dicta en voz alta y se teclea a mano, así que va grande, en
 * cifra tabular y con separación entre caracteres: pegados y en la tipografía
 * normal, una `M` seguida de una `N` se confunden en un móvil.
 */
.sala-codigo{
  font-family:var(--f-num); font-variant-numeric:tabular-nums;
  font-size:34px; font-weight:900; letter-spacing:.22em;
  color:var(--gold); text-indent:.22em;      /* compensa el espaciado final */
  padding:10px 6px; border-radius:12px;
  background:linear-gradient(135deg, rgba(255,211,78,.14), rgba(255,211,78,.05));
  border:1px solid rgba(255,211,78,.34);
}
.sala-reloj{
  margin-top:6px; font-size:12px; color:var(--tx-mid);
  font-variant-numeric:tabular-nums;
}
.sala-reloj.caducada{ color:var(--bad); font-weight:800; }

.sala-input{
  width:100%; box-sizing:border-box;
  font-family:var(--f-num); font-variant-numeric:tabular-nums;
  font-size:26px; font-weight:900; letter-spacing:.20em; text-align:center;
  text-transform:uppercase; text-indent:.20em;
  padding:10px 6px; border-radius:12px;
  background:#0A1226; color:var(--tx-hi);
  border:1px solid var(--c-blue); outline:none;
}
.sala-input::placeholder{ color:var(--tx-lo); font-weight:700; }

.sala-aviso{
  min-height:16px; margin:8px 2px 0;
  font-size:11.5px; line-height:1.4; color:var(--tx-lo);
}
.sala-aviso.mal{ color:var(--bad); font-weight:800; }

/* Clasificación sin nadie por debajo del podio: se explica en vez de dejar
   un panel con una raya de corte y nada más. */
.rk-vacio{
  padding:14px 10px; text-align:center;
  font-size:11.5px; line-height:1.5; color:var(--tx-lo);
}

/* Paginado de la clasificación. Los dos botones comparten fila y ancho: uno al
   lado del otro con el mismo peso, porque ninguna de las dos acciones es más
   importante que la otra. */
.rk-paginado{ display:flex; gap:8px; margin-top:10px; }
/* No existe icono de flecha abajo: se rota el de arriba en vez de inventar un
   id — `ico()` con un nombre desconocido imprime la palabra. */
.rk-flecha-abajo{ transform:rotate(180deg); }

/* ---------------------------- CHAT DE CLAN ---------------------------- */
/*
 * El hilo tiene ALTURA FIJA y scroll propio. Sin ella, treinta mensajes
 * empujan hacia abajo el boton de salir del clan y la pestaña se vuelve un
 * rollo interminable; con ella el chat es un bloque mas de la pantalla.
 */
.clan-chat{
  height:190px; overflow-y:auto; overscroll-behavior:contain;
  display:flex; flex-direction:column; gap:4px;
  padding:8px; border-radius:8px;
  background:rgba(6,10,22,.55); border:1px solid rgba(85,230,255,.10);
  contain:layout style paint;
}
.clan-msg{ font-size:12px; line-height:1.45; word-break:break-word; }
.clan-msg b{ color:#8FA6D8; margin-right:4px; }
.clan-msg.me b{ color:#55E6FF; }

/* ------------------- FONDO CONGELADO BAJO LOS CARTELES ------------------- */
/*
 * Mientras hay un cartel abierto (`html.hay-cartel`, ver ui/popups.js) las
 * animaciones de las pantallas de fondo se PAUSAN — no se cortan: al cerrar
 * retoman donde estaban. El cartel y sus capas viven fuera de `.screen`
 * (#popup-layer, #toast-layer, #fx-layer), asi que nada suyo se congela.
 */
/*
 * LISTA FINITA, NO SELECTOR UNIVERSAL. La primera version era
 * `.screen *` — pausaba todo, si, pero al precio de recalcular el estilo de
 * CINCO MIL nodos al abrir y al cerrar cada cartel: 180 ms de paralisis por
 * toque, que era exactamente la lentitud que se queria curar (reportado: «el
 * cartel tarda un segundo en abrir hasta en computadora»). Esta lista son las
 * animaciones PERPETUAS de verdad —la misma familia que ya recoge el bloque
 * de `prefers-reduced-motion`— y tocarlas invalida decenas de nodos, no miles.
 */
html.hay-cartel .isla-atmos .at-scan,
html.hay-cartel .isla-atmos .at-ring,
html.hay-cartel .isla-atmos .at-mote,
html.hay-cartel .isla-atmos .at-fog,
html.hay-cartel .mp-camino-flujo,
html.hay-cartel .bslot.es-nucleo .bimg::after,
html.hay-cartel .bslot.obrando .bimg::before,
html.hay-cartel .bslot.obrando .bimg::after,
html.hay-cartel .bstate i,
html.hay-cartel .btn-asalto,
html.hay-cartel .btn-asalto::before,
html.hay-cartel .btn-asalto::after,
html.hay-cartel .beast-badge::after,
html.hay-cartel .pulse-ready,
html.hay-cartel .sheen::after,
html.hay-cartel .orb,
html.hay-cartel .orb::after,
html.hay-cartel .dropship,
html.hay-cartel .av-tira.anima,
html.hay-cartel .av-ring,
html.hay-cartel .av-ring2,
html.hay-cartel .av-orbit{
  animation-play-state:paused !important;
}

/* ------------------------- CAMPOS DE FORMULARIO ------------------------- */
/*
 * `.input` se usaba en los carteles (crear clan, chat) SIN existir en ningun
 * CSS: los campos salian con el estilo blanco del navegador sobre el tema
 * oscuro — reportado tal cual: «que cagada basica son esos dos formularios».
 * Un solo bloque para todo campo de texto de cartel.
 */
.input{
  width:100%; padding:11px 12px; border-radius:10px;
  background:rgba(6,10,22,.72); border:1px solid var(--stroke);
  color:#E6ECFF; font:inherit; font-size:14px;
  outline:none; -webkit-appearance:none;
}
.app.orbital-shell .topbar{background:linear-gradient(180deg,rgba(5,7,15,.82),rgba(5,7,15,.5))}
.app.orbital-shell .subbar{background:rgba(5,7,15,.46)}

/* Barra inferior y CTA con acabado sci-fi inspirado en la referencia visual. */
.navbar{
  background:linear-gradient(180deg,rgba(2,18,31,.97),rgba(1,10,20,.99));
  border-top:1px solid rgba(91,205,255,.38);
  box-shadow:0 -8px 28px rgba(0,121,190,.18),inset 0 1px 0 rgba(104,226,255,.12);
}
.nav-item{
  color:#6da9d0;
  font-size:10.5px;
  letter-spacing:1.1px;
  text-shadow:0 0 8px rgba(80,190,255,.2);
}
.nav-item .nico{font-size:28px;color:#65c9ff;filter:drop-shadow(0 0 5px rgba(42,169,255,.5));}
.nav-item.active{color:#d9f6ff;text-shadow:0 0 10px rgba(56,190,255,.75)}
.nav-item.active .nico{transform:translateY(-2px) scale(1.08);filter:drop-shadow(0 0 10px #42c9ff)}
.nav-item.active::before{width:56px;height:2px;background:linear-gradient(90deg,transparent,#4de1ff,transparent);box-shadow:0 0 14px #1dc9ff}
.nav-item.active::after{inset:4px 8px;border-radius:10px;background:radial-gradient(60% 70% at 50% 10%,rgba(37,180,255,.2),transparent 72%)}
.btn-asalto{
  position:relative;
  min-height:78px;
  padding:15px 30px 13px;
  border:1px solid rgba(102,255,206,.9);
  border-radius:7px;
  clip-path:polygon(2% 0,98% 0,100% 22%,98% 78%,96% 100%,4% 100%,0 78%,2% 22%);
  background:linear-gradient(180deg,#22ff9c 0%,#09bd72 58%,#057344 100%);
  color:#01281e;
  box-shadow:0 0 18px rgba(0,255,159,.72),0 0 48px rgba(0,169,255,.2),inset 0 2px 0 rgba(255,255,255,.75),inset 0 -5px 12px rgba(0,53,44,.42);
  text-shadow:0 1px 0 rgba(255,255,255,.35);
}
.btn-asalto::before{content:"";position:absolute;inset:5px;pointer-events:none;border:1px solid rgba(185,255,231,.48);clip-path:inherit;opacity:.9}
.btn-asalto .as-main{font-size:21px;font-weight:950;letter-spacing:2px;color:#eafff8;text-shadow:0 0 10px rgba(0,63,43,.9)}
.btn-asalto .as-sub{font-size:11px;letter-spacing:2.6px;color:#c8ffeb;text-shadow:0 1px 3px #075b43}
.input:focus{ border-color:rgba(85,230,255,.65); box-shadow:0 0 0 2px rgba(85,230,255,.16); }
.input::placeholder{ color:rgba(143,166,216,.45); }
.popup-body label{
  display:block; margin:12px 2px 6px; font-size:11.5px; font-weight:700;
  letter-spacing:.08em; text-transform:uppercase; color:var(--tx-mid, #8FA6D8);
}
.popup-body label:first-child{ margin-top:2px; }
