/* ===========================================================================
   LOBBY "BOSQUE" — el menú con madera, culebra y hojas.
   ---------------------------------------------------------------------------
   Todo cuelga de `body.bosque`, que solo se pone en la pantalla del lobby: el
   resto del juego (entrar, ranking, ganancias, la partida) queda intacto con el
   tema de siempre.

   Dos cosas que hacen falta y no son obvias:

   1) Las clases van con prefijo `bq-` porque nombres como .stat, .panel o
      .jugar YA EXISTEN en theme.css y se pisarían.
   2) Cada selector lleva `body.bosque` adelante por ESPECIFICIDAD, no por
      alcance: theme.css usa selectores con etiqueta (`.clay-card h2`) que le
      ganan a una clase sola, y el nombre del jugador salía en 22 px con 12 px
      de margen ajenos. Con dos clases delante, este archivo manda.

   Los dibujos se sirven como archivos desde assets/ui/ (no incrustados): así el
   teléfono los guarda en caché y no viajan en cada carga del HTML.

   Regla aprendida a golpes con este fondo: TODO texto que caiga directo sobre
   el fondo necesita contorno oscuro. El fondo va de luminancia 0.007 en las
   sombras a 0.909 en los brillos, así que ningún color relleno solo aguanta las
   dos puntas. Con `paint-order: stroke fill` el contorno se dibuja ANTES del
   relleno; si no, en letra chica tapa los huecos de la B y la E.
   =========================================================================== */

/* ---- el fondo, solo en el lobby ---- */
body.bosque { background: #2a5c33 }
/* La imagen va QUIETA. Antes derivaba despacio; se saco por pedido y de paso
   el telefono deja de componer una capa animada todo el tiempo. */
body.bosque::before {
  content: ""; position: fixed; inset: 0; z-index: 0;
  background: url("assets/ui/fondo_toon.webp?v=1") 0 0/190px 190px repeat;
}
body.bosque::after {
  content: ""; position: fixed; inset: 0; z-index: 0; pointer-events: none;
  background:
    radial-gradient(120% 62% at 50% -12%, rgba(255, 246, 186, .30), rgba(255, 246, 186, 0) 58%),
    radial-gradient(120% 80% at 50% 118%, rgba(12, 48, 20, .42), rgba(12, 48, 20, 0) 55%);
}

/* ---- la tarjeta: sin vidrio, sin marco, a pantalla completa ---- */
body.bosque-lobby #ov {
  /* overflow hidden a proposito: el menu entra entero, nunca se desliza. La hoja
     de vistas le pone overflow-y:auto para las pantallas largas y aqui eso
     reservaba sitio para la barra de scroll — 12 px de ancho perdidos. */
  background: none; align-items: stretch; overflow: hidden;
  padding: max(6px, env(safe-area-inset-top)) max(6px, env(safe-area-inset-right))
           max(6px, env(safe-area-inset-bottom)) max(6px, env(safe-area-inset-left));
}
/* fuera las chispas del tema viejo */
body.bosque .ov-scrim::before, body.bosque .ov-scrim::after { display: none }
body.bosque-lobby #card {
  /* La animacion de entrada del tema viejo (card-pop) deja la tarjeta escalada:
     medía 400 px de caja pero se dibujaba en 388, y los botones perdian 12 px de
     ancho. Aqui no hace falta esa entrada. */
  animation: none; transform: none;
  max-width: 430px; max-height: none; height: 100%; overflow: visible;
  padding: 0 !important; background: none; border: 0; border-radius: 0; box-shadow: none;
  backdrop-filter: none; -webkit-backdrop-filter: none;
  display: flex; flex-direction: column;
}
body.bosque .bq { position: relative; display: flex; flex-direction: column; flex: 1; min-height: 0; padding: 0 }

/* ---- cabecera: avatar centrado, nombre debajo ---- */
body.bosque .bq-cab { display: flex; flex-direction: column; align-items: center; flex: none; margin-bottom: 5px }
body.bosque .bq-avwrap { position: relative; width: 70px; height: 70px; flex: none }
body.bosque .bq-av {
  width: 70px; height: 70px; border-radius: 999px; position: relative; overflow: hidden;
  display: flex; align-items: center; justify-content: center; font-size: 30px;
  background: radial-gradient(circle at 50% 35%, #2c4a2e, #16281a); border: 3px solid #7fbf6a;
  box-shadow: 0 0 0 3px rgba(20, 40, 22, .9), 0 0 16px rgba(126, 224, 140, .35);
}
body.bosque .bq-av img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover }
/* el hueco del avatar propio: dice "Tu foto" en vez del monigote. El de las
   filas del ranking (otra gente) sigue igual, lo pinta otra funcion. */
body.bosque .bq-av .bq-sinfoto {
  font-family: var(--font-mono); font-weight: 700; font-size: 11px; line-height: 1.15;
  letter-spacing: .02em; text-align: center; color: #cfe6bf; text-transform: uppercase;
}
body.bosque .bq-cam {
  position: absolute; right: -4px; bottom: -2px; width: 26px; height: 26px; border-radius: 999px;
  display: flex; align-items: center; justify-content: center; font-size: 13px; cursor: pointer;
  background: linear-gradient(180deg, #3f7a3a, #28551f); border: 2px solid #17330f; color: #f3ffe4;
  box-shadow: 0 2px 0 #13270d;
}
body.bosque .bq-cam:active { transform: translateY(2px); box-shadow: none }
body.bosque .bq-nombre {
  margin: 5px 0 0; font-size: 28px; font-weight: 800; line-height: 1.05; text-align: center;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  color: #fff6e2; -webkit-text-stroke: .09em #16300f; paint-order: stroke fill;
  text-shadow: 0 .05em 0 rgba(0, 0, 0, .5);
}
/* "Quitar foto" solo aparece cuando hay foto puesta, y cae sobre el fondo: en
   blanco con contorno se lee sobre las hojas claras y sobre las sombras. Por
   estar escondido de arranque, la auditoría de contraste no lo veía. */
/* va con .bq-cab delante porque este botón también lleva la clase .link, y la
   regla de .link de vistas-bosque.css se carga después y le ganaba el color */
body.bosque .bq-cab .av-rm {
  align-self: center; margin: 3px 0 0; padding: 0; background: none; border: 0;
  font-family: var(--font-mono); font-weight: 700; font-size: 11px; color: #ffffff;
  text-decoration: underline;
  -webkit-text-stroke: .15em #143314; paint-order: stroke fill; text-shadow: 0 .08em .12em rgba(0, 0, 0, .55);
}

/* ---- cápsulas de tickets y saldo ----
   El ícono va AL COSTADO, no colgando arriba: arriba le caía justo encima al
   rótulo y no se leía. Rejilla de dos columnas donde el ícono ocupa las dos
   filas; así no crece de alto y el menú sigue entrando en una pantalla. */
body.bosque .bq-stats {
  display: flex; flex-wrap: nowrap; justify-content: center; gap: 5px; flex: none; margin-bottom: 5px;
}
body.bosque .bq-stat {
  position: relative; flex: 1 1 0; min-width: 0; max-width: 190px; min-height: 34px; padding: 4px 5px 5px;
  display: grid; grid-template-columns: auto auto; grid-template-areas: "rot rot" "ico val";
  /* `align-content: start` clava la PRIMERA fila arriba en las tres cápsulas. Con
     `center` (lo de antes) el bloque se centraba, y como la de trozos tiene una fila
     más, su rótulo quedaba a otra altura que los otros dos. Ahora los tres rótulos
     y los tres números arrancan en la misma línea, y el pie de los trozos cuelga
     debajo sin mover nada. */
  align-items: center; align-content: center; justify-items: center; justify-content: center;
  column-gap: 6px; row-gap: 1px;
  border: 11px solid transparent;
  border-image: url("assets/ui/capsula.webp?v=1") 47 fill / 11px / 0 stretch;
  filter: drop-shadow(0 3px 4px rgba(0, 0, 0, .45));
}
body.bosque .bq-ico {
  grid-area: ico; justify-self: center; width: 30px; height: 30px; background: center/contain no-repeat;
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, .7));
}
/* v18 TROZOS DE TICKET — la TERCERA cápsula, al lado de tickets y saldo.
   Va en la misma fila y no en una línea aparte porque los trozos son otra moneda
   del juego, igual que las otras dos: separarlos los hacía ver como un aviso.

   Pasar de dos cápsulas a tres en un teléfono de 360 px obliga a apretar: el
   hueco baja de 10 a 6 px, el relleno lateral de 8 a 6, y el ícono de 34 a 30.
   `min-width: 0` en cada una es lo que permite que se encojan en vez de
   desbordar la fila (sin eso, flex respeta el ancho del contenido y la tercera
   se sale de la pantalla). */
/* la de trozos lleva UNA FILA MÁS que las otras dos: la regla, cruzando las dos
   columnas. Por eso su rejilla se redefine con un tercer renglón. */
body.bosque .bq-stat.frag {
  /* SIN row-gap: se lo había puesto solo a esta cápsula y ese píxel de separación
     empujaba su número 1 px más abajo que los de las otras dos. La separación del
     pie ya la da su propio margen. */
  grid-template-areas: "rot val" "ico pie";
  /* el rótulo y el contador comparten la primera fila, y la regla acompaña al
     ícono en la segunda: dos filas, igual que tickets y saldo. */
}
body.bosque .bq-ico.trz { background-image: url("assets/ui/ic_trozo.webp?v=1"); width: 35px }
/* el "2/4": el número grande y el total chiquito, para que se lea cuánto falta
   sin tener que procesar una fracción entera */
/* en trozos el número comparte fila con el rótulo: a 30 px estiraría esa fila y la
   cápsula entera crecería, así que se queda más contenido. */
body.bosque .bq-val.trz { font-size: 21px }
body.bosque .bq-val.trz b { font-size: .68em; font-weight: 700; opacity: .78 }
/* la regla, dentro de la cápsula. Va sin contorno (el fondo de la cápsula ya da el
   contraste) y se parte sola en dos renglones. */
body.bosque .bq-frag-pie {
  grid-area: pie; margin: 0; text-align: left; align-self: center;
  font-family: var(--font-mono); font-size: 8.5px; font-weight: 700; line-height: 1.2;
  color: #cfe6bf; letter-spacing: -.01em;
}
@media (max-height: 700px) {
  body.bosque .bq-frag-pie { font-size: 8px }
}
/* el ticket es más ancho que alto (1.20 contra 1.00 de la moneda): con caja
   cuadrada quedaba 17% más bajo y pesaba menos al lado del otro */
body.bosque .bq-ico.tk  { background-image: url("assets/ui/ic_ticket.webp?v=1"); width: 35px }
body.bosque .bq-ico.usd { background-image: url("assets/ui/ic_dolar.webp?v=1") }
body.bosque .bq-rot {
  grid-area: rot; margin: 0; font-family: var(--font-mono); font-weight: 700; font-size: 13px;
  letter-spacing: .04em; text-transform: uppercase; text-align: center; color: #f3ffe4; line-height: 1.05;
  -webkit-text-stroke: .14em #10240f; paint-order: stroke fill; text-shadow: 0 .09em .1em rgba(0, 0, 0, .5);
}
body.bosque .bq-val {
  /* caja de alto FIJO: el "/4" del contador va en letra más chica y eso cambiaba la
     altura de la línea, dejando ese número 1 px más abajo que los otros dos. Con alto
     fijo y centrado, los tres quedan en la misma línea sea cual sea el contenido. */
  grid-area: val; display: flex; align-items: center; justify-content: center; height: 1.2em;
  font-family: var(--font-mono); font-weight: 700; font-size: 30px; line-height: 1; white-space: nowrap;
  text-align: center; color: #ffe9a6; -webkit-text-stroke: .13em #10240f; paint-order: stroke fill;
  text-shadow: 0 .07em 0 rgba(0, 0, 0, .5);
}
body.bosque .bq-val.bal { color: #b6f58c }

/* ---- COMPETIR: la culebra ---- */
/* 90% del ancho: el boton baja de tamano y, como su alto lo manda la
   proporcion del dibujo, se encoge parejo sin deformar la culebra.
   El costo va al lado del texto, mas chico, para que no le compita. */
body.bosque .bq-jugar {
  position: relative; display: flex; align-items: center; justify-content: center; gap: 9px;
  width: 90%; align-self: center; aspect-ratio: 780/211; flex: none; margin: 0 0 6px;
  border: 0; background: none; cursor: pointer;
  font-family: var(--font-head); font-weight: 800; font-size: 24px; transition: transform .12s ease;
}
/* el costo: el numero y el DIBUJO del ticket, no la palabra. La imagen es 1.20
   de ancho contra alto, asi que va 18x15 para no salir estirada. */
body.bosque .bq-costo {
  position: relative; z-index: 1; flex: none; font-style: normal;
  display: inline-flex; align-items: center; gap: 5px;
  font-family: var(--font-mono); font-weight: 700; font-size: 14px; line-height: 1;
  padding: 4px 9px 5px; border-radius: 999px; white-space: nowrap;
  background: rgba(10, 30, 12, .72); border: 1px solid #8fd97a; color: #eaffd8;
}
body.bosque .bq-costo::after {
  content: ""; flex: none; width: 18px; height: 15px;
  background: url("assets/ui/ic_ticket.webp?v=1") center/contain no-repeat;
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, .5));
}
/* el DIBUJO del ticket dentro del rótulo de jugar ("Jugar 1 ticket 🎫 / $2").
   Va en `em` y no en píxeles para que crezca y se encoja con la letra: el botón grande
   escribe a 24 px y el de media fila a 17, y con un tamaño fijo se veía enorme en uno y
   perdido en el otro. La proporción es la real de la imagen (1.20 de ancho contra alto),
   así que no sale estirada. El contorno del texto (-webkit-text-stroke) no la toca. */
body.bosque .bq-t.big .bq-tk {
  display: inline-block; flex: none; width: 1.15em; height: .96em; margin: 0 .2em -.07em;
  background: url("assets/ui/ic_ticket.webp?v=1") center/contain no-repeat;
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, .5));
}
body.bosque .bq-jugar::before {
  content: ""; position: absolute; inset: 0;
  background: url("assets/ui/boton.webp?v=1") center/100% 100% no-repeat;
  filter: drop-shadow(0 4px 7px rgba(0, 0, 0, .5));
}
body.bosque .bq-jugar span { position: relative; z-index: 1 }
body.bosque .bq-jugar:active { transform: translateY(2px) scale(.99) }

/* LOS DOS MODOS, UNO AL LADO DEL OTRO (pedido del dueño). Antes el de competir ocupaba
   el 90% del ancho y el de contrarreloj caia debajo, empujando el resto del menu fuera
   de pantalla en telefonos cortos.
   Van en una fila con el ancho repartido y el boton se ENCOGE: el fondo es una imagen
   con aspect-ratio fijo, asi que reducir el ancho reduce el alto solo y no se deforma.
   La letra baja a 17 px porque "CONTRARRELOJ" es larga y a 24 no entra. */
body.bosque .bq-modos {
  display: flex; gap: 8px; width: 96%; align-self: center; margin: 0 0 7px; flex: none;
}
/* Los botones de modo YA NO usan el ovalo (boton.webp). Ese dibujo es de proporcion
   fija (780x211): estirado a media fila quedaba deforme y el texto de CONTRARRELOJ
   se montaba en el borde curvo -- medido: 14px de holgura contra 39 del otro, y el
   marco un 37% mas gordo que el dibujo original. En su lugar va la CAPSULA verde de
   las estadisticas: es un borde 9-slice, como las tablas de madera, asi que llena
   CUALQUIER caja sin deformarse y todo el ancho interior es utilizable. Verde = jugar
   (los dos modos), madera = menu; y la jerarquia la dan el alto, el dorado y el latido. */
body.bosque .bq-modos .bq-jugar {
  width: auto; flex: 1 1 0; min-width: 0; margin: 0;
  aspect-ratio: auto; height: 74px;
  flex-direction: column; gap: 2px; padding: 3px 8px 5px;
  border: 13px solid transparent;
  border-image: url("assets/ui/capsula.webp?v=1") 47 fill / 13px / 0 stretch;
  filter: drop-shadow(0 3px 4px rgba(0, 0, 0, .45));
  font-size: clamp(14px, 4.3vw, 17px);
}
/* el ovalo del boton grande vive en ::before; aqui sobra */
body.bosque .bq-modos .bq-jugar::before { display: none }
/* el costo SIN pastilla (pedido del dueño): solo el numero y el ticket, flotando */
body.bosque .bq-modos .bq-costo { background: none; border: 0; padding: 0; font-size: 11px; gap: 4px }
body.bosque .bq-modos .bq-costo::after { width: 15px; height: 12px }
body.bosque .bq-modos .bq-t.big { line-height: 1.06; text-align: center }

/* ===== EL BOTON DE JUGAR, SOLO EN LA FILA =====
   NO lleva la culebra (boton.webp). Se probo traerla de vuelta —es el dibujo que enmarcaba
   el boton en la version vieja— y al dueño no le gusto, asi que se queda la CAPSULA verde
   como el resto. Queda anotado para no volver a intentarlo: el problema no era tecnico (con
   aspect-ratio la culebra no se deformaba en ningun tamaño), era que no gustaba.

   Lo que SI se conserva de ese intento es el rotulo: una sola linea, "Jugar" grande y el
   costo separado y mas chico. Con la capsula hay mas sitio que con la culebra —322x48 px
   utiles contra 229x32— asi que la separacion puede ser mas generosa. */
body.bosque .bq-modos .bq-jugar:only-child {
  flex-direction: row; align-items: center; justify-content: center;
  font-size: clamp(15px, 4.6vw, 18px);
}
body.bosque .bq-modos .bq-jugar:only-child .bq-t.big { white-space: nowrap; line-height: 1.02 }
body.bosque .bq-modos .bq-jugar:only-child .rp-a { display: inline; font-size: 1.5em }
/* 2em de separacion (venia de .75): el dueño la pidio mas suelta dos veces. A 18 px de base
   son 36 px de aire, y el rotulo entero sigue midiendo la mitad del hueco disponible. */
body.bosque .bq-modos .bq-jugar:only-child .rp-b { display: inline; margin-left: 2em; font-size: .95em }
/* EL ROTULO DE JUGAR, EN UNA O EN DOS LINEAS.
   El boton de contrarreloj vive siempre dentro de .bq-modos, solo o acompañado, asi que
   lo que los distingue es :only-child — no una clase, que habria que recordar poner.
     · solo (lo de hoy):        "Jugar 1 ticket [ticket] / $2"   en una linea (306 px utiles, mide 164)
     · con COMPETIR al lado:    "Jugar 1 ticket" / "[ticket] / $2"  en dos (solo hay 128 px)
   Cada pieza lleva nowrap para que ninguna se parta por dentro. */
body.bosque .bq-modos .bq-jugar .bq-t.big { white-space: normal }
body.bosque .bq-modos .bq-jugar .bq-t.big .rp-a,
body.bosque .bq-modos .bq-jugar .bq-t.big .rp-b { display: block; white-space: nowrap }
body.bosque .bq-modos .bq-jugar:only-child .bq-t.big .rp-a,
body.bosque .bq-modos .bq-jugar:only-child .bq-t.big .rp-b { display: inline }

/* ---- la lista de tablas ----
   Sin alto mínimo: los botones se reparten lo que sobra. Los anchos del borde
   salen de variables que calcula acomodaPlanks() a partir del alto REAL, porque
   los bordes no se encogen solos: si fueran fijos y no cupieran, la lista
   desbordaría y la fila de abajo quedaría montada sobre el último botón.
   Los cortes 81/94/35/100 dejan cada ramo de hojas dentro de una esquina, y en
   un marco de 9 piezas las esquinas se copian tal cual: por más que el botón se
   estire, las hojas no se deforman. */
/* En un telefono alto las tablas se repartian TODO el alto libre y salian enormes al
   lado de los botones de modo. Se les pone techo y el sobrante se reparte como AIRE
   entre ellas (space-evenly), no como madera. acomodaPlanks() no se entera: lee el
   alto REAL de cada tabla despues del layout, sea cual sea. */
body.bosque .bq-lista { display: flex; flex-direction: column; flex: 1; min-height: 0; gap: 3px }
body.bosque .bq-lista.con-modos { justify-content: space-evenly }
body.bosque .bq-lista.con-modos .bq-tabla { max-height: 84px }
body.bosque .bq-tabla {
  position: relative; flex: 1 1 0; min-height: 0; display: flex; align-items: center; justify-content: center;
  gap: 8px; padding: 0 22px var(--bq-pb, 7px); cursor: pointer; background: none; text-align: center;
  border: 30px solid transparent;
  border-width: var(--bq-bt, 30px) var(--bq-br, 35px) var(--bq-bb, 13px) var(--bq-bl, 37px);
  border-image: url("assets/ui/tabla.webp?v=1") 81 94 35 100 fill /
    var(--bq-bt, 30px) var(--bq-br, 35px) var(--bq-bb, 13px) var(--bq-bl, 37px) / 0 stretch;
  filter: drop-shadow(0 3px 4px rgba(0, 0, 0, .45)); transition: transform .12s ease, filter .12s ease;
}
body.bosque .bq-tabla:active {
  transform: translateY(2px); filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .45)) brightness(1.06);
}
/* el ícono va EN LÍNEA con el texto: en las esquinas de arriba hay hojas */
body.bosque .bq-tabla i.ic {
  width: var(--bq-ic, 28px); height: var(--bq-ic, 28px); flex: none;
  background: center/contain no-repeat; filter: drop-shadow(0 2px 2px rgba(0, 0, 0, .55));
}
body.bosque .bq-tabla i.ic.ancho { width: calc(var(--bq-ic, 28px) * 1.42) }
body.bosque .bq-tabla i.podio    { background-image: url("assets/ui/ic_podio.webp?v=1") }
body.bosque .bq-tabla i.culebra  { background-image: url("assets/ui/culebra.webp?v=1") }
body.bosque .bq-tabla i.banderas { background-image: url("assets/ui/ic_banderas.webp?v=1") }
body.bosque .bq-tabla i.usd      { background-image: url("assets/ui/ic_dolar.webp?v=1") }
body.bosque .bq-tabla i.ticket   { background-image: url("assets/ui/ic_ticket.webp?v=1") }
body.bosque .bq-tabla i.refs     { background-image: url("assets/ui/ic_referidos.webp?v=1") }
body.bosque .bq-t {
  color: #fff4da; font-weight: 800; font-size: clamp(15px, 4.4vw, 19px); line-height: 1.1;
  letter-spacing: .005em; white-space: nowrap;
  -webkit-text-stroke: .155em #2e1408; paint-order: stroke fill; text-shadow: 0 .085em 0 rgba(0, 0, 0, .45);
}
/* "Mejores Jugadas recientes" es el rótulo MÁS LARGO del menú y hay que meterlo COMPLETO
   en la tabla de madera. Va en UN renglón más chico, y no en dos, porque la tabla solo
   tiene 19 px de alto por dentro (el resto es la madera con las hojas): dos renglones se
   salían por arriba, encima de las hojas.
   EL TELÉFONO ANGOSTO ES EL QUE MANDA. El borde de madera mide 93 px SIEMPRE (sale del
   alto de la tabla, no del ancho), así que en una pantalla de 320 se come mucho más
   sitio en proporción: ahí la fuente máxima que entra es 11.2 px = 3.50vw, mientras que
   en una de 430 caben 18.6 px. Por eso el coeficiente es 3.3vw — el que entra en la
   angosta entra en todas. Medido, no estimado.
   Los costados pierden los 22 px de aire (pasan a 6): se los puede dar porque el marco
   ya separa el texto de la madera. La clase va en el BOTÓN y no con :has() a propósito —
   :has() no existe en los Android viejos y ahí el texto se saldría sin que nada avise.
   Y el recorte con puntitos es el último seguro: en una pantalla más angosta que 320
   (una Fold cerrada) preferimos "…recient…" antes que texto encima de las hojas. */
body.bosque .bq-tabla.estrecho { padding-left: 6px; padding-right: 6px }
body.bosque .bq-tabla .bq-t.largo {
  font-size: clamp(10px, 3.3vw, 15px); min-width: 0; overflow: hidden; text-overflow: ellipsis;
}
body.bosque .bq-t.big {
  color: #ffe57a; font-size: inherit; -webkit-text-stroke: .145em #14380e;
  text-shadow: 0 .07em 0 rgba(0, 0, 0, .5), 0 0 .8em rgba(255, 214, 90, .55);
  animation: bq-latido 2.6s ease-in-out infinite;
}
@keyframes bq-latido { 0%, 100% { transform: scale(1) } 50% { transform: scale(1.05) } }

/* el punto de EN VIVO: rojo, con halo, latiendo despacio, pegado al texto */
body.bosque .bq-vivo {
  width: 11px; height: 11px; border-radius: 999px; flex: none;
  background: radial-gradient(circle at 35% 32%, #ff9c8e 0%, #f22b2b 55%, #960b0b 100%);
  box-shadow: 0 0 7px 2px rgba(255, 45, 45, .85), inset 0 -1px 2px rgba(0, 0, 0, .55);
  animation: bq-envivo 2.2s ease-in-out infinite;
}
@keyframes bq-envivo {
  0%, 100% { opacity: 1; box-shadow: 0 0 9px 3px rgba(255, 45, 45, .95), inset 0 -1px 2px rgba(0, 0, 0, .55) }
  50%      { opacity: .42; box-shadow: 0 0 2px 0 rgba(255, 45, 45, .30), inset 0 -1px 2px rgba(0, 0, 0, .55) }
}

/* ---- avisos y racha ----
   Los mensajes del juego se escriben con className = "msg", así que se estilan
   por ESA clase: si se les pusiera una nueva, el primer error la borraría y el
   texto quedaría invisible sobre el fondo. */
body.bosque .bq-aviso, body.bosque .msg {
  flex: none; margin: 0 0 7px; padding: 0; background: none; border: 0; text-align: center;
  font-family: var(--font-mono); font-weight: 700; font-size: 11px; line-height: 1.4; color: #f3ffe4;
  -webkit-text-stroke: .15em #143314; paint-order: stroke fill; text-shadow: 0 .08em .12em rgba(0, 0, 0, .55);
}
body.bosque .msg { color: #ffd9cf; -webkit-text-stroke-color: #4a1208 }
body.bosque .msg.info, body.bosque .msg.ok { color: #f3ffe4; -webkit-text-stroke-color: #143314 }
body.bosque .bq-aviso:empty, body.bosque .msg:empty { display: none }
body.bosque #l-racha:not(:empty) { flex: none; margin-bottom: 8px }
body.bosque #l-racha .rk { background: rgba(10, 26, 12, .72); border: 2px solid #4b8b45; border-radius: 13px }

/* ---- los dos botones de las esquinas de arriba -----------------------------
   Antes iban en una fila propia abajo, que costaba ~59 px de alto. Arriba, a los
   lados del avatar, ese espacio estaba vacio: ahi caben los dos y la lista se
   queda con el alto que sobra. Van redondos porque en una esquina un pill se
   lee como un recorte, no como un boton.
   Quedan por ENCIMA del nombre en z pero no lo pisan: el avatar mide 70 px de
   ancho y esta centrado, asi que a los costados sobran mas de 100 px. */
/* ---- la placa de madera del soporte ---------------------------------------
   El boton va DENTRO de un recuadro de madera, con el rotulo debajo. La madera
   de placa.webp se saco de tabla.webp, asi que es la misma veta y el mismo tono
   que los botones de la lista: no se ve como un parche pegado.
   Marco de 9 piezas (corte 46) para que las esquinas redondeadas no se estiren.
   El volumen queda como circulo suelto a la izquierda, a la misma altura que el
   circulo del soporte, para que los dos se lean como un par. */
body.bosque .bq-placa {
  position: absolute; top: 0; right: 0; z-index: 3;
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 0 5px 4px;
  border: 12px solid transparent;
  border-image: url("assets/ui/placa.webp?v=1") 46 fill / 12px / 0 stretch;
  filter: drop-shadow(0 3px 5px rgba(0, 0, 0, .45));
}
body.bosque .bq-son, body.bosque .bq-soporte {
  width: 42px; height: 42px; padding: 0; flex: none;
  border-radius: 999px; cursor: pointer; display: flex; align-items: center; justify-content: center;
  font-size: 20px; line-height: 1;
}
body.bosque .bq-son {
  position: absolute; top: 14px; left: 2px; z-index: 3;
  background: linear-gradient(180deg, #6a6a6a, #3a3a3a); border: 2px solid #262626;
  box-shadow: 0 3px 0 #1a1a1a, inset 0 1px 0 rgba(255, 255, 255, .18);
}
body.bosque .bq-son.off { background: linear-gradient(180deg, #5a5a5a, #303030) }
body.bosque .bq-son:active { transform: translateY(3px); box-shadow: 0 0 0 #1a1a1a }
body.bosque .bq-soporte {
  position: relative; background: linear-gradient(180deg, #ffb149, #ea6412); border: 2px solid #7d3005;
  box-shadow: 0 3px 0 #5e2404, 0 0 20px rgba(255, 140, 45, .5), inset 0 1px 0 rgba(255, 255, 255, .42);
  color: #3f1602;
}
body.bosque .bq-soporte:active { transform: translateY(3px); box-shadow: 0 0 0 #5e2404, 0 0 14px rgba(255, 140, 45, .4) }
/* el globito rojo sobre naranja da 1.7:1 y se pierde: el aro crema lo separa */
body.bosque .bq-soporte em {
  position: absolute; top: -5px; right: -4px; min-width: 21px; height: 21px; padding: 0 4px;
  display: flex; align-items: center; justify-content: center; border-radius: 999px;
  background: #d91f10; border: 2px solid #ffeccd; color: #fff; font-style: normal;
  font-family: var(--font-mono); font-weight: 700; font-size: 11px; box-shadow: 0 2px 6px rgba(0, 0, 0, .45);
}
body.bosque .bq-soporte em.hidden { display: none }
/* el rótulo "Soporte" debajo del botón: un círculo con 💬 no dice qué hace, y
   cae sobre el fondo, así que lleva contorno como todo lo que no está dentro de
   un panel. Va absoluto para no cambiar el tamaño del círculo. */
body.bosque .bq-placa .bq-et {
  position: static; font-style: normal; font-family: var(--font-head); font-weight: 800; font-size: 15px;
  line-height: 1; white-space: nowrap; pointer-events: none; color: #fff3dc;
  -webkit-text-stroke: .16em #3a1c06; paint-order: stroke fill; text-shadow: 0 .08em .1em rgba(0, 0, 0, .45);
}
body.bosque .bq-soporte.late { animation: bq-latechat 1.5s ease-in-out infinite }
/* ---- "Mensaje nuevo" -------------------------------------------------------
   El juego ya lo tenía (#chatNew, un texto rojo que titila junto al flotante) y
   el diseño nuevo lo estaba escondiendo. Vuelve, pero al lado del botón redondo.
   Va como elemento propio y no reusando #chatNew porque ese es `position: fixed`
   pegado a la esquina de la PANTALLA: en una tablet, donde la tarjeta queda
   centrada y angosta, aparecería lejísimos del botón. Este es absoluto dentro de
   la tarjeta, así que sigue al botón a cualquier ancho.
   La punta a la derecha lo ata visualmente al botón, como un globo de diálogo. */
body.bosque .bq-nuevo {
  position: absolute; top: 92px; right: 2px; z-index: 3; pointer-events: none;
  padding: 5px 9px 6px; border-radius: 9px; font-style: normal; white-space: nowrap;
  background: linear-gradient(180deg, #e8483a, #b8231a); border: 2px solid #ffeccd;
  font-family: var(--font-head); font-weight: 800; font-size: 11px; line-height: 1; color: #fff;
  box-shadow: 0 3px 8px rgba(0, 0, 0, .5);
  animation: bq-avisonuevo 1.4s ease-in-out infinite;
}
body.bosque .bq-nuevo::after {
  content: ""; position: absolute; top: -9px; right: 16px;
  border: 5px solid transparent; border-bottom-color: #ffeccd;
}
body.bosque .bq-nuevo.hidden { display: none }
@keyframes bq-avisonuevo { 0%, 100% { opacity: 1 } 50% { opacity: .45 } }
@keyframes bq-latechat {
  0%, 100% { box-shadow: 0 3px 0 #5e2404, 0 0 16px rgba(255, 140, 45, .45), inset 0 1px 0 rgba(255, 255, 255, .42) }
  50%      { box-shadow: 0 3px 0 #5e2404, 0 0 28px rgba(255, 196, 60, .9), inset 0 1px 0 rgba(255, 255, 255, .42) }
}

/* ---- cuenta: dos pastillas legibles ----
   Eran dos enlaces subrayados de 10.5 px sobre el fondo y no se leian. Con el
   alto que se gano al quitar la fila de abajo, pasan a ser botones de verdad. */
body.bosque .bq-cuenta {
  display: flex; align-items: center; justify-content: center; gap: 10px; flex: none; margin-top: 6px;
}
body.bosque .bq-cuenta button {
  flex: 0 1 auto; padding: 9px 14px 10px; border-radius: 999px; cursor: pointer; text-decoration: none;
  background: linear-gradient(180deg, #3f7a3a, #28551f); border: 2px solid #17330f;
  box-shadow: 0 3px 0 #13270d, inset 0 1px 0 rgba(255, 255, 255, .18);
  font-family: var(--font-head); font-weight: 800; font-size: 13px; color: #f3ffe4;
  -webkit-text-stroke: .1em #14330f; paint-order: stroke fill;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
body.bosque .bq-cuenta button:active { transform: translateY(2px); box-shadow: 0 1px 0 #13270d }
body.bosque .bq-cuenta button.out {
  background: linear-gradient(180deg, #b8483c, #7e2b22); border-color: #4a1208;
  box-shadow: 0 3px 0 #3c0f07, inset 0 1px 0 rgba(255, 255, 255, .18);
  color: #fff1ec; -webkit-text-stroke-color: #3c0f07;
}
body.bosque .bq-cuenta button.out:active { box-shadow: 0 1px 0 #3c0f07 }

/* en el lobby el chat flotante se esconde: su lugar es el botón de la fila */
body.bosque-lobby #chatBtn, body.bosque-lobby #chatNew { display: none !important }

/* ---- pantallas cortas ------------------------------------------------------
   Las TABLAS se acomodan solas (las escala acomodaPlanks), pero lo de arriba y
   abajo tiene tamaño fijo: si no se encoge también, en un teléfono corto se
   come todo el alto y a las tablas les quedan 12 px. Estas dos reglas son las
   que dejan sitio; el reparto de las tablas sale de lo que sobre. */
@media (max-height: 700px) {
  body.bosque .bq-avwrap, body.bosque .bq-av { width: 54px; height: 54px }
  body.bosque .bq-av .bq-sinfoto { font-size: 10px }
  body.bosque .bq-cam { width: 23px; height: 23px; font-size: 11px }
  body.bosque .bq-nombre { font-size: 23px }
  body.bosque .bq-cab { margin-bottom: 4px }
  body.bosque .bq-stat { min-height: 29px; padding: 3px 6px 4px }
  body.bosque .bq-ico { width: 29px; height: 29px }
  body.bosque .bq-ico.tk { width: 34px }
  body.bosque .bq-rot { font-size: 10px }
  body.bosque .bq-val { font-size: 19px }
  body.bosque .bq-stats { margin-bottom: 5px }
  body.bosque .bq-jugar { font-size: 20px; margin-bottom: 5px }
  /* en pantallas cortas la fila se aprieta un poco mas, pero NUNCA se apila: el
     objetivo del cambio era justamente que los dos entren en el mismo renglon */
  body.bosque .bq-modos { gap: 6px; width: 98% }
  /* mas bajos, para devolverle alto a las tablas */
  body.bosque .bq-modos .bq-jugar { gap: 1px; height: 62px; border-width: 11px; border-image-width: 11px }
  body.bosque .bq-costo { font-size: 13px; padding: 3px 8px 4px; gap: 4px }
  body.bosque .bq-costo::after { width: 16px; height: 13px }
  body.bosque .bq-lista { gap: 2px }
  body.bosque .bq-t { font-size: clamp(13.5px, 4vw, 17px) }
  body.bosque .bq-vivo { width: 10px; height: 10px }
  body.bosque .bq-son, body.bosque .bq-soporte { width: 38px; height: 38px; font-size: 18px }
  body.bosque .bq-placa { border-width: 11px; padding: 0 6px 3px }
  body.bosque .bq-placa .bq-et { font-size: 12px }
  body.bosque .bq-son { top: 12px }
  body.bosque .bq-nuevo { top: 84px; font-size: 10.5px; padding: 4px 8px 5px }
  body.bosque .bq-cuenta { margin-top: 5px; gap: 9px }
  body.bosque .bq-cuenta button { font-size: 12px; padding: 8px 12px 9px }
}
@media (max-height: 600px) {
  body.bosque .bq-avwrap, body.bosque .bq-av { width: 48px; height: 48px }
  body.bosque .bq-av .bq-sinfoto { font-size: 9px }
  body.bosque .bq-nombre { font-size: 20px }
  body.bosque .bq-stat { min-height: 26px }
  body.bosque .bq-ico { width: 26px; height: 26px }
  body.bosque .bq-ico.tk { width: 31px }
  body.bosque .bq-rot { font-size: 11px }
  body.bosque .bq-val { font-size: 24px }
  body.bosque .bq-jugar { font-size: 18px }
  body.bosque .bq-costo { font-size: 12px; padding: 3px 7px 4px }
  body.bosque .bq-costo::after { width: 15px; height: 12px }
  body.bosque .bq-t { font-size: clamp(12.5px, 3.7vw, 15px) }
  body.bosque .bq-son, body.bosque .bq-soporte { width: 34px; height: 34px; font-size: 16px }
  body.bosque .bq-placa { border-width: 10px; padding: 0 6px 3px }
  body.bosque .bq-placa .bq-et { font-size: 11px }
  body.bosque .bq-son { top: 11px }
  body.bosque .bq-nuevo { top: 76px; font-size: 9.5px; padding: 4px 7px 5px }
  body.bosque .bq-cuenta { margin-top: 4px }
  body.bosque .bq-cuenta button { font-size: 11.5px; padding: 7px 11px 8px }
}

@media (prefers-reduced-motion: reduce) {
  body.bosque .bq-t.big,
  body.bosque .bq-vivo,
  body.bosque .bq-soporte.late,
  body.bosque .bq-nuevo { animation: none }
  body.bosque .bq-vivo { opacity: 1 }
}

/* ===========================================================================
   PANTALLAS ANGOSTAS — van AL FINAL a propósito.
   Estaban más arriba que las reglas normales de .bq-rot/.bq-val y, a igual peso,
   en CSS gana la última: nunca se aplicaban. El rótulo seguía en 13 px en un
   teléfono de 360 px, que es donde justamente hacía falta achicarlo.
   =========================================================================== */
/* pantallas ANGOSTAS (no bajas): se achica el contenido de las cápsulas para que
   las tres sigan entrando en un solo renglón. Sin esto, en un teléfono de 360 px
   la fila se partiría en dos y el menú perdería una franja de alto. */
@media (max-width: 400px) {
  body.bosque .bq-stats { gap: 4px }
  body.bosque .bq-stat { padding: 3px 3px 4px }
  body.bosque .bq-ico { width: 26px; height: 26px }
  body.bosque .bq-ico.tk { width: 30px }
  body.bosque .bq-ico.trz { width: 30px }
  body.bosque .bq-rot { font-size: 11.5px; letter-spacing: 0 }
  body.bosque .bq-val { font-size: 26px }
  body.bosque .bq-val.trz { font-size: 18px }
  body.bosque .bq-frag-pie { font-size: 7.5px }
}
/* MUY angostas: el ícono se apila ARRIBA del texto. Con el ícono al lado, "TICKETS"
   no entra en un tercio de 340 px por más que se achique la letra; apilado, el texto
   se queda con todo el ancho de la cápsula y las tres siguen en una sola fila. */
@media (max-width: 344px) {
  body.bosque .bq-rot { font-size: 10.5px }
  body.bosque .bq-val { font-size: 23px }
  /* En pantallas de 320 px la cápsula de trozos mide ~98 px y el contenido ~76: no
     entran "TROZOS" + el contador + la regla. Ahí se simplifica a la misma forma que
     las otras dos y la regla se esconde. Se pierde la explicación en el teléfono más
     chico del parque, pero la alternativa es que el texto se salga del marco — y la
     regla se entiende una vez y ya. */
  body.bosque .bq-stat.frag { grid-template-areas: "rot" "ico val" }
  body.bosque .bq-val.trz { font-size: 20px }
  body.bosque .bq-frag-pie { display: none }
}

/* ---------------------------------------------------------------------------
   Elegir bioma al competir. SOLO ESTÉTICA: el mundo lo sigue generando el
   simulador con la semilla del torneo, así que elegir aquí no mueve ni una
   manzana. Se pinta sobre el mismo scrim que los otros avisos (.cg-scrim).
   Sin backdrop-filter a propósito — en el móvil cuesta cuadros.
   --------------------------------------------------------------------------- */
/* Aquí estaba el estilo del selector de mapas (.mapsel/.ms-*), retirado en 0118:
   el mapa es uno para todos y rota cada N partidas. */
