:root {
  /* Paleta EXACTA de la maqueta final aprobada (MIDAS_SENTINEL_CLOUD_HANDOFF,
     19/09) -- valores tomados literalmente de su <style>, no aproximados.
     Los NOMBRES de variable se mantienen (son los que consume el resto de
     este fichero, 2000+ líneas, en 7 páginas): remapear el valor cambia el
     look en cascada sin tener que tocar cada selector uno a uno. --accent
     deja de ser violeta y pasa a ser el "--blue" de la maqueta -- esta
     paleta no lleva violeta en ningún sitio; los degradados accent->accent-2
     (marca, botones, founder-badge) se convierten así en el mismo azul->cian
     que ya usa el gráfico de la maqueta, sin tocar esos selectores. */
  --bg: #020713;
  --bg-panel: #050f1c;
  --bg-card: #08152a;
  --border: rgba(117, 154, 195, 0.25);
  --text: #f4fbff;
  --text-dim: #8294ac;
  --accent: #178bff;
  --accent-2: #00eaff;
  --good: #35f3ac;
  --warn: #ffc400;
  --bad: #ff5b74;
  --g7777: #a855f7;
  --g4444: #fb923c;
  --gffff: #38bdf8;
  --radius: 14px;
  /* Borde/brillo cian "de panel" (paneles, header, ticker) -- mas vivido
     que --border, que es el neutro para separadores internos. */
  --glow-cyan-border: rgba(0, 234, 255, 0.3);
  --glow-cyan-soft: rgba(0, 208, 255, 0.1);
  /* Linea de energia de la cabecera / subrayado de nav activo. */
  --line: rgba(0, 234, 255, 0.26);
  /* Degradado diagonal de panel de la maqueta (.panel/.metric/.token) --
     mas rico que un --bg-card plano; se aplica selector a selector en las
     zonas visibles de index.html, no de golpe a los 2000 usos de --bg-card. */
  --panel-grad: linear-gradient(145deg, rgba(8, 24, 46, .88), rgba(3, 10, 23, .88));
  /* Alto real de .topbar (20/09) -- .mainnav es TAMBIEN position:sticky
     top:0 (fila propia debajo, no dentro de <header>), asi que si no
     coincide con la altura real de .topbar las dos se superponen al hacer
     scroll. Adivinarla por breakpoint (lo que habia aqui antes) se rompio
     tres veces en la misma tarde en cuanto .brand y .value-prop crecieron:
     un numero fijo por ancho de pantalla no puede seguir un texto que
     reajusta lineas de forma continua. Ahora la mide bg-fx.js con
     ResizeObserver sobre .topbar y la escribe aqui via JS -- este valor es
     solo el suelo de respaldo para el primer pintado, antes de que el
     script corra. */
  --topbar-h: 90px;
}

* { box-sizing: border-box; }

/* El color de fondo va SOLO en <html>, nunca en <body> -- .bg-fx es un
   hijo de <body> con position:fixed y z-index:-1, y por el orden de
   pintado de CSS ("backgrounds y bordes del elemento" se pintan ANTES
   que sus descendientes con z-index negativo, pero un hijo normal en
   flujo -- como el propio <body> visto desde <html> -- se pinta DESPUES
   de esos descendientes negativos) el fondo opaco de <body> tapaba
   completamente a .bg-fx, entero, sin dar ningun error: por eso ni las
   nebulosas ni los planetas ni el rayo ambiental se veian nunca en la
   pagina real, aunque en una prueba aislada mas simple (sin esta
   jerarquia exacta) todo funcionaba perfectamente. Medido y confirmado
   con una pagina de prueba antes de tocar esto. */
html {
  margin: 0;
  padding: 0;
  background: var(--bg);
}
body {
  margin: 0;
  padding: 0;
  color: var(--text);
  font-family: "Segoe UI", system-ui, -apple-system, sans-serif;
  overflow-x: hidden;
}

/* ---------- Fondo ambiental (fijo, detras de todo, no interactivo) ---------- */
/* Solo CSS: dos manchas de color a la deriva + un campo de estrellas fijo.
   Barato para la GPU (transform/background-position), no hay canvas ni JS.
   background-color y background-image van SEPARADOS (no en el shorthand
   combinado) a proposito: mezclar gradientes con un color solido dentro
   del shorthand "background: ..., var(--bg)" es valido en teoria, pero es
   facil que un navegador (o una regla de mayor especificidad mas abajo)
   invalide la propiedad entera y se pierda TODO el fondo sin avisar. Con
   las propiedades separadas, un fallo en una no arrastra a la otra. */
.bg-fx {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  overflow: hidden;
  background-color: var(--bg);
  background-repeat: no-repeat;
  /* Gradiente EXACTO de ".space" en la maqueta aprobada -- el toque de
     morado (rgba(76,26,156,...)) es del propio documento de referencia,
     es nebulosa ambiental, no un acento de interfaz (esos son solo
     azul/cian/dorado). IMPORTANTE: nunca mezclar un tamaño de elipse en px
     explicito CON un background-size en % -- el corte "transparent X%" +
     background-size es lo unico que controla el tamaño aqui. */
  background-image:
    radial-gradient(circle at 77% 44%, rgba(0, 132, 184, .18), transparent 30%),
    radial-gradient(circle at 28% 70%, rgba(76, 26, 156, .18), transparent 36%),
    linear-gradient(150deg, #061125 0%, #020712 48%, #03101a 100%);
  background-size: 180% 180%, 180% 180%, 100% 100%;
  /* La maqueta no anima este fondo -- se le da una deriva muy lenta (24s)
     porque el propietario pidio explicitamente mas "vida" de fondo en las
     rondas anteriores; el resto (estrellas, nebulosa, destellos) reproduce
     la maqueta al detalle. */
  animation: bg-drift 24s ease-in-out infinite alternate;
}
/* Estrellas parpadeantes por CANVAS (no CSS) -- identico a la maqueta:
   cada estrella respira con su propio desfase de fase (ver dibujarEstrellas
   en bg-fx.js), lo que da un titileo real en vez de un patron que se repite
   cada 340px como el punteado CSS anterior. El <canvas id="stars"> vive
   dentro de .bg-fx en el HTML; aqui solo se posiciona. */
#stars {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: .92;
}
/* Nebulosa desenfocada -- igual que ".nebula" de la maqueta, un unico blob
   grande que "respira" de tamaño. Va DEBAJO de las estrellas en el orden
   del DOM (antes en el HTML) para que las estrellas se vean nitidas encima. */
.nebula {
  position: absolute;
  inset: 10% -15% -20% 20%;
  filter: blur(80px);
  background: radial-gradient(ellipse at 65% 40%, rgba(0, 231, 255, .11), transparent 38%);
  animation: breathe 8s ease-in-out infinite;
}
/* Vinneta suave: acentua la profundidad sin llegar a oscurecer el
   contenido del centro, donde esta el feed. */
.bg-fx::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  background: radial-gradient(ellipse 95% 85% at 50% 40%, transparent 60%, rgba(4,5,10,.45) 100%);
}
@keyframes bg-drift {
  0%   { background-position: 0% 10%, 100% 90%, 0 0; }
  100% { background-position: 40% 55%, 62% 42%, 0 0; }
}
@keyframes breathe { 50% { opacity: .72; transform: scale(1.1); } }
@media (prefers-reduced-motion: reduce) { .nebula { animation: none; } }

/* Planetas: cruzan la pantalla en un arco lento (offset-path) y giran
   sobre si mismos, de tamaño y tipo distintos cada vez -- ver bg-fx.js.
   Capa propia con z-index explicito, entre las estrellas y la viñeta. */
.planet-layer { position: absolute; inset: 0; overflow: visible; pointer-events: none; z-index: 2; }
.planet {
  /* El circulo (y, para el tipo anillado, el anillo que sobresale) los
     dibuja el propio canvas -- sin border-radius aqui: el lienzo del
     tipo anillado es mas ancho que alto y un radio del 50% le cortaria
     los anillos por los lados. */
  position: absolute;
  top: 0; left: 0;
  animation: planet-cross linear forwards;
}
@keyframes planet-cross {
  0%   { offset-distance: 0%; opacity: 0; }
  6%   { opacity: .92; }
  94%  { opacity: .92; }
  100% { offset-distance: 100%; opacity: 0; }
}

/* Rayo ambiental de fondo: canvas a pantalla completa, dibuja un rayo
   tenue en un punto al azar cada 7-16s y se apaga -- distinto del rayo
   "de impacto" de la llegada de un token. mix-blend-mode:screen para que
   ilumine el fondo en vez de tapar lo que hay debajo con un rectangulo.
   Clase propia (NO ".bg-fx canvas"): los planetas tambien son <canvas>
   dentro de .bg-fx, y ese selector les pisaria posicion/tamaño/z-index. */
.bg-bolt-canvas {
  position: absolute;
  inset: 0;
  z-index: 4;
  mix-blend-mode: screen;
}

@media (prefers-reduced-motion: reduce) {
  .bg-fx, .bg-fx::before { animation: none; }
  .planet, .bg-bolt-canvas { display: none; }
}

/* Propuesta de valor central de la cabecera (20/09, sobre
   CABECERA_PROPUESTA_VALOR.html) -- sustituye al eslogan "Analizamos hoy..."
   de la ronda anterior. */
/* Reescrito 20/09 (cuarta vuelta): era position:absolute centrado sobre todo
   el ancho de .topbar, sin enterarse de cuanto sitio ocupaban de verdad
   .brand y .topbar-actions. Mientras los tres eran pequenos coincidia por
   pura casualidad; en cuanto la marca crecio (30px) el titulo empezo a
   pintarse literalmente ENCIMA de "MIDAS SENTINEL" en desktop, tablet y
   movil por igual (medido con getClientRects, no solo cajas). Ahora es un
   hijo flex real de .topbar, en medio de .brand y .topbar-actions en el
   propio orden del HTML: crece para llenar el hueco que sobra entre los
   otros dos (flex:1) y, si ese hueco no alcanza ni su minimo, .topbar
   (flex-wrap:wrap) lo manda a su propia fila -- automatico en cualquier
   ancho, sin adivinar puntos de corte. */
.value-prop {
  flex: 1 1 260px;
  min-width: 0;
  padding: 6px 14px;
  text-align: center;
  pointer-events: none;
}
.value-prop h1 {
  margin: 0;
  color: #f5fdff;
  font-size: 29px;
  line-height: 1.15;
  letter-spacing: .5px;
  text-shadow: 0 0 8px rgba(255, 255, 255, .4), 0 0 24px rgba(0, 220, 255, .68);
}
.value-prop h1 span { color: #42f4d2; }
.value-prop p {
  margin: 8px 0 10px;
  color: #c3d3e2;
  font-size: 16px;
  line-height: 1.45;
}
.value-prop code {
  font-family: "Courier New", monospace;
  font-size: .92em;
  color: #ffe9a8;
  background: rgba(255, 196, 0, .1);
  border: 1px solid rgba(255, 196, 0, .25);
  border-radius: 4px;
  padding: 1px 5px;
}
/* Frase final destacada: cierra el mensaje de verificacion tecnica, en cian
   para separarla visualmente del parrafo explicativo de arriba. */
.value-highlight {
  margin: 0 0 12px;
  color: var(--accent-2);
  font-weight: 700;
  font-size: 15px;
  line-height: 1.4;
  text-shadow: 0 0 10px rgba(0, 234, 255, .35);
}
/* Los 4 indicadores con icono: comparten clase con la copia identica que
   tiene .trust-card en el sidebar (mensaje distinto, mismos 4 conceptos) --
   por eso van sueltos, sin acoplar a .value-prop ni a .trust-card. */
.value-checks {
  display: flex;
  justify-content: center;
  align-items: stretch;
  gap: 8px;
  flex-wrap: wrap;
}
.value-check {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 8px 12px;
  border: 1px solid rgba(0, 234, 255, .35);
  border-radius: 12px;
  background: linear-gradient(160deg, rgba(6, 22, 44, .82), rgba(4, 12, 26, .82));
  box-shadow: 0 0 12px rgba(0, 234, 255, .16), inset 0 0 8px rgba(0, 234, 255, .06);
  pointer-events: auto;
}
.value-check svg {
  width: 17px;
  height: 17px;
  flex: none;
  fill: none;
  stroke: var(--accent-2);
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
  filter: drop-shadow(0 0 3px rgba(0, 234, 255, .5));
}
.value-check span {
  color: #d6f3ff;
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: .2px;
  white-space: nowrap;
}
@media (max-width: 1100px) {
  .value-prop h1 { font-size: 22px; }
  .value-prop p { font-size: 14px; }
  .value-highlight { font-size: 12.5px; }
  .value-check { padding: 6px 10px; }
  .value-check svg { width: 15px; height: 15px; }
  .value-check span { font-size: 11.5px; }
}
@media (max-width: 720px) {
  /* Por debajo de 720px .value-prop ya no cabe a la altura de .brand /
     .topbar-actions ni creciendo al maximo -- flex-wrap la manda a su
     propia fila (ver .value-prop { flex-basis } arriba); aqui solo se
     ajustan tamanos de fuente para esa fila completa, ya no un "top" a
     mano. */
  .value-prop { flex-basis: 100%; padding: 10px 16px 4px; }
  .value-check span { white-space: normal; }
  .value-prop h1 { font-size: 21px; }
  .value-prop p { font-size: 14px; max-width: 520px; margin: 8px auto 0; }
  .value-highlight { font-size: 12.5px; margin: 0 auto 10px; max-width: 480px; }
}
/* El ajuste de .brand h1/.tagline para movil muy estrecho vive junto a sus
   reglas base (mas abajo, tras ".tagline") a proposito -- misma especificidad
   que la base, y en CSS gana la ultima en el orden del fichero. Puesta aqui
   arriba, la base (mas abajo) se la comia siempre (mismo bug que ya paso con
   .topbar el 20/09). */

/* Barra de energia FIJA sobre la cabecera -- elemento propio en el HTML
   (".top-energy", primer hijo de .app/body), no un pseudo-elemento: la
   maqueta la trata como una pieza de marca permanente, no como un
   detalle del borde de .topbar. */
/* Intensificada 20/09 (version final aprobada): mas brillo/parpadeo, con
   "neonLinePulse" (brightness, no solo box-shadow) en vez de la version
   anterior. */
.top-energy {
  height: 3px;
  background: linear-gradient(90deg, transparent 1%, #008cff 11%, var(--accent-2) 32%, #eaffff 50%, var(--accent-2) 68%, #008cff 89%, transparent 99%);
  box-shadow: 0 0 4px #fff, 0 0 11px #73f7ff, 0 0 24px #00c8ff, 0 0 48px rgba(0, 112, 255, .82);
  animation: neon-line-pulse 2.8s ease-in-out infinite;
  position: relative;
  z-index: 21;
}
@keyframes neon-line-pulse {
  0%, 100% { filter: brightness(.86); opacity: .78; }
  50%      { filter: brightness(1.42); opacity: 1; }
}

/* Banner "en construccion" (23/09) -- ver el comentario en index.html junto
   al div. No sticky a proposito: se ve al cargar y se va con el scroll, no
   ocupa sitio mientras se navega el resto de la pagina. */
.construction-banner {
  background: linear-gradient(90deg, rgba(255, 196, 0, .28), rgba(255, 196, 0, .14));
  border-bottom: 2px solid var(--warn);
  color: #ffe17c;
  font-size: 19px;
  font-weight: 700;
  text-align: center;
  padding: 20px 20px;
  line-height: 1.5;
  letter-spacing: .2px;
}
.construction-banner strong { color: #fff; font-weight: 900; }
@media (max-width: 720px) {
  .construction-banner { font-size: 15px; padding: 16px 14px; }
}

.topbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  /* stretch (por defecto) repartiria el alto extra entre .brand y
     .topbar-actions si alguna vez van en filas distintas -- ver el bug de
     "en vivo" superpuesto documentado el 20/09 en el bloque ~720px. Con
     .value-prop ahora participando en el flujo (no position:absolute), es
     ademas el hijo cuya altura casi siempre marca la fila. */
  align-content: flex-start;
  justify-content: space-between;
  padding: 16px 20px;
  border-bottom: 1px solid var(--line);
  background: linear-gradient(180deg, rgba(2,8,21,.94), rgba(2,8,21,.7));
  backdrop-filter: blur(8px);
  position: sticky;
  top: 0;
  z-index: 20;
}
/* Linea de energia bajo la cabecera, intensificada igual que .top-energy --
   version final aprobada 20/09. */
.topbar::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -2px;
  height: 3px;
  background: linear-gradient(90deg, transparent 0%, #006eff 8%, var(--accent-2) 23%, #dfffff 48%, var(--accent-2) 76%, #006eff 92%, transparent 100%);
  box-shadow: 0 0 4px #fff, 0 0 10px var(--accent-2), 0 0 24px rgba(0, 173, 255, .95), 0 0 48px rgba(0, 92, 255, .48);
  animation: neon-line-pulse 3.2s .4s ease-in-out infinite;
}
/* Tercer efecto de luz (20/09, pedido explicito): una capsula de luz que
   recorre todo el borde inferior de la cabecera cada 6,5s -- distinta de
   los dos destellos fijos (.header-flare, que respiran en su sitio) y de
   la linea de fondo (que no se mueve). */
.topbar::before {
  content: "";
  position: absolute;
  z-index: 23;
  bottom: -4px;
  left: -14%;
  width: 160px;
  height: 7px;
  border-radius: 50%;
  background: linear-gradient(90deg, transparent, #fff 42%, #9effff 50%, #fff 58%, transparent);
  filter: blur(.4px);
  box-shadow: 0 0 11px #fff, 0 0 25px var(--accent-2), 0 0 46px #007bff;
  animation: header-sweep-kf 6.5s linear infinite;
  pointer-events: none;
}
@keyframes header-sweep-kf {
  0%   { left: -14%; opacity: 0; }
  8%   { opacity: 1; }
  88%  { opacity: 1; }
  100% { left: 103%; opacity: 0; }
}
/* Destellos viajeros sobre el borde inferior de la cabecera -- dos puntos
   de luz que recorren su propio arco de opacidad/escala, desfasados entre
   si (animation-delay negativo). Puramente decorativo: aria-hidden en el
   HTML, ver .header-flare ahi. */
.header-flare {
  position: absolute;
  z-index: 22;
  bottom: -5px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #fff;
  pointer-events: none;
  box-shadow: 0 0 6px #fff, 0 0 14px #68f5ff, 0 0 30px #00d9ff, 0 0 58px #008cff;
  animation: header-flare-kf 5.8s ease-in-out infinite;
}
.header-flare::before, .header-flare::after {
  content: "";
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  background: linear-gradient(90deg, transparent, #d9fdff, transparent);
  opacity: .9;
}
.header-flare::before { width: 92px; height: 2px; }
.header-flare::after { width: 2px; height: 28px; background: linear-gradient(180deg, transparent, #d9fdff, transparent); }
.header-flare.flare-a { left: 19%; animation-delay: -1.1s; }
.header-flare.flare-b { right: 20%; animation-delay: -3.9s; }
@keyframes header-flare-kf {
  0%, 100% { opacity: .18; transform: scale(.45); }
  18%      { opacity: 1;   transform: scale(1.22); }
  34%      { opacity: .28; transform: scale(.65); }
  50%      { opacity: .82; transform: scale(1); }
  72%      { opacity: .16; transform: scale(.5); }
}
@media (prefers-reduced-motion: reduce) {
  .top-energy, .header-flare, .topbar::after, .topbar::before { animation: none; }
}

.brand { display: flex; align-items: center; gap: 14px; }
/* Escudo-radar de marca (20/09, version final aprobada) -- reproduce
   ".shield" con el barrido conico girando, no el borde con clip-path de la
   ronda anterior. Selector .brand-mark reutilizado a proposito -- nada mas
   en el CSS/HTML que lo referencia cambia. */
.brand-mark {
  position: relative;
  width: 46px;
  height: 51px;
  flex: none;
  overflow: hidden;
  background: radial-gradient(circle at 50% 50%, rgba(0, 234, 255, .2), rgba(0, 81, 180, .08) 48%, transparent 70%);
}
.brand-mark::before {
  content: "";
  position: absolute;
  inset: 3px;
  border-radius: 50%;
  background: conic-gradient(from 0deg, transparent 0 72%, rgba(0, 234, 255, .8) 87%, transparent 100%);
  filter: drop-shadow(0 0 4px var(--accent-2));
  animation: brand-radar-sweep 2.8s linear infinite;
}
.brand-mark::after {
  content: "";
  position: absolute;
  left: 50%; top: 50%;
  width: 28px; height: 28px;
  transform: translate(-50%, -50%);
  border: 1px solid rgba(112, 243, 255, .68);
  border-radius: 50%;
  box-shadow: inset 0 0 0 6px rgba(0, 234, 255, .07), 0 0 8px rgba(0, 234, 255, .45);
}
.brand-mark i {
  position: relative;
  z-index: 3;
  display: block;
  width: 8px;
  height: 8px;
  margin: auto;
  top: 50%;
  transform: translateY(-50%);
  background: var(--warn);
  border-radius: 50%;
  box-shadow: 0 0 12px var(--warn);
}
@keyframes brand-radar-sweep { to { transform: rotate(360deg); } }

.brand h1 {
  margin: 0;
  font-family: "Chakra Petch", "Segoe UI", sans-serif;
  font-weight: 700;
  /* 20/09 (tercera vuelta): igualado en tamano a .value-prop h1 (29px) --
     el nombre de marca se quedaba pequeno al lado del mensaje central que
     acabamos de agrandar. */
  font-size: 30px;
  letter-spacing: .03em;
}
/* Degradado de texto para la mitad "acento" del nombre -- mismo par
   violeta/cian que la linea de energia y el icono. */
.brand h1 .accent {
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.tagline { margin: 4px 0 0; font-size: 15px; color: var(--text-dim); }
.tagline strong { color: var(--text); font-weight: 600; }
/* Entre 721 y 1100px .brand y .topbar-actions van en la MISMA fila que
   .value-prop (centrado, absolute) -- no se apilan como en movil. Al hacer
   .brand h1 mas grande (30px) se metia por debajo del parrafo centrado
   (visto en vivo: "MIDAS SENTINEL" literalmente debajo del texto de
   propuesta de valor). .value-prop YA se reducia en este corte (22px/56vw);
   reducido el nombre de marca en paralelo para que sigan "a juego" como
   pidio el usuario, y para dejarle sitio de verdad al centro. */
@media (max-width: 1100px) {
  .brand h1 { font-size: 23px; }
  .tagline { font-size: 12.5px; }
}
/* Movil muy estrecho (20/09): por debajo de ~340px "MIDAS SENTINEL" a 23px
   (heredado del corte de arriba) aun no cabe en una linea y el nombre de
   marca se parte en dos, empujando .tagline hacia abajo -- .value-prop
   (position:absolute, top fijo) no se entera de eso y se superponia con la
   marca. Reducido lo justo para que quepa en una linea otra vez, y el top
   de respaldo bajado por si acaso. */
@media (max-width: 360px) {
  .brand h1 { font-size: 20px; }
  .tagline { font-size: 12px; }
  .value-prop { top: 150px; }
}

@media (prefers-reduced-motion: reduce) {
  .brand-mark::before { animation: none; }
}

.topbar-actions { display: flex; align-items: center; gap: 12px; }

.conn-status {
  display: flex; align-items: center; gap: 6px;
  font-size: 12px; color: var(--text-dim);
}
.conn-status .dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--warn);
  box-shadow: 0 0 8px var(--warn);
}
.conn-status[data-state="live"] .dot { background: var(--good); box-shadow: 0 0 8px var(--good); }
.conn-status[data-state="down"] .dot { background: var(--bad); box-shadow: 0 0 8px var(--bad); }

.icon-btn {
  background: var(--bg-card);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 10px;
  padding: 6px 10px;
  cursor: pointer;
  font-size: 16px;
}
.icon-btn[aria-pressed="true"] { border-color: var(--accent-2); }
.ic-btn-cancelar { color: var(--bad); border-color: rgba(248,113,113,.4); margin-top: 6px; }
.ic-btn-cancelar:hover { background: rgba(248,113,113,.08); }

/* ---------- Tarjeta de confianza (lateral, junto al feed) ----------
   Reskin 19/09 sobre la maqueta final: pasa de tarjeta verde propia a
   ".panel"+".info" de la referencia -- fondo/borde cian neutro, el verde
   queda solo en el acento puntual (icono, "y vender"), como en la maqueta. */
.trust-card {
  border-radius: var(--radius);
  border: 1px solid var(--glow-cyan-border);
  background: var(--panel-grad);
  box-shadow: 0 0 22px rgba(0, 208, 255, .08), inset 0 0 24px rgba(10, 96, 148, .06);
  backdrop-filter: blur(8px);
  padding: 24px;
}
.trust-icon {
  width: 42px;
  height: 42px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 20px;
  border-radius: 50%;
  background: rgba(53, 243, 172, .14);
  border: 1px solid rgba(53, 243, 172, .4);
  margin-bottom: 12px;
}
/* Agrandado 20/09 (pedido explicito -- "se ha quedado todo un poco pequeño").
   Selector ".trust-card .trust-tagline" (no ".trust-tagline" a secas) a
   proposito -- el elemento es un <p> dentro de .trust-card, asi que
   tambien coincide con ".trust-card p" (mas abajo): con solo una clase de
   especificidad, ESA regla generica ganaba y el tamaño real quedaba en
   14.5px pese a que aqui pusiera 15.5px (visto al verificar en el
   navegador -- el CSSOM tenia la regla correcta, pero perdia el empate). */
.trust-card .trust-tagline {
  font-size: 15.5px;
  line-height: 1.65;
  color: #a9b8ca;
  margin: 0 0 18px;
}
.trust-card h2 {
  margin: 18px 0;
  font-family: "Chakra Petch", "Segoe UI", sans-serif;
  font-size: 20px;
  font-weight: 800;
  color: #fff;
  line-height: 1.45;
  letter-spacing: .01em;
}
.trust-card h2 em { font-style: normal; color: #31e6ba; }
.trust-card p {
  margin: 0 0 12px;
  font-size: 14.5px;
  line-height: 1.6;
  color: #cfd5e3;
}
.trust-card p strong { color: var(--text); }
.trust-link {
  display: inline-block;
  font-size: 13.5px;
  font-weight: 700;
  color: var(--accent-2);
  text-decoration: none;
}
.trust-link:hover { text-decoration: underline; }
/* Los 4 indicadores con icono (20/09, corregido: iban en la cabecera y
   pisaban el logo -- ver .value-prop mas arriba. Este es el sitio correcto,
   dentro de la tarjeta de confianza del sidebar donde ya vivia el mensaje
   "compra y vende sin miedo..." que sustituyen). .value-checks/.value-check
   son clases compartidas (definidas junto a .value-prop); aqui solo se
   ajusta la alineacion -- la version de cabecera los centraba, aqui van a
   la izquierda como el resto de la tarjeta. */
.trust-card .value-checks { justify-content: flex-start; margin-top: 4px; }

/* ---------- Aviso "aprende del historial antes de invertir" (index) ---------- */
.tip-banner {
  display: flex;
  gap: 16px;
  align-items: flex-start;
  border-radius: var(--radius);
  border: 1px solid rgba(251,191,36,.35);
  background: linear-gradient(160deg, rgba(251,191,36,.10), rgba(124,92,255,.05));
  box-shadow: 0 0 0 1px rgba(251,191,36,.08) inset;
  padding: 18px 20px;
  margin-bottom: 36px;
}
.tip-banner-icon {
  flex-shrink: 0;
  width: 38px;
  height: 38px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
  border-radius: 50%;
  background: rgba(251,191,36,.14);
  border: 1px solid rgba(251,191,36,.4);
}
.tip-banner h3 {
  margin: 0 0 6px;
  font-family: "Chakra Petch", "Segoe UI", sans-serif;
  font-size: 15px;
  font-weight: 700;
  color: var(--text);
}
.tip-banner p {
  margin: 0;
  font-size: 13px;
  line-height: 1.6;
  color: #cfd5e3;
}
.tip-banner p strong { color: var(--warn); }
.tip-banner p a { color: var(--warn); font-weight: 700; text-decoration: none; }
.tip-banner p a:hover { text-decoration: underline; }
@media (max-width: 640px) { .tip-banner { flex-direction: column; } }

.allinone-banner {
  padding: 12px 20px;
  border-bottom: 1px solid var(--border);
  background: linear-gradient(120deg, rgba(124,92,255,.12), rgba(251,191,36,.07));
  text-align: center;
}
.allinone-banner-inner { max-width: 1200px; margin: 0 auto; }
.allinone-banner h2 { margin: 0; font-size: 15px; font-weight: 700; }

/* ---------- Metricas de portada (reescrito 22/09, revision de UX) ----------
   Dos secciones de 4 tarjetas cada una (antes: una sola fila de 6,
   mezclando "actividad de hoy" con "rendimiento historico" -- ver
   #stats-bar-historico mas abajo). Mismos IDs para volatility-stats.js/
   app.js/funnel-stats.js (#stat-today, #stat-alltime, #vol-*,
   #funnel-hoy-*). OJO: acotado a "#stats-bar"/"#stats-bar-historico" (no
   ".metrics"/".metric" a secas) a proposito -- app.js YA usa esos mismos
   nombres de clase para la fila Par/Liquidez/Holders DENTRO de cada
   .token-card, y una regla sin acotar se los pisaria (visto al escribir
   esto la primera vez: dos ".metrics" identicas competian por
   grid-template-columns y una de las dos perdia segun el orden en el
   fichero). */
#stats-bar.metrics, #stats-bar-historico.metrics {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
  padding: 10px 20px;
}
/* "Actividad de hoy" bajo a 2 tiles (22/09 noche, ver comentario en
   index.html junto a "stats-bar") -- misma especificidad que la regla de
   arriba (1 id + 1 clase), gana por ir despues. Ancho maximo para que las
   dos tiles no se estiren a ocupar todo el ancho de la fila entera. */
#stats-bar.stats-bar-2col {
  grid-template-columns: repeat(2, 1fr);
  max-width: 620px;
}
#stats-bar .metric, #stats-bar-historico .metric {
  /* Bajado 22/09 noche (pedido explicito -- "agrupar mas estas lineas",
     hueco entre las dos secciones de metricas demasiado grande para que
     todo el resumen quepa sin scroll). Contenido identico, solo menos
     aire vertical por tarjeta. */
  min-height: 74px;
  padding: 11px 16px;
  border: 1px solid rgba(0, 205, 255, .38);
  border-radius: 10px;
  background: var(--panel-grad);
  box-shadow: inset 0 0 18px rgba(0, 145, 255, .04);
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: row; /* explicito a proposito, ver comentario junto a ".token-card .metrics" */
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
/* Eyebrow de cada seccion ("Actividad de hoy" / "Rendimiento historico
   observado") -- separa visualmente las dos historias que antes vivian en
   la misma fila (punto 5 de la revision: "separar claramente actividad del
   escaner, resultados historicos y accion del usuario"). */
.stats-section-label {
  /* 18px -> 11px (22/09 noche): ver comentario en "#stats-bar.metrics". */
  margin: 11px 20px 5px;
  font-size: 12.5px;
  font-weight: 800;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--accent-2);
}
.stats-section-label:first-of-type { margin-top: 8px; }
/* Iconos SVG por metrica (20/09, version final aprobada) -- sustituyen los
   emoji de la ronda anterior por los trazos vectoriales exactos de la
   maqueta, con el icono a la DERECHA del texto (no a la izquierda). Color
   por "currentColor": cian por defecto, y una clase modificadora por tipo
   (igual que la maqueta: .green/.gold/.red, sin prefijo "metric-icon-"). */
.metric-copy { min-width: 0; }
.metric-icon {
  flex: 0 0 38px;
  width: 38px;
  height: 38px;
  display: grid;
  place-items: center;
  color: #13dfff;
  filter: drop-shadow(0 0 7px currentColor);
}
.metric-icon svg {
  width: 32px;
  height: 32px;
  stroke: currentColor;
  fill: none;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.metric-icon.green { color: #23efbf; }
.metric-icon.gold  { color: var(--warn); }
.metric-icon.red   { color: #ff526d; }
/* Barrido de luz que cruza la tarjeta cada 6s -- igual que la maqueta,
   puramente decorativo. */
#stats-bar .metric::before, #stats-bar-historico .metric::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(110deg, transparent 30%, rgba(0, 234, 255, .08), transparent 65%);
  transform: translateX(-100%);
  animation: metric-sweep 6s infinite;
}
@keyframes metric-sweep { 55%, 100% { transform: translateX(120%); } }
/* Contraste subido 22/09 (pedido explicito -- "titulos de casillas con
   mayor contraste"): #a3b4c9 sobre el fondo casi negro de la tarjeta
   quedaba demasiado apagado para una etiqueta que hay que leer de un
   vistazo. */
#stats-bar .metric label, #stats-bar-historico .metric label {
  display: block;
  color: #c3d3ea;
  font-size: 13px;
  letter-spacing: .5px;
  text-transform: uppercase;
  line-height: 1.3;
}
#stats-bar .metric strong, #stats-bar-historico .metric strong {
  display: block;
  margin-top: 4px;
  font-size: 23px;
  font-family: "Chakra Petch", "Segoe UI", sans-serif;
}
#stats-bar .metric strong.cyan, #stats-bar-historico .metric strong.cyan { color: #34f5d2; }
#stats-bar .metric strong.gold, #stats-bar-historico .metric strong.gold { color: var(--warn); }
#stats-bar .metric strong.red, #stats-bar-historico .metric strong.red { color: var(--bad); }
/* Resalta el porcentaje dentro de la propia etiqueta ("Superan +250%",
   "Alguno supera +10.000%") -- pedido explicito, para que se lea de un
   vistazo sin tener que fijarse en el valor grande de abajo. */
#stats-bar .metric-highlight, #stats-bar-historico .metric-highlight {
  font-weight: 800;
  text-transform: none;
  letter-spacing: normal;
}
#stats-bar .metric-highlight.cyan, #stats-bar-historico .metric-highlight.cyan { color: #34f5d2; }
#stats-bar .metric-highlight.gold, #stats-bar-historico .metric-highlight.gold { color: var(--warn); }
@media (prefers-reduced-motion: reduce) { #stats-bar .metric::before, #stats-bar-historico .metric::before { animation: none; } }
@media (max-width: 1100px) { #stats-bar.metrics, #stats-bar-historico.metrics { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 720px)  { #stats-bar.metrics, #stats-bar-historico.metrics { grid-template-columns: 1fr 1fr; } }

/* "Calculando…" en vez de un guion permanente (22/09, pedido explicito --
   "nunca dejar guiones permanentes en la pagina principal"). Pulso sutil
   de opacidad en vez de texto estatico, para que se note que es un estado
   de carga y no un valor real; los scripts (app.js/funnel-stats.js/
   volatility-stats.js) quitan esta clase en cuanto pintan el numero real. */
.stat-loading {
  color: var(--text-dim) !important;
  font-weight: 600 !important;
  animation: stat-pulse 1.6s ease-in-out infinite;
}
@keyframes stat-pulse { 0%, 100% { opacity: .55; } 50% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .stat-loading { animation: none; opacity: .75; } }

/* Ya no en cursiva (22/09, pedido explicito -- "evitar textos largos
   completamente en cursiva") e interlineado subido a 1,5 para que se lea
   comodo en parrafos de una linea larga. */
.stats-hero-note {
  margin: 0;
  /* 16px -> 5px de padding inferior (22/09 noche) -- ver comentario en
     "#stats-bar.metrics". El texto no cambia, solo el aire debajo. */
  padding: 0 20px 5px;
  font-size: 13.5px;
  color: var(--text-dim);
  line-height: 1.45;
}
.stats-hero-note a { color: var(--accent-2); font-weight: 700; text-decoration: none; }
.stats-hero-note a:hover { text-decoration: underline; }

/* ---------- Embudo de deteccion (22/09, pedido explicito) ----------
   Clases propias (".funnel-*"), NUNCA ".metrics"/".metric" a secas -- ver
   el comentario junto a "#stats-bar.metrics" un poco mas arriba: esos
   nombres ya colisionaron una vez entre la barra de portada y las tarjetas
   de token, y el arreglo fue acotar cada uno a su propio ambito. Misma
   logica aqui: un ambito nuevo para un bloque nuevo. */
.funnel-stats {
  margin: 0 auto 28px;
  max-width: 1180px;
  padding: 26px 24px 22px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--panel-grad);
}
.funnel-head h2 {
  margin: 0 0 8px;
  font-size: 22px;
  line-height: 1.35;
  font-family: "Chakra Petch", "Segoe UI", sans-serif;
}
.funnel-head p {
  margin: 0 0 18px;
  color: var(--text-dim);
  font-size: 14.5px;
  line-height: 1.6;
  max-width: 780px;
}
.funnel-hero {
  margin: 0 0 18px;
  padding: 14px 18px;
  border: 1px solid var(--glow-cyan-border);
  border-radius: 10px;
  background: rgba(0, 234, 255, .05);
}
.funnel-hero p {
  margin: 0;
  font-size: 15.5px;
  line-height: 1.6;
}
.funnel-hero strong { color: var(--accent-2); font-family: "Chakra Petch", "Segoe UI", sans-serif; }
.funnel-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
  margin-bottom: 14px;
}
.funnel-metric {
  padding: 14px 16px;
  border: 1px solid rgba(0, 205, 255, .38);
  border-radius: 10px;
  background: var(--bg-card);
}
.funnel-metric label {
  display: block;
  color: #a3b4c9;
  font-size: 12.5px;
  letter-spacing: .4px;
  text-transform: uppercase;
  line-height: 1.3;
}
.funnel-metric strong {
  display: block;
  margin-top: 6px;
  font-size: 22px;
  font-family: "Chakra Petch", "Segoe UI", sans-serif;
  color: var(--good);
}
.funnel-highlight { color: var(--accent-2); font-weight: 800; text-transform: none; letter-spacing: normal; }
.funnel-note {
  margin: 0 0 18px;
  font-size: 12.5px;
  color: var(--text-dim);
  font-style: italic;
  line-height: 1.6;
  max-width: 900px;
}
.funnel-bullets {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px 22px;
  margin-bottom: 18px;
}
.funnel-bullet {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  font-size: 13.5px;
  color: var(--text);
}
.funnel-bullet span:first-child { flex: 0 0 auto; font-size: 16px; }
.funnel-audience {
  margin: 0 0 12px;
  font-size: 14px;
  line-height: 1.65;
  color: var(--text);
  max-width: 900px;
}
.funnel-disclaimer {
  margin: 0;
  font-size: 12px;
  color: var(--text-dim);
  line-height: 1.6;
  max-width: 900px;
}
@media (max-width: 900px) {
  .funnel-grid { grid-template-columns: repeat(2, 1fr); }
  .funnel-bullets { grid-template-columns: 1fr; }
}
@media (max-width: 520px) {
  .funnel-grid { grid-template-columns: 1fr 1fr; }
  .funnel-head h2 { font-size: 19px; }
}
/* [hidden] tiene la MISMA especificidad que ".funnel-grid"/".funnel-hero"
   (0,1,0) -- sin esto, el "display:grid"/bloque de esas clases gana por
   orden en la cascada y el atributo `hidden` deja de ocultar nada (mismo
   fallo ya documentado junto a ".sniper-form[hidden]" mas abajo). */
.funnel-grid[hidden], .funnel-hero[hidden] { display: none; }

/* ---------- Columna decorativa ".visual" + SPIDER-X (19/09, sobre la
   maqueta final aprobada MIDAS_SENTINEL_CLOUD_HANDOFF) ----------
   Sustituye al panel "Datos reales" de la ronda anterior. Puramente
   ambiental -- ninguna cifra real, aria-hidden, sin datos dinamicos. El
   grafico es un SVG estatico con dos trazados animados (cian y dorado) mas
   chispas viajeras -- igual que la maqueta, sin canvas ni libreria. */
.visual { position: relative; min-height: 540px; overflow: hidden; }
.energy-beams {
  position: absolute;
  z-index: 1;
  top: 0;
  right: 3%;
  width: 68%;
  height: 380px;
  pointer-events: none;
  overflow: hidden;
  opacity: .94;
}
.energy-beams i {
  position: absolute;
  left: 50%;
  top: 43%;
  width: 570px;
  height: 3px;
  transform-origin: left center;
  background: linear-gradient(90deg, rgba(190, 251, 255, .9), rgba(0, 211, 255, .54) 24%, transparent 76%);
  filter: blur(.6px);
  box-shadow: 0 0 12px #00d9ff, 0 0 28px rgba(0, 120, 255, .62);
}
.energy-beams i:nth-child(1) { transform: rotate(16deg);  animation: beam-pulse 4.8s ease-in-out infinite; }
.energy-beams i:nth-child(2) { transform: rotate(153deg); animation: beam-pulse 5.7s 1.1s ease-in-out infinite; }
.energy-beams i:nth-child(3) { transform: rotate(205deg); animation: beam-pulse 6.2s 2s ease-in-out infinite; }
@keyframes beam-pulse { 0%, 100% { opacity: .08; scale: .74 1; } 50% { opacity: .8; scale: 1 1; } }

/* Hueco para SPIDER-X (widget 3D real, montado aqui por spider-x-bootstrap.js
   -- ver ese fichero). El resplandor ambar+cian de detras es SUYO propio,
   no del modelo: se ve igual mientras el .glb todavia esta cargando. */
.spider-slot {
  position: absolute;
  top: 6px;
  right: 2%;
  width: 61%;
  height: 330px;
  z-index: 4;
}
.spider-slot::before {
  content: "";
  position: absolute;
  z-index: 0;
  left: 50%; top: 44%;
  width: 170px; height: 140px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 211, 74, .34) 0%, rgba(255, 152, 0, .16) 30%, transparent 69%);
  filter: blur(15px);
  animation: spider-core-pulse 3.6s ease-in-out infinite;
}
.spider-slot::after {
  content: "";
  position: absolute;
  z-index: 0;
  left: 50%; top: 64%;
  width: 430px; height: 105px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(ellipse, rgba(255, 178, 0, .14) 0%, rgba(0, 229, 255, .24) 34%, rgba(0, 116, 255, .09) 52%, transparent 74%);
  filter: blur(25px);
  opacity: .94;
}
@keyframes spider-core-pulse {
  0%, 100% { opacity: .62; transform: translate(-50%, -50%) scale(.92); }
  50%      { opacity: 1;   transform: translate(-50%, -50%) scale(1.13); }
}
/* El widget real (#spider-x-widget) se monta DENTRO de .spider-slot en modo
   "empotrado" -- ver la regla #spider-x-widget.spx-embedded mas abajo, junto
   al resto de reglas de SPIDER-X. */

/* Primera capa del grafico (20/09, version final aprobada) -- SVG propio,
   DEBAJO de ".chart" (z-index inferior): barras de volumen + una curva
   ascendente cian->dorado con su propio brillo, mas el texto que antes
   vivia en el panel "Datos reales" suelto. */
.market-depth {
  position: absolute;
  z-index: 1;
  inset: 46px -4% 0 -25%;
  width: 129%;
  height: 450px;
  /* Bajado de .72 a .45 el 22/09 (pedido explicito -- "la grafica domina
     tanto que parece decorativa y distrae del contenido funcional",
     "30-40% menos de contraste"). Sigue de fondo, ya no compite con el
     feed real. */
  opacity: .45;
}
.market-depth .volume-bar { fill: url(#barGlow); }
.market-depth .upper-trend {
  fill: none;
  stroke: url(#upperStroke);
  stroke-width: 2.3;
  filter: drop-shadow(0 0 7px #00dfff);
}
.market-depth .upper-glow { fill: none; stroke: #e7fcff; stroke-width: .8; opacity: .55; }
.market-depth .chart-caption { fill: #29dfff; font-size: 11px; letter-spacing: 2.2px; opacity: .72; }

.chart {
  position: absolute;
  z-index: 2;
  inset: 96px -4% 0 -25%;
  width: 129%;
  height: 438px;
  filter: drop-shadow(0 0 9px rgba(0, 234, 255, .78));
  /* Añadido 22/09, mismo motivo que ".market-depth" de arriba -- de fondo,
     no protagonista. */
  opacity: .65;
}
.chart .grid-line { stroke: rgba(80, 153, 203, .12); stroke-width: 1; }
/* Barras de fondo (20/09) -- la "primera grafica" sobre la que la linea
   ascendente (.blue-line/.gold-line) hace de tendencia por encima, igual
   que en la referencia. */
.chart .chart-bars rect {
  fill: url(#chartAreaGrad);
  opacity: .55;
}
.chart .blue-line { fill: none; stroke: #12ddff; stroke-width: 4; stroke-linecap: round; stroke-linejoin: round; }
.chart .blue-runner {
  fill: none; stroke: #fff; stroke-width: 6; stroke-linecap: round;
  stroke-dasharray: 3 132;
  filter: drop-shadow(0 0 10px #00eaff);
  animation: chart-run-blue 5.8s linear infinite;
}
.chart .gold-line { fill: none; stroke: var(--warn); stroke-width: 2.5; stroke-dasharray: 8 7; stroke-linecap: round; }
.chart .gold-runner {
  fill: none; stroke: #fff6a5; stroke-width: 4; stroke-linecap: round;
  stroke-dasharray: 2 155;
  filter: drop-shadow(0 0 10px var(--warn));
  animation: chart-run-gold 7.2s linear infinite;
}
.chart .chart-area { fill: url(#chartAreaGrad); }
.chart .point { fill: white; filter: drop-shadow(0 0 7px #00eaff); }
.chart .gold-point { fill: var(--warn); filter: drop-shadow(0 0 8px var(--warn)); }
.chart .travel-spark { filter: drop-shadow(0 0 6px currentColor) drop-shadow(0 0 14px currentColor); }
.chart .spark-tail { opacity: .13; filter: blur(4px) drop-shadow(0 0 8px currentColor) drop-shadow(0 0 18px currentColor); }
@keyframes chart-run-blue { to { stroke-dashoffset: -540; } }
@keyframes chart-run-gold { to { stroke-dashoffset: -620; } }
@media (prefers-reduced-motion: reduce) {
  .energy-beams i, .spider-slot::before, .chart .blue-runner, .chart .gold-runner, .chart .travel-spark {
    animation: none;
  }
}

/* ---------- "Ganadores de ayer" (rehecho 19/09 sobre la maqueta final) ----------
   Reproduce ".winners"/".ticker"/".coin"/".upgrade" de la referencia
   aprobada: una franja compacta de una sola fila, no una seccion propia con
   fondo degradado. Mismos IDs/clases para daily-winners.js (#dw-list,
   #dw-total, .daily-winner-item) -- solo cambia el estilo. */
/* Agrandada 20/09 (pedido explicito -- "se ve muy chiquitito") -- mas alto,
   mas relleno, textos y píldoras a mayor tamaño. Sigue siendo una franja de
   una fila (no la caja con fondo degradado de antes de la maqueta). */
.daily-winners {
  /* margen/padding recortados 22/09 noche -- ver comentario en
     "#stats-bar.metrics"; justo debajo va ahora la franja de fundador
     (.founder-bar), que no necesita tanto aire de separacion. */
  margin: 0 20px 10px;
  min-height: 84px;
  display: flex;
  align-items: center;
  gap: 24px;
  flex-wrap: wrap;
  border: 1px solid var(--glow-cyan-border);
  border-radius: 12px;
  padding: 12px 20px;
  background: rgba(4, 14, 29, .82);
  overflow: hidden;
}
.daily-winners[hidden] { display: none; }
/* Titulo + subtitulo apilados (20/09, version final -- ".winner-title" de
   la maqueta), no en linea base como antes. min-width fijo para que no
   "baile" al cambiar el numero de #dw-total. */
.daily-winners-head {
  display: flex;
  flex-direction: column;
  gap: 6px;
  flex: none;
  min-width: 240px;
}
/* Agrandado 22/09 tarde (pedido explicito -- "más llamativo, que se vea") */
.daily-winners-title {
  font-family: "Chakra Petch", "Segoe UI", sans-serif;
  font-size: 24px;
  font-weight: 800;
  color: #ffe17c;
  text-shadow: 0 0 14px rgba(255, 225, 124, .45);
  white-space: nowrap;
}
.daily-winners-sub { font-size: 17px; color: #c3d3ea; line-height: 1.4; }
.daily-winners-sub strong { color: var(--accent-2); font-weight: 800; }
/* Envoltorio de las flechas + el ticker -- las flechas son botones REALES
   (no decorativos) que desplazan #dw-list con scrollBy, ver daily-winners.js. */
.ticker-shell { display: flex; align-items: center; gap: 5px; min-width: 0; flex: 1; }
.ticker-arrow {
  flex: 0 0 30px;
  width: 30px;
  height: 30px;
  border: 0;
  background: transparent;
  color: #ffd64b;
  font-size: 26px;
  cursor: pointer;
  text-shadow: 0 0 10px var(--warn);
}
.daily-winners-list {
  display: flex;
  flex-wrap: nowrap;
  gap: 10px;
  overflow-x: auto;
  scroll-behavior: smooth;
  scrollbar-width: none;
  min-width: 0;
  flex: 1;
}
.daily-winners-list::-webkit-scrollbar { display: none; }
/* Agrandado 20/09 (segunda vuelta -- "los ganadores de ayer, ampliar tambien") */
.daily-winner-item {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: none;
  padding: 11px 18px;
  border-radius: 24px;
  border: 1px solid rgba(0, 234, 255, .2);
  background: #061423;
  text-decoration: none;
  white-space: nowrap;
  transition: border-color .15s ease, transform .15s ease;
}
.daily-winner-item:hover { border-color: var(--accent-2); transform: translateY(-1px); }
.daily-winner-pct { font-weight: 800; color: #2ef2c7; font-size: 16px; }
.daily-winner-symbol { font-size: 15px; color: var(--text); }

/* ---------- Reflejo animado de los botones Premium (20/09, version final) ----------
   Compartido por LOS TRES botones Premium de la web (.daily-winners-cta,
   .tpt-unlock, .hidden-banner-cta) -- igual que la maqueta aplica el mismo
   bloque a ".upgrade,.premium-btn,.bottom-lock button". Antes cada uno
   tenia su propio degradado dorado suelto y ninguno tenia el brillo
   diagonal que los cruza cada ~4s. */
.btn-premium-shine {
  position: relative;
  overflow: hidden;
  border: 1px solid #ffe171;
  background: linear-gradient(120deg, #fff0a2 0%, #ffd055 26%, #f5a900 67%, #ffca32 100%);
  color: #201300;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.85), inset 0 -2px 8px rgba(154,80,0,.2), 0 0 10px rgba(255,188,0,.7), 0 0 25px rgba(255,151,0,.28);
  text-shadow: 0 1px 0 rgba(255,255,255,.45);
  transition: transform .2s ease, box-shadow .2s ease;
}
.btn-premium-shine::before {
  content: "";
  position: absolute;
  top: -60%; bottom: -60%; left: -35%;
  width: 22%;
  transform: skewX(-22deg);
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.95), transparent);
  animation: premium-shine-kf 3.8s ease-in-out infinite;
}
.btn-premium-shine:hover {
  transform: translateY(-1px);
  box-shadow: inset 0 1px 0 #fff, 0 0 16px rgba(255,211,61,.95), 0 0 34px rgba(255,145,0,.42);
}
@keyframes premium-shine-kf {
  0%, 58%   { left: -35%; opacity: 0; }
  64%       { opacity: 1; }
  82%, 100% { left: 120%; opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .btn-premium-shine::before { animation: none; display: none; }
}

/* .daily-winners-cta / .daily-winners-cta-price quitados (23/09): el boton
   "Hazte Premium" de esta franja duplicaba al de la tarjeta fundador. Esa
   tarjeta sigue usando .btn-premium-shine (arriba), que por eso no se toca. */
@media (max-width: 720px) {
  .daily-winners { height: auto; }
  .daily-winners-list { flex-wrap: wrap; overflow: visible; }
}

/* ---------- Avisos de Telegram/Premium en el sidebar (rehechos 19/09) ----------
   Antes: badge suelto + titulo + parrafo, sin ninguna afordancia de "esto
   se puede pulsar". Ahora: icono + texto + flecha, mismo patron que una
   fila de accion de cualquier app -- se lee como algo que hacer, no como
   una nota al pie. */
.premium-teaser, .telegram-teaser {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 10px;
  padding: 11px 14px;
  border-radius: var(--radius);
  text-decoration: none;
  color: var(--text);
  transition: border-color .15s ease, transform .15s ease;
}
.premium-teaser:hover, .telegram-teaser:hover { transform: translateY(-1px); }

.premium-teaser {
  border: 1px solid rgba(255, 196, 0, .35);
  background: var(--panel-grad);
}
.premium-teaser:hover { border-color: var(--warn); box-shadow: 0 0 20px rgba(255, 196, 0, .18); }
.telegram-teaser {
  border: 1px solid var(--glow-cyan-border);
  background: var(--panel-grad);
}
.telegram-teaser:hover { border-color: var(--accent-2); box-shadow: 0 0 20px var(--glow-cyan-soft); }

.teaser-icon {
  flex: none;
  width: 34px;
  height: 34px;
  border-radius: 9px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
}
.premium-teaser .teaser-icon { background: rgba(251,191,36,.16); }
.telegram-teaser .teaser-icon { background: rgba(34,158,217,.16); }

.teaser-body { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.teaser-body strong { font-size: 15.5px; font-family: "Chakra Petch", "Segoe UI", sans-serif; }
.teaser-body span { font-size: 13px; color: var(--text-dim); line-height: 1.5; }

.teaser-arrow { margin-left: auto; flex: none; color: var(--text-dim); font-size: 17px; transition: transform .15s ease; }
.premium-teaser:hover .teaser-arrow, .telegram-teaser:hover .teaser-arrow { transform: translateX(2px); color: var(--text); }

main { padding: 20px; max-width: 1200px; margin: 0 auto; }

/* ---------- Grid de 3 columnas: info / token / visual (rehecho 19/09 sobre
   la maqueta final aprobada, MIDAS_SENTINEL_CLOUD_HANDOFF) ----------
   Antes eran 2 columnas (sidebar + contenido, con el token y el historial
   apilados dentro de "contenido"). La maqueta pide 3: info a la izquierda,
   el token gratis en el centro, y una columna decorativa a la derecha
   (".visual", con SPIDER-X). El historial sigue debajo, a todo el ancho --
   por eso hidden-banner/historial llevan grid-column:1/-1 en vez de vivir
   dentro de una cuarta columna. */
main.layout {
  display: grid;
  grid-template-columns: 330px 400px 1fr;
  align-items: stretch;
  gap: 18px 24px;
  max-width: none;
  margin: 0;
  padding: 20px 24px;
}
.sidebar { grid-column: 1; }
.token-col { grid-column: 2; min-height: 455px; }
.visual { grid-column: 3; }

/* ---------- Cabecera "token-alert" del token gratis (20/09, sobre
   TOKEN_ALERT_REFERENCIA.html -- reemplaza a .history-header suelta) ----------
   Radar + titulo + contador en una sola pieza destacada, en vez de un
   titulo pequeño y un contador aparte encima de la ficha. Colores
   deliberadamente literales (no var(--accent-2) etc.) -- la maqueta pide
   fidelidad exacta a estos tonos concretos, ligeramente mas verdosos que el
   cian del resto de la web. id="free-countdown-value" vive en el <b> de
   ".next-drop": lo sigue escribiendo actualizarCuentaAtras() en app.js sin
   ningun cambio, ver el comentario junto al marcado en index.html. */
.token-alert {
  position: relative;
  display: grid;
  grid-template-columns: 62px 1fr auto;
  align-items: center;
  gap: 13px;
  margin: 0 0 17px;
  padding: 13px 14px;
  border: 1px solid rgba(48, 241, 255, .46);
  border-radius: 12px;
  background:
    radial-gradient(circle at 12% 50%, rgba(0, 234, 255, .2), transparent 31%),
    linear-gradient(105deg, rgba(7, 34, 58, .94), rgba(3, 15, 32, .94));
  box-shadow: inset 0 0 22px rgba(0, 211, 255, .1), 0 0 18px rgba(0, 217, 255, .16);
}
.token-radar {
  position: relative;
  width: 56px;
  height: 56px;
  display: grid;
  place-items: center;
  border: 1px solid rgba(53, 245, 223, .65);
  border-radius: 50%;
  background: radial-gradient(circle, rgba(55, 244, 204, .24) 0 8%, rgba(0, 229, 255, .08) 9% 42%, transparent 44%);
  box-shadow: 0 0 12px rgba(40, 241, 218, .42), inset 0 0 15px rgba(0, 234, 255, .15);
}
.token-radar::before, .token-radar::after {
  content: "";
  position: absolute;
  border-radius: 50%;
  border: 1px solid rgba(48, 240, 223, .3);
}
.token-radar::before { inset: 9px; }
.token-radar::after { inset: 18px; }
.radar-sweep {
  position: absolute;
  inset: 3px;
  border-radius: 50%;
  background: conic-gradient(from 0deg, transparent 0 73%, rgba(54, 255, 214, .82) 91%, transparent 100%);
  animation: token-radar-sweep 2.4s linear infinite;
}
.radar-core {
  position: relative;
  z-index: 2;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #48ffc9;
  box-shadow: 0 0 6px #fff, 0 0 18px #24f4cf;
}
.token-alert-copy small { display: block; color: #74a0bb; font-size: 9px; font-weight: 800; letter-spacing: 1.5px; }
.token-alert-copy strong {
  display: block;
  margin-top: 3px;
  color: #eaffff;
  font-size: 16px;
  line-height: 1.05;
  letter-spacing: .35px;
  text-shadow: 0 0 10px rgba(0, 234, 255, .52);
}
.next-drop { text-align: right; }
.next-drop span { display: block; color: #7f9ab1; font-size: 8px; font-weight: 800; letter-spacing: 1px; }
.next-drop b {
  display: block;
  margin-top: 3px;
  color: #52ffe1;
  font-family: Consolas, monospace;
  font-size: 22px;
  letter-spacing: 1px;
  text-shadow: 0 0 9px #00d9ff, 0 0 19px rgba(0, 234, 255, .55);
}
/* Ampliada 22/09 (pedido explicito -- "debe ser la accion principal del
   usuario gratuito", antes quedaba pequeña). Mismo grid de 3 columnas,
   solo mas alta y con una nota + CTA dentro de la propia tarjeta. */
.token-alert--big {
  padding: 20px 22px;
  margin-bottom: 20px;
  grid-template-columns: 74px 1fr auto;
}
.token-alert--big .token-radar { width: 68px; height: 68px; }
.token-alert--big .token-alert-copy strong { font-size: 19px; }
.token-alert-note {
  display: block;
  margin-top: 8px;
  color: var(--text-dim);
  font-size: 13px;
  line-height: 1.5;
  max-width: 46ch;
}
.token-alert-cta {
  display: inline-block;
  margin-top: 10px;
  padding: 7px 14px;
  border: 1px solid rgba(53, 245, 223, .5);
  border-radius: 999px;
  color: #d8fff6;
  font-size: 12.5px;
  font-weight: 700;
  text-decoration: none;
  background: rgba(53, 245, 223, .1);
  white-space: nowrap;
}
.token-alert-cta:hover { background: rgba(53, 245, 223, .2); }
@keyframes token-radar-sweep { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .radar-sweep { animation: none; } }
@media (max-width: 720px) {
  .token-alert { grid-template-columns: 52px 1fr; }
  .token-radar { width: 48px; height: 48px; }
  .next-drop {
    grid-column: 1 / -1;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding-top: 9px;
    border-top: 1px solid rgba(0, 234, 255, .18);
    text-align: left;
  }
  .next-drop b { font-size: 24px; }
}
#hidden-banner, main.layout > #historial { grid-column: 1 / -1; }
.sidebar .trust-card { margin-bottom: 0; }
/* Dentro de .sidebar-sticky (flex en desktop) la trust-card nunca se
   encoge -- todo el recorte de altura lo absorbe el dock de graficas
   (flex:1 + overflow-y:auto), nunca el texto de confianza. */
.sidebar-sticky .trust-card { flex-shrink: 0; }
/* El aside se estira a la altura del feed (align-items:stretch) solo para
   darle sitio al sticky de abajo -- sin eso, el contenedor del sticky
   mediria solo lo alto que es la tarjeta y no tendria recorrido para
   seguir el scroll. El sticky vive en .sidebar-sticky (trust-card + dock de
   graficas juntos) para que los dos se muevan como un solo bloque -- antes
   solo estaba en .trust-card, que era lo unico que habia. */
@media (min-width: 901px) {
  /* Sin el tope de altura + flex, el bloque (trust-card + dock) crecia sin
     limite al abrir 2-3 graficas y solo se veia bajando TODA la pagina --
     el propio feed quedaba "por delante" del sticky en vez de al lado.
     Con esto el bloque entero nunca pasa de la altura visible, la
     trust-card conserva su alto natural arriba, y el dock (flex:1 + su
     propio overflow-y) es lo unico que hace scroll, y solo dentro de si
     mismo -- justo lo pedido: "poder hacer scroll en esa parte". */
  .sidebar-sticky {
    position: sticky;
    top: 132px;
    max-height: calc(100vh - 132px - 24px);
    display: flex;
    flex-direction: column;
    /* Red de seguridad (19/09, fallo real reportado): el diseño asume que
       trust-card + los dos avisos de Telegram/Premium SIEMPRE caben enteros
       y solo .chart-dock hace scroll interno (ver comentario de arriba).
       Pero eso depende de la altura del contenido, y en una ventana mas baja
       (portatil, zoom del navegador) esa suma puede superar max-height. Sin
       overflow, un elemento sticky que se desborda NO se recorta: pinta por
       ENCIMA de lo que haya despues en la pagina (paginacion, formulario de
       contacto, footer), que es justo el solape que se reporto. Con esto,
       en el peor caso aparece una barra de scroll en el bloque entero --
       mal menor comparado con tapar el resto de la pagina. */
    overflow-y: auto;
    overflow-x: hidden;
  }
}
/* Breakpoints EXACTOS de la maqueta para su ".feed" -- aqui aplicados a
   main.layout, que es el equivalente real con 3 columnas + historial. */
@media (max-width: 1100px) {
  main.layout { grid-template-columns: 290px 1fr; }
  .token-col { grid-column: 2; }
  /* La columna decorativa no desaparece: pasa a fondo, muy tenue, detras
     del token -- igual que ".visual{position:absolute;opacity:.45}" de la
     maqueta. position:relative en .token-col (añadido en su propia regla)
     la ancla ahi en vez de al layout entero. */
  .visual {
    grid-column: 2;
    grid-row: 1;
    position: absolute;
    inset: 0 0 0 42%;
    opacity: .45;
    z-index: -1;
  }
  .token-col { position: relative; z-index: 1; }
}
@media (max-width: 900px) {
  main.layout { grid-template-columns: 1fr; }
  .sidebar, .token-col, .visual, #hidden-banner, main.layout > #historial { grid-column: 1; }
}
@media (max-width: 720px) {
  main.layout { display: block; }
  .token-col { margin-top: 12px; }
  .visual { position: relative; inset: auto; height: 310px; opacity: 1; z-index: auto; margin-top: 16px; }
}

/* ---------- Dock de graficas del sidebar (ver abrirGraficaIC en app.js) ----------
   Iframes de DexScreener, creados/destruidos al abrir/cerrar -- nunca mas de
   MAX_CHARTS a la vez (2 por defecto). Cero peticiones propias: todo el
   trafico del grafico va directo del navegador a dexscreener.com. */
.chart-dock {
  margin-top: 16px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  /* flex:1 le da todo el alto que sobre dentro de .sidebar-sticky una vez
     descontada la trust-card; min-height:0 es imprescindible -- sin el, un
     hijo flex no se encoge por debajo de su contenido y el overflow-y de
     abajo nunca llegaria a activarse. Solo importa en desktop (sticky),
     ver el media query de main.layout -- en movil no hace falta limitar
     nada, el scroll normal de la pagina ya lo resuelve. */
  min-height: 0;
  overflow-y: auto;
  padding-right: 4px;
}
/* Barra de scroll visible a proposito -- el raton sobre un grafico hace
   zoom en la propia grafica (igual que en dexscreener.com), asi que la
   rueda casi nunca llega a mover este contenedor. Con el thumb bien visible
   se puede arrastrar a mano; los botones de abajo (.chart-dock-nav) son la
   via que funciona SIEMPRE, sin depender de acertar con el raton fuera del
   iframe. */
.chart-dock::-webkit-scrollbar { width: 8px; }
.chart-dock::-webkit-scrollbar-track { background: transparent; }
.chart-dock::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }
.chart-dock::-webkit-scrollbar-thumb:hover { background: var(--accent-2); }
.chart-dock-nav {
  display: flex;
  gap: 8px;
  margin-top: 8px;
  flex-shrink: 0; /* fuera del area que hace scroll -- siempre visible */
}
.chart-dock-nav button { flex: 1; padding: 5px; font-size: 13px; }
.chart-dock-hint {
  font-size: 12px; color: var(--text-dim); line-height: 1.5;
  border: 1px dashed var(--border); border-radius: var(--radius);
  padding: 14px; text-align: center; margin: 0;
}
.chart-slot {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-card);
  overflow: hidden;
  /* Sin esto, .chart-dock (flex column con altura limitada) ENCOGIA cada
     tarjeta de grafica para que las dos cupieran sin desbordar, en vez de
     dejarlas a su alto natural y desbordar -> scroll. flex-shrink:0 es lo
     que fuerza el desborde real que activa el overflow-y:auto del dock. */
  flex-shrink: 0;
}
.chart-slot-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 8px 10px; font-size: 12.5px; font-weight: 700;
  border-bottom: 1px solid var(--border);
}
.chart-slot-head .icon-btn { padding: 2px 8px; font-size: 13px; }
/* 220 -> 280: con la barra de dibujo ya quitada (chartLeftToolbar=0 en
   app.js) sobraba menos motivo para ir tan ajustado, y a 220px el precio y
   el eje de fechas quedaban muy apretados. */
.chart-slot iframe { display: block; width: 100%; height: 280px; border: 0; }

.section-block { margin-bottom: 36px; }
.section-title {
  font-size: 15px;
  font-weight: 700;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: .04em;
  margin: 0 0 14px;
}

.history-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 14px;
}
.history-header .section-title { margin: 0; }
.history-controls { display: flex; align-items: center; gap: 10px; }
.history-controls label {
  font-size: 12px;
  color: var(--text-dim);
  display: flex;
  align-items: center;
  gap: 6px;
}
.history-controls select {
  background: var(--bg-card);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 5px 8px;
  font-size: 13px;
}

.pagination {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  margin-top: 20px;
}
.pagination[hidden] { display: none; }
.pagination button:disabled { opacity: .35; cursor: not-allowed; }
#page-info { font-size: 12.5px; color: var(--text-dim); }

.feed {
  display: grid;
  /* 280 -> 310: con el sidebar ya en 340px (antes 280px) esto por si solo
     bajaba de 5 a 4 columnas solo en monitores muy anchos -- medido en
     1920px de viewport, con 280 seguian entrando 5 (972px sobraban 44px de
     margen, tarjetas casi al minimo). Subir el minimo del propio grid es lo
     que de verdad controla cuantas caben, sin depender del ancho exacto de
     la pantalla de cada uno. De paso da mas aire a la fila de acciones,
     que ahora lleva un boton mas (Grafica). */
  grid-template-columns: repeat(auto-fill, minmax(310px, 1fr));
  gap: 16px;
}

.feed-empty {
  text-align: center;
  color: var(--text-dim);
  margin-top: 60px;
  font-size: 14px;
}

/* ---------- Cuenta atrás a la siguiente ventana de 2,5h ---------- */
.free-countdown {
  font-size: 12.5px;
  color: var(--text-dim);
  white-space: nowrap;
}
.free-countdown strong {
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  color: var(--accent-2);
  font-weight: 700;
  letter-spacing: .02em;
}

/* ---------- Aviso de tokens ocultos en esta ventana (Premium) ----------
   Reskin 19/09 sobre ".bottom-lock" de la maqueta final. La maqueta la
   ancla con position:absolute al fondo de ".feed" -- aqui se deja en flujo
   normal, a todo el ancho, justo debajo del grid de 3 columnas: el
   contenido real (ficha del token) tiene alto variable, y una barra
   position:absolute podria solaparse con una ficha mas alta de lo previsto
   en la maqueta (checklist desplegado, etc.). Mismo lenguaje visual --
   icono + texto + boton dorado en fila -- sin ese riesgo. */
.hidden-banner {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  margin-top: 4px;
  padding: 13px 18px;
  border-radius: 10px;
  border: 1px solid var(--glow-cyan-border);
  background: rgba(3, 12, 25, .9);
  text-decoration: none;
  color: var(--text-dim);
  font-size: 12px;
  transition: border-color .15s ease, background .15s ease;
}
.hidden-banner[hidden] { display: none; }
.hidden-banner:hover { border-color: var(--warn); }
.hidden-banner-icon {
  flex: none;
  width: 36px; height: 36px;
  display: flex; align-items: center; justify-content: center;
  font-size: 17px;
  border-radius: 50%;
  background: rgba(255, 196, 0, .1);
  border: 1px solid rgba(255, 196, 0, .45);
}
.hidden-banner-text { flex: 1 1 220px; font-size: 13px; line-height: 1.5; color: var(--text-dim); }
.hidden-banner-text strong { color: var(--text); }
/* Tamaño/posicion propios; color y reflejo vienen de .btn-premium-shine. */
.hidden-banner-cta {
  flex: none;
  margin-left: auto;
  padding: 10px 20px;
  border-radius: 7px;
  font-size: 12px;
  white-space: nowrap;
}

/* ---------- Nota "solo gratuitos" sobre el historial ---------- */
.history-note {
  font-size: 12.5px;
  color: var(--text-dim);
  margin: -6px 0 14px;
}
.history-note a { color: var(--accent-2); text-decoration: none; font-weight: 700; }
.history-note a:hover { text-decoration: underline; }

/* ---------- Página Premium (premium.html) ---------- */
.premium-fineprint {
  text-align: center;
  font-size: 12px;
  color: var(--text-dim);
  margin: -12px 0 0;
}

/* Reskin 19/09 sobre ".token" de la maqueta final -- mismo fondo degradado
   de panel que el resto de tarjetas, mas el barrido de luz diagonal que la
   maqueta le da SOLO a esta pieza (".token:after"), reutilizado aqui tanto
   para la ficha destacada de la ventana como para las del historial. */
.token-card {
  position: relative;
  background: var(--panel-grad);
  border: 1px solid var(--glow-cyan-border);
  box-shadow: 0 0 22px rgba(0, 208, 255, .08), inset 0 0 24px rgba(10, 96, 148, .06);
  border-radius: var(--radius);
  padding: 14px;
  overflow: hidden;
  backdrop-filter: blur(8px);
  transition: box-shadow .15s ease, border-color .15s ease;
}
.token-card:hover {
  border-color: rgba(0, 234, 255, 0.5);
  box-shadow: 0 0 24px rgba(0, 234, 255, 0.2);
}
.token-card::after {
  content: "";
  position: absolute;
  top: -30%; bottom: -30%; left: -45%;
  width: 28%;
  transform: skewX(-18deg);
  background: linear-gradient(90deg, transparent, rgba(125, 244, 255, .16), rgba(255, 255, 255, .28), transparent);
  filter: blur(4px);
  pointer-events: none;
  animation: token-scan 7s 1.5s ease-in-out infinite;
}
@keyframes token-scan {
  0%, 52% { left: -45%; opacity: 0; }
  60%     { opacity: 1; }
  78%, 100% { left: 125%; opacity: 0; }
}
@media (prefers-reduced-motion: reduce) { .token-card::after { animation: none; display: none; } }

/* ---------- Llegada de un token: "impacto" de ~3s ---------- ---------
   Secuencia: varios rayos finos CRUZAN TODA LA PANTALLA desde fuera del
   viewport (sobre todo desde arriba) y convergen en el punto exacto de
   la tarjeta -> sacudida + una "supernova" pequeña (nucleo + puntas)
   pensada para caber dentro de la propia tarjeta -> humo que se disipa
   -> un velo oscuro que cubre los datos se aclara al final,
   revelandolos. Los rayos y la supernova viven en un unico <canvas>
   (.lightning-canvas, position:fixed) en <body>, NO dentro de la
   tarjeta: confinados al recuadro de la tarjeta se veian minusculos y se
   perdian contra el fondo. El velo/humo si siguen siendo hijos de
   .token-card, que durante la animacion pasa a overflow:visible para que
   el humo pueda asomar por encima del borde. El --ring-color (color
   segun grupo de sufijo) lo fija JS. */
.token-card.materializing {
  --ring-color: var(--accent-2);
  overflow: visible;
  animation: card-pop 450ms ease-out,
             energy-pulse 2900ms ease-in-out;
}
@keyframes card-pop {
  0%   { opacity: .8; transform: scale(.96); }
  100% { opacity: 1; transform: scale(1); }
}
@keyframes energy-pulse {
  0%   { box-shadow: 0 0 0 0 var(--ring-color); }
  14%  { box-shadow: 0 0 38px 7px var(--ring-color); }
  30%  { box-shadow: 0 0 8px 1px var(--ring-color); }
  78%  { box-shadow: 0 0 4px 0 var(--ring-color); }
  92%  { box-shadow: 0 0 32px 6px var(--ring-color); }
  100% { box-shadow: 0 0 0 0 var(--ring-color); }
}

/* Velo: oculta los datos reales hasta que "se disipa el humo". */
.impact-veil {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: linear-gradient(160deg, #04050a 0%, #0c0e16 55%, #04050a 100%);
  z-index: 5;
  pointer-events: none;
  animation: veil-clear 700ms ease-in 2150ms forwards;
}
@keyframes veil-clear {
  0%   { opacity: 1; }
  100% { opacity: 0; }
}

/* Los rayos y la explosion ("supernova") se dibujan ahora en un unico
   <canvas> a pantalla completa (ver crearEfectoLlegada en app.js) --
   nada de spans de CSS rotados/escalados ni de circulos que se hinchan:
   cada rayo se traza de punto a punto (origen -> centro de la tarjeta)
   y la explosion es un nucleo + puntas dibujados con radio proporcional
   al tamaño de la tarjeta, no de la pantalla. position:fixed + inset:0
   lo ancla al VIEWPORT; z-index muy alto para verse sobre cualquier
   tarjeta y la barra superior. */
.lightning-canvas {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 9999;
  pointer-events: none;
}

/* Sacudida del contenido en el instante del impacto (sincronizada con el
   destello, 620ms). Se aplica a <main>, nunca a <body>: un transform en
   un ancestro convierte a ESE ancestro en el contenedor de referencia de
   sus descendientes position:fixed, rompiendo el anclaje al viewport de
   .bg-fx, .lightning-canvas y el topbar. */
.impact-shake {
  animation: impact-shake-kf 380ms ease-out 600ms;
}
@keyframes impact-shake-kf {
  0%   { transform: translate(0, 0); }
  10%  { transform: translate(-6px, 3px); }
  22%  { transform: translate(5px, -4px); }
  36%  { transform: translate(-4px, 4px); }
  52%  { transform: translate(3px, -3px); }
  68%  { transform: translate(-2px, 2px); }
  85%  { transform: translate(1px, -1px); }
  100% { transform: translate(0, 0); }
}

/* Humo: unas cuantas manchas difusas que suben y se disipan. */
.impact-smoke {
  position: absolute;
  bottom: 46%;
  left: calc(50% + var(--sx, 0px));
  width: 58px;
  height: 58px;
  margin-left: -29px;
  background: radial-gradient(circle, rgba(210, 210, 220, .5), transparent 70%);
  border-radius: 50%;
  filter: blur(5px);
  opacity: 0;
  z-index: 6;
  animation: smoke-rise 1900ms ease-out forwards;
}
@keyframes smoke-rise {
  0%   { opacity: 0; transform: translateY(0) scale(.5); }
  18%  { opacity: .6; }
  100% { opacity: 0; transform: translateY(-75px) scale(1.9); }
}

@media (prefers-reduced-motion: reduce) {
  /* Sin fuegos artificiales: la tarjeta aparece ya en su estado final,
     sin rayos/humo y sin el velo tapando los datos. app.js tambien evita
     crear el canvas y reproducir el sonido cuando se pide menos
     movimiento -- esto es la red de seguridad en CSS. */
  .token-card.materializing { animation: none !important; opacity: 1 !important; }
  .impact-veil, .impact-smoke, .lightning-canvas {
    animation: none !important;
    opacity: 0 !important;
    display: none !important;
  }
  /* impact-shake se queda SOLO sin animacion/transform -- nunca con
     display:none, porque va sobre <main> y ocultaria toda la pagina. */
  .impact-shake { animation: none !important; transform: none !important; }
}

.card-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; }

.names { flex: 1; margin: 0 10px; min-width: 0; }
.symbol { display: block; font-size: 16px; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.name { display: block; font-size: 11px; color: var(--text-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.age { font-size: 11px; color: var(--text-dim); white-space: nowrap; }

/* Reskin 19/09 sobre ".token-grid"/".datum" de la maqueta -- misma rejilla
   de 3 columnas que ya generaba app.js (metricEl()), solo con caja propia
   por dato en vez de texto suelto.
   OJO: acotado a ".token-card .metrics" (no ".metrics" a secas) a proposito
   -- el mismo fallo de nombre compartido que #stats-bar, aqui al reves:
   ".metrics > div" sin acotar tambien pillaba a las tarjetas de METRICAS DE
   PORTADA (#stats-bar.metrics > .metric son igualmente "div hijos directos
   de algo con clase .metrics") y les imponia flex-direction:column, apilando
   el icono debajo del texto en vez de al lado (20/09, reportado en vivo). */
.token-card .metrics {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 9px;
  margin: 12px 0;
}
.token-card .metrics > div {
  display: flex;
  flex-direction: column;
  padding: 12px;
  border: 1px solid rgba(117, 154, 195, .23);
  border-radius: 7px;
  background: rgba(2, 8, 19, .55);
}
.token-card .metrics .label { font-size: 9px; color: #71849a; text-transform: uppercase; letter-spacing: .04em; }
.token-card .metrics .value { display: block; margin-top: 5px; font-size: 13px; font-weight: 600; }

/* ---------- Checklist de garantia de la tarjeta (rehecho 19/09) ----------
   Antes: las mismas 7 lineas ("Owner renunciado", "Sin minteo"...) sueltas
   y siempre visibles, identicas en casi todas las tarjetas del historial --
   mucho alto de tarjeta para informacion que rara vez varia. Ahora un
   <details> nativo: colapsado dice "Verificado N/N" de un vistazo, y solo
   se despliega si alguien quiere comprobar la lista entera. Sin JS extra
   para abrir/cerrar -- lo hace el propio elemento. */
.token-checklist {
  margin: 10px 0;
  padding-top: 10px;
  border-top: 1px dashed var(--border);
}
.token-checklist summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  font-weight: 700;
}
.token-checklist summary::-webkit-details-marker { display: none; }
.token-checklist-summary-text.ok { color: var(--good); }
.token-checklist-summary-text.warn { color: var(--warn); }
.token-checklist-chev { margin-left: auto; color: var(--text-dim); font-size: 10px; transition: transform .15s ease; }
.token-checklist[open] .token-checklist-chev { transform: rotate(180deg); }
.token-checklist-body {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 8px;
  margin-top: 8px;
}
.token-checklist-item { font-size: 11px; line-height: 1.4; }
.token-checklist-item.ok { color: var(--good); }
.token-checklist-item.warn { color: var(--warn); }

/* ---------- Aviso Premium de la tarjeta (rehecho 19/09) ----------
   Antes: una unica frase de texto ("con Premium: compradores...") repetida
   tal cual en cada tarjeta del historial -- al tercer repaso el ojo deja de
   leerla. Ahora cada metrica va en su propia fila con el valor ENMASCARADO
   ("•••", nunca un numero inventado: el backend no manda ese dato a quien
   no es Premium, asi que no hay nada real que mostrar ni difuminar) y un
   boton real al final, no un enlace suelto dentro de la frase. */
/* Reskin 19/09 sobre ".locked"+".premium-btn" de la maqueta -- caja de
   filas enmascaradas + boton ancho, en vez de tarjeta con boton pequeño
   alineado a la izquierda. */
.token-premium-teaser {
  margin-top: 12px;
  padding: 10px;
  border-radius: 8px;
  border: 1px solid rgba(255, 196, 0, .4);
  background: rgba(255, 196, 0, .05);
  display: flex;
  flex-direction: column;
  gap: 7px;
}
.tpt-row { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.tpt-row .tpt-label { font-size: 11px; color: #b8a670; line-height: 1.5; }
.tpt-row .tpt-masked { flex: none; font-size: 11px; font-weight: 800; letter-spacing: .14em; color: var(--warn); }
/* Tamaño/posicion propios; color y reflejo vienen de .btn-premium-shine
   (app.js ya le añade esa clase junto con "tpt-unlock"). */
.tpt-unlock {
  margin-top: 4px;
  width: 100%;
  text-align: center;
  font-size: 13px;
  letter-spacing: .25px;
  border-radius: 8px;
  padding: 12px;
  text-decoration: none;
}

.card-topbrand {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  margin-bottom: 12px;
  border-radius: 10px;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  text-decoration: none;
  transition: border-color .15s ease;
}
.card-topbrand:hover { border-color: var(--accent-2); }
.card-topbrand-mark { width: 22px; height: 22px; flex: none; }
.card-topbrand-title {
  font-family: "Chakra Petch", "Segoe UI", sans-serif;
  font-weight: 700;
  font-size: 13px;
  letter-spacing: .03em;
  color: var(--text);
}
.card-topbrand-title em {
  font-style: normal;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* Reskin 19/09 sobre ".links" de la maqueta -- mismo azul oscuro de boton
   secundario, algo mas de relleno vertical. */
.actions { display: flex; gap: 9px; flex-wrap: wrap; margin-top: 9px; }
.actions a, .actions button {
  flex: 1;
  min-width: 100px;
  text-align: center;
  font-size: 11.5px;
  font-weight: 700;
  text-decoration: none;
  color: #dce8f6;
  background: #071326;
  border: 1px solid rgba(124, 161, 202, .35);
  padding: 11px 8px;
  border-radius: 7px;
  cursor: pointer;
  font-family: inherit;
}
.actions a:hover, .actions button:hover { border-color: var(--accent-2); color: var(--accent-2); }
/* Marca la tarjeta cuyo boton de grafica tiene el iframe abierto ahora mismo
   en el dock del sidebar -- ver abrirGraficaIC/cerrarGraficaIC en app.js. */
.actions button.btn-chart.activa {
  border-color: var(--accent-2);
  color: var(--accent-2);
  background: rgba(56,189,248,.08);
}

.address-line {
  font-size: 10px;
  color: var(--text-dim);
  margin-top: 8px;
  word-break: break-all;
}

.card-brand {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 10px;
  padding-top: 8px;
  border-top: 1px solid var(--border);
  color: var(--text-dim);
  text-decoration: none;
  font-size: 10px;
  letter-spacing: .02em;
  transition: color .15s ease;
}
.card-brand:hover { color: var(--accent-2); }
.card-brand-icon {
  width: 18px;
  height: 18px;
  border-radius: 4px;
  object-fit: cover;
  flex-shrink: 0;
}

.disclaimer {
  border-top: 1px solid var(--border);
  padding: 16px 20px 40px;
  color: var(--text-dim);
  font-size: 11.5px;
  max-width: 900px;
  margin: 0 auto;
  line-height: 1.5;
}
.disclaimer strong { color: var(--text); }

.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(4, 6, 10, .78);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 50;
  padding: 20px;
}
.modal-backdrop[hidden] { display: none; }
.modal {
  background: var(--bg-card);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  max-width: 460px;
  padding: 24px;
}
.modal h2 { margin-top: 0; }
.modal p { color: var(--text-dim); font-size: 13.5px; line-height: 1.5; }
.btn-primary {
  margin-top: 8px;
  background: var(--accent);
  color: #fff;
  border: none;
  border-radius: 10px;
  padding: 10px 18px;
  font-size: 14px;
  cursor: pointer;
}
.btn-primary:hover { background: #6a4be8; }

/* ---------- Navegacion principal (compartida por todas las paginas) ---------- */
.mainnav {
  display: flex;
  gap: 4px;
  padding: 0 20px;
  background: var(--bg-panel);
  border-bottom: 1px solid var(--border);
  overflow-x: auto;
  position: sticky;
  /* 20/09: .topbar TAMBIEN es sticky top:0, asi que si este "top" no
     coincide con su alto real las dos se superponen al hacer scroll. El
     alto de .topbar ya no es fijo por breakpoint (.value-prop reparte texto
     de forma continua) asi que --topbar-h la mide y la escribe bg-fx.js con
     ResizeObserver -- ver el IIFE al final de ese fichero. */
  top: var(--topbar-h);
  z-index: 19;
}
.mainnav a {
  display: flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
  padding: 12px 14px;
  color: var(--text-dim);
  text-decoration: none;
  font-size: 13px;
  font-weight: 600;
  border-bottom: 2px solid transparent;
}
.mainnav a:hover { color: var(--text); }
.mainnav a[aria-current="page"] {
  color: var(--text);
  border-bottom-color: var(--accent-2);
  box-shadow: 0 2px 10px -2px var(--accent-2);
}
.pill-soon {
  display: inline-block;
  font-size: 9px;
  font-weight: 700;
  vertical-align: middle;
  color: var(--warn);
  background: rgba(251,191,36,.12);
  border: 1px solid rgba(251,191,36,.4);
  border-radius: 999px;
  padding: 2px 7px;
  letter-spacing: .03em;
  /* 22/09 -- ahora es un <a> (enlaza a #founder-offer), no solo un <span>
     decorativo: sin esto heredaria el subrayado por defecto del navegador. */
  text-decoration: none;
  cursor: pointer;
}
.pill-soon:hover { border-color: rgba(251,191,36,.75); background: rgba(251,191,36,.2); }
.pill-tier {
  color: var(--accent-2);
  background: rgba(34,211,238,.12);
  border-color: rgba(34,211,238,.4);
}
.pill-free {
  color: var(--good);
  background: rgba(52,211,153,.12);
  border-color: rgba(52,211,153,.4);
}
.pill-gold {
  color: #fde68a;
  background: linear-gradient(135deg, rgba(251,191,36,.22), rgba(217,119,6,.18));
  border-color: rgba(251,191,36,.55);
  font-weight: 800;
}

/* ---------- Paginas de contenido (texto) ---------- */
.page {
  max-width: 860px;
  margin: 0 auto;
  padding: 36px 20px 60px;
  line-height: 1.65;
}
.page h1 { font-size: 28px; margin: 0 0 6px; }
.page .lead { color: var(--text-dim); font-size: 15px; margin: 0 0 32px; }
.page h2 { font-size: 20px; margin: 40px 0 12px; scroll-margin-top: 110px; }
.page h2:first-of-type { margin-top: 8px; }
.page h3 { font-size: 15.5px; margin: 22px 0 8px; color: var(--accent-2); }
.page p { color: #cfd5e3; font-size: 14.5px; margin: 0 0 14px; }
.page ul { margin: 0 0 14px; padding-left: 20px; color: #cfd5e3; font-size: 14.5px; }
.page li { margin-bottom: 6px; }
.page strong { color: var(--text); }
.page a, .page a:visited {
  color: var(--accent-2);
  text-decoration: underline;
  text-decoration-color: rgba(34,211,238,.4);
}
.page a:hover { color: var(--text); }

.callout {
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--bg-card);
  padding: 18px 20px;
  margin: 18px 0;
}
.callout.good { border-color: rgba(52,211,153,.4); background: rgba(52,211,153,.06); }
.callout.bad { border-color: rgba(248,113,113,.4); background: rgba(248,113,113,.06); }
.callout.warn { border-color: rgba(251,191,36,.4); background: rgba(251,191,36,.06); }
.callout h3 { margin-top: 0; }
.callout p:last-child { margin-bottom: 0; }

.cover-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  margin: 20px 0 28px;
}
@media (max-width: 640px) { .cover-grid { grid-template-columns: 1fr; } }

/* ---------- Tarjetas de precios (Bot) ---------- */
.pricing-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px;
  margin: 24px 0 32px;
}
@media (max-width: 640px) { .pricing-grid { grid-template-columns: 1fr; } }

.price-card {
  border: 1px solid var(--glow-cyan-border);
  box-shadow: 0 0 16px var(--glow-cyan-soft);
  border-radius: var(--radius);
  background: var(--bg-card);
  padding: 22px;
  display: flex;
  flex-direction: column;
}
/* Dorado reservado a Premium (19/09) -- coherente con el resto de la web:
   el cian es el borde por defecto de cualquier tarjeta, el dorado marca
   específicamente lo que cuesta dinero. */
.price-card.highlight {
  border-color: var(--warn);
  box-shadow: 0 0 0 1px var(--warn) inset, 0 0 20px rgba(251,191,36,.15);
}
.price-card .plan-name { font-size: 13px; color: var(--text-dim); text-transform: uppercase; letter-spacing: .06em; }
.price-card .plan-price { font-size: 30px; font-weight: 800; margin: 6px 0 2px; }
.price-card .plan-price small { font-size: 13px; color: var(--text-dim); font-weight: 500; }
.price-card ul { list-style: none; padding: 0; margin: 16px 0; flex: 1; }
.price-card ul li { padding-left: 22px; position: relative; font-size: 13.5px; color: #cfd5e3; margin-bottom: 8px; }
.price-card ul li::before { content: "✓"; position: absolute; left: 0; color: var(--good); font-weight: 700; }

/* ---------- Precio de fundador Premium (18/09), ver premium-pricing.js ---------- */
.founder-badge {
  display: inline-block;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .03em;
  text-transform: uppercase;
  color: #0b0d17;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
  padding: 4px 10px;
  border-radius: 999px;
  margin-bottom: 8px;
}
.price-was {
  font-size: 17px;
  font-weight: 600;
  color: var(--text-dim);
  text-decoration: line-through;
  text-decoration-color: #ff5c7a;
  margin-right: 8px;
}
.price-now { font-size: 30px; font-weight: 800; }
.founder-note {
  font-size: 12.5px;
  color: var(--text-dim);
  margin: 6px 0 0;
  line-height: 1.5;
}
.founder-note strong { color: #cfd5e3; }

/* ---------- Fila "Actividad de hoy" + franja de fundador, lado a lado
   (22/09 noche, ultima ronda) -- antes cada una vivia en su propia fila
   de ancho completo, y a la derecha de las 2 tiles de "Actividad de hoy"
   (max-width 620px) quedaba un hueco vacio en pantallas anchas. Pedido
   explicito: llenar ese hueco con la franja de fundador para acortar la
   pagina entera una franja. `.hoy-col` reutiliza el mismo contenido de
   siempre (label+tiles+nota); sus hijos pierden el margen/padding lateral
   de 20px que tenian como secciones sueltas -- ahora ese inset lo pone
   `.hoy-founder-row` una sola vez, para los dos. */
.hoy-founder-row {
  display: flex;
  align-items: stretch;
  gap: 24px;
  margin: 0 20px 14px;
}
.hoy-col {
  /* Sin encoger (22/09 noche): con flex-shrink:1 el navegador repartia el
     hueco casi todo para founder-bar (943px) y dejaba esta columna a
     417px, mas estrecha de lo que sus propias 2 tiles necesitan. Ancho
     fijo aqui, y que sea founder-bar (flex:1) quien ocupe lo que sobre. */
  flex: 0 0 660px;
  min-width: 0;
}
.hoy-col .stats-section-label,
.hoy-col .stats-hero-note { margin-left: 0; margin-right: 0; padding-left: 0; padding-right: 0; }
.hoy-col #stats-bar.metrics { padding-left: 0; padding-right: 0; }

/* ---------- Franja "Oferta Fundadores" (22/09, rehecha en horizontal;
   ampliada al doble; movida al hueco de "Actividad de hoy" -- las tres,
   la misma noche) -- esquema recuperado de "MIDAS SENTINEL -- Rediseno
   visual.txt", pero como TARJETA VERTICAL ocupaba ~450px y no dejaba ver
   el resto del resumen sin scroll. Ahora vive dentro de
   `.hoy-founder-row` (ver arriba) en vez de ser su propia fila de ancho
   completo -- por eso `flex:1` en vez de margen propio, que ya pone el
   contenedor. Tres bloques dentro: `.founder-bar-top` (badge+precio),
   `.founder-bar-benefits` (tres beneficios con check) y el CTA aparte,
   como ultimo paso antes de la letra pequeña -- mejor flujo de lectura
   en una columna mas estrecha que cuando iba a lo ancho completo. Mismos
   tonos dorados que .btn-premium-shine/.founder-locked-tag de siempre --
   sin inventar un dorado nuevo. */
.founder-bar {
  display: flex;
  flex-direction: column;
  gap: 12px;
  flex: 1 1 auto;
  min-width: 280px;
  /* 23/09: la pill de cabecera y la pestaña "Premium" del nav ahora saltan
     aqui (#founder-offer) en vez de a premium.html -- .topbar y .mainnav son
     sticky (top:0 / top:var(--topbar-h)) y sin esto el salto deja la tarjeta
     tapada debajo de las dos. Mismo patron que ".page h2" mas abajo. */
  scroll-margin-top: calc(var(--topbar-h) + 44px);
  padding: 18px 26px;
  border-radius: 14px;
  border: 1px solid rgba(251, 191, 36, .5);
  background:
    radial-gradient(circle at 10% 20%, rgba(251, 191, 36, .12), transparent 55%),
    rgba(4, 14, 29, .82);
  box-shadow: 0 0 0 1px rgba(251, 191, 36, .12) inset;
}
.founder-bar-top {
  /* Columna, no fila (22/09 noche): con la franja ahora en una columna de
     ~700px (antes iba a lo ancho completo, ~1350px), el badge y
     .founder-bar-copy competian por el mismo ancho y title+precio+tag
     acababan apilados en 3 lineas dentro de un hueco estrecho. Poniendo
     el badge en su propia linea, .founder-bar-copy recupera el ancho
     completo de la columna y title+precio+tag caben en una sola linea. */
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
}
.founder-bar-badge {
  flex: none;
  font-size: 12.5px;
  font-weight: 800;
  letter-spacing: .05em;
  text-transform: uppercase;
  white-space: nowrap;
  color: #201300;
  background: linear-gradient(90deg, #fff0a2, #ffca32);
  padding: 6px 14px;
  border-radius: 999px;
}
.founder-bar-copy {
  /* align-self:stretch (22/09 noche): el padre ahora es columna con
     align-items:flex-start (para que el badge no se estire) -- sin esto
     copy heredaria ese mismo encogido-a-su-contenido y perderia el ancho
     completo que necesita para no apilar title+precio+tag en 3 lineas. */
  align-self: stretch;
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  min-width: 0;
}
.founder-bar-title {
  font-size: 17px;
  font-weight: 700;
  color: var(--text);
}
.founder-bar-title em { color: var(--warn); font-style: normal; }
.founder-bar-price {
  display: flex;
  align-items: baseline;
  gap: 8px;
  white-space: nowrap;
}
.founder-bar-price .price-now { font-size: 30px; }
.founder-bar-price small { color: var(--text-dim); font-size: 13px; }
.founder-bar-price .price-was { font-size: 15px; margin-right: 0; }
.founder-locked-tag {
  flex: none;
  font-size: 11.5px;
  font-weight: 800;
  letter-spacing: .03em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--warn);
  background: rgba(255, 196, 0, .12);
  border: 1px solid rgba(255, 196, 0, .4);
  border-radius: 999px;
  padding: 4px 12px;
}
.founder-bar-cta {
  /* Dentro de .founder-bar-mid (fila) junto a los beneficios -- flex:none
     para que no se estire a compartir el ancho con la lista. */
  flex: none;
  padding: 15px 30px;
  border-radius: 999px;
  font-size: 15.5px;
  font-weight: 900;
  letter-spacing: .02em;
  text-decoration: none;
  white-space: nowrap;
}
/* Los tres beneficios pedidos explicitamente (22/09 noche), traduccion
   directa: acceso sin espera desde el primer minuto, +10 parametros por
   token, y las carteras rug-pull/ganadoras que ya manda de verdad
   `enviar_ficha_premium_v3` en el backend -- no una promesa nueva. Mismo
   check "✓" que ya usa `.price-card ul li::before` en premium.html, para
   no inventar un icono nuevo. */
/* Fila que reune beneficios (izquierda) + CTA (derecha) -- ver comentario
   en index.html junto a esta misma clase. */
.founder-bar-mid {
  display: flex;
  align-items: center;
  gap: 24px;
  padding: 12px 0 0;
  border-top: 1px solid rgba(251, 191, 36, .22);
}
.founder-bar-benefits {
  display: flex;
  flex-direction: column;
  gap: 6px;
  flex: 1 1 auto;
  min-width: 0;
  list-style: none;
  margin: 0;
  padding: 0;
}
.founder-bar-benefits li {
  padding-left: 22px;
  position: relative;
  font-size: 13.5px;
  line-height: 1.4;
  color: #cfd5e3;
}
.founder-bar-benefits li::before {
  content: "✓";
  position: absolute;
  left: 0;
  top: 0;
  color: var(--good);
  font-weight: 800;
}
.founder-bar-fine {
  margin: 0;
  font-size: 12px;
  color: var(--text-dim);
}
.founder-bar-fine strong { color: #cfd5e3; }
/* Sin ancho para dos columnas de verdad, .hoy-col (660px) y .founder-bar
   (min-width 280px) ya no caben lado a lado -- apilar antes de que
   lleguen a chocar. */
@media (max-width: 1100px) {
  .hoy-founder-row { flex-direction: column; }
  .hoy-col { flex-basis: auto; }
}
@media (max-width: 900px) {
  .founder-bar-top { justify-content: center; text-align: center; }
  .founder-bar-copy { justify-content: center; }
  /* .founder-bar-mid pasa a columna en movil -- sin ancho para beneficios
     y CTA lado a lado, apilar es mas legible que encogerlos a la fuerza. */
  .founder-bar-mid { flex-direction: column; align-items: stretch; }
  .founder-bar-cta { width: 100%; text-align: center; }
  /* .founder-bar-benefits ya es flex-direction:column a cualquier ancho
     (22/09 noche) -- en movil solo hace falta centrar el bloque entero,
     el check de cada linea se queda a la izquierda de su propio texto. */
  .founder-bar-benefits { align-items: center; }
  .founder-bar-benefits li { text-align: left; }
  .founder-bar-fine { text-align: center; }
}

/* ---------- Caja de contacto "¿tienes alguna duda?" (index, tras el feed) ---------- */
.contact-box {
  max-width: 1200px;
  margin: 0 auto 20px;
  padding: 0 20px;
}
.contact-box-inner {
  display: flex;
  gap: 16px;
  align-items: center;
  flex-wrap: wrap;
  border-radius: var(--radius);
  border: 1px solid rgba(34,211,238,.35);
  background: linear-gradient(160deg, rgba(34,211,238,.10), rgba(124,92,255,.05));
  box-shadow: 0 0 0 1px rgba(34,211,238,.08) inset;
  padding: 20px;
}
.contact-box-icon {
  flex-shrink: 0;
  width: 42px;
  height: 42px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 20px;
  border-radius: 50%;
  background: rgba(34,211,238,.14);
  border: 1px solid rgba(34,211,238,.4);
}
.contact-box-text { flex: 1 1 220px; min-width: 200px; }
.contact-box-text h3 {
  margin: 0 0 4px;
  font-family: "Chakra Petch", "Segoe UI", sans-serif;
  font-size: 15px;
  font-weight: 700;
  color: var(--text);
}
.contact-box-text p { margin: 0; font-size: 13px; color: var(--text-dim); }
.contact-form { flex: 2 1 360px; margin-top: 0; }
@media (max-width: 640px) {
  .contact-box-inner { flex-direction: column; align-items: stretch; }
  .contact-form { flex-basis: auto; }
}

/* ---------- Formulario de lista de espera ---------- */
.waitlist-form {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 10px;
}
.waitlist-form input[type="email"] {
  flex: 1;
  min-width: 200px;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 10px 12px;
  border-radius: 10px;
  font-size: 14px;
}
.waitlist-form input[type="text"] { display: none; }
.waitlist-form textarea {
  flex: 1 1 100%;
  min-width: 200px;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 10px 12px;
  border-radius: 10px;
  font: inherit;
  font-size: 14px;
  resize: vertical;
}
.waitlist-form button {
  background: var(--accent);
  color: #fff;
  border: none;
  border-radius: 10px;
  padding: 10px 18px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}
.waitlist-form button:hover { background: #6a4be8; }
.waitlist-msg { font-size: 12.5px; margin-top: 8px; min-height: 16px; }
.waitlist-msg.ok { color: var(--good); }
.waitlist-msg.err { color: var(--bad); }
/* Aviso de "operación en marcha" -- parpadeo suave para que se note que
   sigue viva (no colgada) durante los 5-10s que puede tardar una compra
   con puente de 3 transacciones. */
.waitlist-msg.pending { color: var(--accent-2); font-weight: 600; animation: ic-pending-pulse 1.2s ease-in-out infinite; }
@keyframes ic-pending-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }
@media (prefers-reduced-motion: reduce) {
  .waitlist-msg.pending { animation: none; }
}

/* ---------- Panel del Sniper Bot ---------- */
.sniper-connect {
  text-align: center;
  padding: 48px 20px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-card);
}
.sniper-connect p { max-width: 480px; margin: 0 auto 18px; color: var(--text-dim); }

.wallet-box {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-card);
  padding: 18px 20px;
  margin: 18px 0;
}
.wallet-box .addr {
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: 13px;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 8px 10px;
  word-break: break-all;
}
.wallet-box .balance { font-size: 22px; font-weight: 800; }
.wallet-box .balance small { font-size: 12px; color: var(--text-dim); font-weight: 500; }
.wallet-box .copy-btn {
  background: var(--bg-panel);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 8px;
  padding: 6px 10px;
  font-size: 12px;
  cursor: pointer;
}

.sniper-form { display: grid; grid-template-columns: 1fr 1fr; gap: 18px 24px; margin: 18px 0; }
/* [hidden] tiene la MISMA especificidad que .sniper-form (0,1,0) -- sin esto
   el "display:grid" de arriba gana y el formulario no llega a ocultarse
   nunca (visto en vivo al probar el desplegable de index.html: el atributo
   se ponia y quitaba bien, pero el form seguia mostrandose siempre). */
.sniper-form[hidden] { display: none; }
@media (max-width: 640px) { .sniper-form { grid-template-columns: 1fr; } }
.sniper-field label {
  display: block;
  font-size: 13px;
  font-weight: 700;
  margin-bottom: 4px;
}
.sniper-field input {
  width: 100%;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 9px 11px;
  border-radius: 8px;
  font-size: 14px;
  font-family: "IBM Plex Mono", ui-monospace, monospace;
}
.sniper-field .explain {
  font-size: 12px;
  color: var(--text-dim);
  margin-top: 4px;
  line-height: 1.5;
}

/* Config del feed (#fd-defaults-form): son todo campos de un solo numero,
   asi que el grid de dos columnas anchas de .sniper-form (pensado para
   formularios con mas texto, como interceptor-panel.html) sobraba muchisimo
   espacio a cada lado del input. Mas columnas y mas estrechas, solo aqui --
   no se toca .sniper-form en si, que siguen usando los demas paneles. */
#fd-defaults-form.sniper-form {
  grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
  gap: 12px 16px;
  margin: 14px 0 18px;
}
#fd-defaults-form .sniper-field label {
  font-size: 11.5px;
  margin-bottom: 3px;
}
#fd-defaults-form .sniper-field input {
  padding: 6px 8px;
  font-size: 13px;
}
/* Los dos campos con nota explicativa larga (orden limite, slippage venta)
   necesitan ancho de sobra para el texto -- ocupan la fila entera, pero el
   input en si se queda igual de pequeño que el resto. */
#fd-defaults-form .sniper-field.span-full {
  grid-column: 1 / -1;
}
#fd-defaults-form .sniper-field.span-full input {
  max-width: 150px;
}

/* Aviso breve al abrir la config desde el botoncito de una tarjeta -- el
   formulario puede estar fuera de la vista (o ya oculto) y el scroll solo
   no deja claro DONDE ha aterrizado la página; el resplandor sí. */
.sniper-form.config-flash,
#defaults-form.config-flash {
  animation: config-flash-kf 1.4s ease-out;
}
@keyframes config-flash-kf {
  0%   { box-shadow: 0 0 0 3px var(--accent-2); border-radius: 10px; }
  100% { box-shadow: 0 0 0 3px transparent; border-radius: 10px; }
}
@media (prefers-reduced-motion: reduce) {
  .sniper-form.config-flash, #defaults-form.config-flash { animation: none; }
}

.sniper-toggle-row { display: flex; align-items: center; gap: 12px; margin: 22px 0; }
.sniper-toggle-row .status-badge {
  font-size: 12px; font-weight: 700; padding: 4px 10px; border-radius: 999px;
}
.sniper-toggle-row .status-badge.on { color: var(--good); background: rgba(52,211,153,.14); }
.sniper-toggle-row .status-badge.off { color: var(--text-dim); background: rgba(255,255,255,.06); }

.activity-table { width: 100%; border-collapse: collapse; font-size: 13px; margin-top: 10px; }
.activity-table th {
  text-align: left; color: var(--text-dim); text-transform: uppercase;
  font-size: 10.5px; letter-spacing: .04em; padding: 6px 8px; border-bottom: 1px solid var(--border);
}
.activity-table td { padding: 8px; border-bottom: 1px solid var(--border); }
.activity-table .pnl-pos, .ic-pos-cambio.pnl-pos, .ic-pos-pnl.pnl-pos { color: var(--good); font-weight: 700; }
.activity-table .pnl-neg, .ic-pos-cambio.pnl-neg, .ic-pos-pnl.pnl-neg { color: var(--bad); font-weight: 700; }
.activity-table .status-pill {
  font-size: 10.5px; font-weight: 700; padding: 2px 8px; border-radius: 999px;
}
.activity-table .status-pill.OPEN { color: var(--accent-2); background: rgba(34,211,238,.14); }
.activity-table .status-pill.CLOSED { color: var(--text-dim); background: rgba(255,255,255,.06); }

/* ---------- Interceptor: tarjetas de decisión en vivo ---------- */
.interceptor-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 16px;
  margin: 14px 0 24px;
}
.interceptor-card {
  border: 1px solid rgba(251,191,36,.35);
  border-radius: var(--radius);
  background: linear-gradient(160deg, rgba(251,191,36,.07), var(--bg-card));
  padding: 16px 18px;
}
.interceptor-card .ic-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
  margin-bottom: 6px;
}
.interceptor-card .ic-symbol { font-weight: 800; font-size: 15px; }
.interceptor-card .ic-countdown {
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: 12.5px; color: var(--warn);
}
.interceptor-card .ic-addr {
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: 11px; color: var(--text-dim); word-break: break-all; margin-bottom: 10px;
}
.interceptor-card .ic-price,
.token-card .ic-price {
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-weight: 800;
}
.interceptor-card .ic-price { font-size: 20px; margin-bottom: 12px; }
.interceptor-card .ic-price small, .token-card .ic-price small { font-size: 11px; color: var(--text-dim); font-weight: 500; }
.interceptor-card .ic-config-actual,
.token-card .ic-config-actual {
  font-size: 11.5px; color: var(--text-dim); margin: 2px 0 6px;
}
.interceptor-card .ic-slippage,
.token-card .ic-slippage {
  font-size: 11.5px; color: var(--text-dim); margin: 0 0 12px;
}
.interceptor-card .ic-motivo-precio,
.token-card .ic-motivo-precio {
  font-size: 12px; line-height: 1.4; color: var(--warn);
  background: rgba(251,191,36,.08); border: 1px solid rgba(251,191,36,.25);
  border-radius: 8px; padding: 7px 9px; margin: -4px 0 12px;
}
.interceptor-card .ic-actions,
.token-card .ic-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.interceptor-card .ic-limit-box,
.token-card .ic-limit-box {
  margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--border);
  display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
}
.interceptor-card .ic-limit-box input,
.token-card .ic-limit-box input {
  width: 130px; background: var(--bg-panel); border: 1px solid var(--border);
  color: var(--text); padding: 7px 9px; border-radius: 8px; font-size: 13px;
  font-family: "IBM Plex Mono", ui-monospace, monospace;
}

/* ---------- Interceptor integrado en las tarjetas del feed (index.html) ---------- */
/* Mismos componentes .ic-* de arriba, reutilizados dentro de .token-card --
   ver el plan "Interceptor integrado en Feed en vivo" (09/09-11/09/2026):
   sin countdown ni Retomar/Abandonar, porque la propia tarjeta del feed ya
   tiene un ciclo de vida natural (MAX_CARDS_LIVE en app.js) que hace
   innecesaria esa maquina de estados. */
.token-card .ic-price { font-size: 15px; margin-bottom: 8px; }
.token-card .ic-embed {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
}
.token-card .ic-btn-conectar { width: 100%; }
.token-card .ic-btn-reentrar { width: 100%; margin-top: 8px; }
.token-card .ic-pos-precio { font-family: "IBM Plex Mono", ui-monospace, monospace; }
.token-card .ic-pos-cambio,
.token-card .ic-pos-pnl {
  font-size: 12.5px;
  margin-bottom: 6px;
}
.token-card .ic-btn-vender {
  width: 100%;
  background: var(--bad);
  border-color: var(--bad);
  color: #fff;
  font-weight: 700;
}
.token-card .ic-btn-vender:hover { opacity: .88; }
.token-card .ic-btn-vender:disabled { opacity: .5; cursor: default; }

/* Tarjeta con una posicion abierta de verdad: anclada arriba del feed y
   excluida del recorte por MAX_CARDS_LIVE (ver agregarToken/app.js) -- no
   puede perderse de vista solo porque lleguen tokens nuevos detras. */
.token-card.con-posicion {
  border-color: var(--accent-2);
  box-shadow: 0 0 0 1px var(--accent-2) inset;
}
.token-card.con-posicion::before {
  content: "📌 Posición abierta";
  display: block;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--accent-2);
  margin-bottom: 8px;
}

.interceptor-card.ic-done { opacity: .6; }
.interceptor-card .ic-timeout-box {
  margin-top: 10px; padding-top: 10px; border-top: 1px solid rgba(248,113,113,.35);
  display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
  font-size: 13px; color: var(--warn);
}

.ic-waiting {
  display: flex; align-items: center; gap: 12px;
  color: var(--text-dim); font-size: 13.5px; padding: 12px 2px;
}
.ic-radar {
  position: relative; width: 12px; height: 12px; border-radius: 50%;
  background: rgba(251,191,36,.9); flex: none;
  animation: ic-pulse 1.6s ease-out infinite;
}
@keyframes ic-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(251,191,36,.55); }
  70%  { box-shadow: 0 0 0 14px rgba(251,191,36,0); }
  100% { box-shadow: 0 0 0 0 rgba(251,191,36,0); }
}
.ic-dots span { animation: ic-dot 1.4s infinite; opacity: 0; }
.ic-dots span:nth-child(2) { animation-delay: .2s; }
.ic-dots span:nth-child(3) { animation-delay: .4s; }
@keyframes ic-dot { 0%, 100% { opacity: 0; } 50% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .ic-radar { animation: none; box-shadow: 0 0 0 4px rgba(251,191,36,.25); }
  .ic-dots span { animation: none; opacity: 1; }
}

@media (max-width: 520px) {
  .topbar { flex-wrap: wrap; gap: 10px; }
  .stats-bar { gap: 14px; }
}
/* Por debajo de 720px .brand ya no cabe en una sola fila junto a
   .topbar-actions -- ancla ambos arriba de su propia fila en vez de
   centrarlos (align-items:center de la base se veia raro con filas de alto
   distinto). Colocada aqui (despues de la regla base ".topbar", no antes) a
   proposito: con la misma especificidad, la ultima en el orden del fichero
   es la que gana -- puesta antes de la base, el padding/align-items de aqui
   se perdian siempre (visto en vivo al integrarlo la primera vez). */
@media (max-width: 720px) {
  .topbar { padding: 14px 16px 20px; align-items: flex-start; }
}

/* ---------- SPIDER-X (mascota 3D/sonora, capa de presentacion) ----------
   Dos modos, decididos por spider-x-bootstrap.js segun exista ".spider-slot"
   en la pagina:
   - Flotante/arrastrable (por defecto, como siempre): position:fixed sobre
     el viewport, con cursor de arrastre.
   - Empotrado (".spx-embedded", 19/09 sobre la maqueta final -- index.html
     ya trae ".spider-slot" dentro de ".visual"): llena el hueco fijo de la
     columna decorativa, sin arrastre ni cursor de mano -- ese hueco YA es
     un sitio permanente, no hace falta reposicionarlo a mano. */
#spider-x-widget {
  position: fixed;
  left: 18px;
  bottom: 18px;
  width: 200px;
  height: 200px;
  z-index: 40;
  cursor: grab;
  touch-action: none; /* el arrastre por tacto no debe hacer scroll de la pagina */
}
#spider-x-widget.spx-dragging { cursor: grabbing; }
#spider-x-widget canvas { display: block; }
/* Reducida ~60% (20/09, pedido explicito -- "más pequeñita, al menos un 50
   o un 70"). transform:scale en vez de encoger .spider-slot: asi el brillo
   ambar/cian de detras (::before/::after, en px fijos) no queda
   desproporcionado respecto al modelo. El renderer sigue dibujando al
   tamaño real del hueco (clientWidth/Height no cambia con transform), solo
   se ve mas pequeño en pantalla -- no hace falta redimensionar el canvas. */
#spider-x-widget.spx-embedded {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  cursor: default;
  touch-action: auto;
  /* transform-origin en la esquina superior derecha (no "center") -- al
     encoger, el modelo se queda anclado ahi en vez de flotar hacia el medio
     del hueco. Pedido explicito: "mas o menos debajo del boton Hazte
     Premium... mas a la derecha, un poco mas arriba". */
  transform: scale(.4);
  transform-origin: top right;
}
#spider-x-controls {
  position: fixed;
  left: 18px;
  bottom: 222px;
  z-index: 41;
  display: flex;
  gap: 6px;
}
#spider-x-controls.spx-embedded {
  position: absolute;
  left: auto;
  bottom: auto;
  top: 8px;
  right: 8px;
  z-index: 5;
}
.spider-x-btn {
  width: 30px;
  height: 30px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--bg-panel);
  color: var(--text);
  font-size: 14px;
  cursor: pointer;
  opacity: .55;
  transition: opacity .15s ease;
}
.spider-x-btn:hover { opacity: 1; }

/* Aviso de "posicion ficticia" bajo la mascota -- ver spider-x-bootstrap.js.
   pointer-events:none para que no estorbe al arrastrar la mascota si el
   navegador considera que este texto (justo debajo) tambien es objetivo. */
#spider-x-caption {
  position: fixed;
  z-index: 40;
  text-align: center;
  font-size: 10.5px;
  line-height: 1.3;
  color: var(--text-dim);
  opacity: .75;
  pointer-events: none;
  text-shadow: 0 1px 2px var(--bg);
}
#spider-x-caption.spx-embedded {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 6px;
  width: auto;
}

#spider-x-devpanel {
  position: fixed;
  left: 18px;
  top: 18px;
  z-index: 50;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 12px;
  font-size: 12px;
  color: var(--text);
  max-width: 260px;
}
#spider-x-devpanel strong { display: block; margin-bottom: 6px; color: var(--accent-2); }
#spider-x-devpanel .spx-dev-estados { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 8px; }
#spider-x-devpanel .spx-dev-estados button {
  font-size: 10.5px;
  padding: 3px 6px;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--bg-card);
  color: var(--text);
  cursor: pointer;
}
#spider-x-devpanel .spx-dev-estados button:hover { border-color: var(--accent-2); }
#spider-x-devpanel label { display: block; font-size: 11px; color: var(--text-dim); margin-top: 4px; }
#spider-x-devpanel input[type="range"] { width: 100%; }

@media (max-width: 520px) {
  #spider-x-widget { width: 130px; height: 130px; left: 8px; bottom: 8px; }
  #spider-x-controls { left: 8px; bottom: 148px; }
}

/* ---------- Musica ambiental global (spiderx-music.js) ---------- */
/* Por defecto es un hijo mas de .topbar-actions (junto al icono de sonido de
   "token nuevo" que ya vive ahi, en index.html) -- flujo normal, sin
   position:fixed. Solo en las paginas que NO tienen esa fila de acciones en
   la topbar (todas menos index.html hoy) spiderx-music.js le añade
   .spx-music-flotante y entonces sí se fija arriba a la derecha. */
#spiderx-music-control {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: 999px;
  opacity: .6;
  transition: opacity .15s ease;
}
#spiderx-music-control:hover,
#spiderx-music-control:focus-within { opacity: 1; }
#spiderx-music-control.spx-music-flotante {
  position: fixed;
  top: 18px;
  right: 18px;
  z-index: 41;
}
#spiderx-music-control.spx-music-off #spiderx-music-volume {
  opacity: .35;
  pointer-events: none;
}
#spiderx-music-toggle {
  width: 30px;
  height: 30px;
  flex: none;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--bg-card);
  color: var(--text-dim);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
#spiderx-music-toggle[aria-pressed="true"] {
  border-color: var(--accent-2);
  color: var(--accent-2);
}
#spiderx-music-toggle:hover { opacity: .9; }
.spx-music-icon {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: 2px;
  width: 14px;
  height: 12px;
}
.spx-music-icon .spx-bar {
  width: 3px;
  height: 4px;
  border-radius: 1px;
  background: currentColor;
  transform-origin: bottom;
  transition: height .15s ease;
}
/* Sin musica sonando: tres barras quietas a distinta altura, como un
   ecualizador en pausa -- no hace falta otro icono para el estado "off". */
.spx-music-icon .spx-bar:nth-child(1) { height: 5px; }
.spx-music-icon .spx-bar:nth-child(2) { height: 9px; }
.spx-music-icon .spx-bar:nth-child(3) { height: 3px; }
#spiderx-music-toggle.spx-music-playing .spx-bar {
  animation: spx-music-eq 0.9s ease-in-out infinite;
}
#spiderx-music-toggle.spx-music-playing .spx-bar:nth-child(1) { animation-delay: -0.6s; }
#spiderx-music-toggle.spx-music-playing .spx-bar:nth-child(2) { animation-delay: -0.2s; }
#spiderx-music-toggle.spx-music-playing .spx-bar:nth-child(3) { animation-delay: -0.4s; }
@keyframes spx-music-eq {
  0%, 100% { height: 3px; }
  50% { height: 12px; }
}
#spiderx-music-volume {
  width: 64px;
  accent-color: var(--accent-2);
  cursor: pointer;
}
@media (max-width: 520px) {
  #spiderx-music-control { padding: 5px 8px; gap: 6px; }
  #spiderx-music-control.spx-music-flotante { top: 8px; right: 8px; }
  #spiderx-music-volume { width: 46px; }
}

/* ---------- Pagina "nuestro centinela" (mascota.html) ---------- */
.mascota-hero {
  margin: 8px 0 36px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: linear-gradient(135deg, rgba(255,106,0,.08), transparent 60%);
  overflow: hidden;
}
.mascota-hero .foto {
  width: 100%;
  aspect-ratio: 16 / 8;
  object-fit: cover;
  object-position: center 35%;
  display: block;
  background: #d8d8d8;
}
.mascota-hero .txt { padding: 20px 24px 24px; }
.mascota-hero .lead { margin: 0; }

.mascota-estados {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 18px;
  margin: 18px 0 36px;
}
.mascota-estado {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-card);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
.mascota-estado img {
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  background: #0b0e14;
  display: block;
}
.mascota-estado .txt { padding: 14px 16px; }
.mascota-estado h3 { margin: 0 0 6px; font-size: 14.5px; }
.mascota-estado p { margin: 0; font-size: 13.5px; color: var(--text-dim); }
.mascota-estado.tp { border-color: rgba(52,211,153,.4); }
.mascota-estado.sl { border-color: rgba(248,113,113,.4); }

@media (max-width: 640px) {
  .mascota-hero { flex-direction: column; text-align: center; }
}
