/* Mesa de juego (table.js). Prefijo tb-. Compone los tokens y componentes de style.css (docs/diseno.md).
   Excepción documentada: los colores del fondo de la mesa son propios del módulo (únicos hex del archivo):
   los tres del marrón de antes y los del gris de EDHPlay, que es el de por defecto. */
.tb-root { --tb-bg-1: #1c140d; --tb-bg-2: #120c08; --tb-bg-3: #0c0805; }

html.tb-html { overflow: hidden; height: 100%; }
body.tb-body { overflow: hidden; position: fixed; inset: 0; width: 100%; height: 100%; }
body.tb-body #app { height: 100%; overflow: hidden; }
body.tb-dragging, body.tb-dragging * { cursor: grabbing !important; }
body.tb-mode .tb-root { cursor: crosshair; }
.tb-root { position: fixed; inset: 0; display: flex; flex-direction: column; color: var(--text); font-size: var(--fs-3); user-select: none; -webkit-user-select: none; overflow: clip;
  /* `clip` y no `hidden`: la mano asoma por debajo del borde a propósito, y con `hidden` la mesa entera
     queda como caja con scroll y el navegador la corre unos píxeles sola (la vida y el turno se iban fuera de pantalla). */
  background-color: var(--tb-bg-2);
  background-image: linear-gradient(rgba(255,255,255,.02) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,.02) 1px, transparent 1px), radial-gradient(120% 80% at 50% 110%, var(--tb-bg-1) 0%, var(--tb-bg-2) 55%, var(--tb-bg-3) 100%);
  background-size: 20px 20px, 20px 20px, 100% 100%; }
/* Fondo de mesa de Arena (Preferencias). Es la textura de móvil del set, que el juego guarda ya horneada
   con su luz: la mesa entera, con las dos mitades y los dos escudos (tools/mtga-piezas/mesas.mjs).
   Va con una veladura negra encima —lo único que no sale del juego— porque estas mesas están pintadas
   para verse en perspectiva y con la luz de la escena, y a pantalla completa le comen el contraste a las
   cartas. Con el fondo puesto se va la cuadrícula: la mesa ya tiene su propio dibujo. */
.tb-root.tb-conmat { background-image: linear-gradient(rgba(0,0,0,.42), rgba(0,0,0,.42)), var(--tb-mat, none);
  background-size: cover, cover; background-position: center, center; background-repeat: no-repeat, no-repeat; }
/* el casillero de cada jugador es un panel opaco y taparía la mesa: con fondo puesto queda apenas
   oscurecido, así el dibujo pasa y la carta sigue teniendo contra qué leerse */
.tb-root.tb-conmat .tb-other { background: color-mix(in srgb, var(--bg) 30%, transparent); }
.tb-root.tb-conmat .tb-mini-in { background-color: transparent; }
/* las mesas del tocón (madera y velas) ya son oscuras: van sin la veladura de las de Arena */
.tb-root.tb-conmat.tb-fondo-madera { background-image: var(--tb-mat, none); background-size: cover; background-position: center; }
/* El gris de EDHPlay (el de por defecto): medido en su mesa. Afuera #1a1b1f, cada casillero #23242a con una
   cuadrícula de 20 px apenas marcada (gris al 4 %). Las superficies de la mesa (pastillas, paneles, bordes)
   pasan al mismo gris frío, así no quedan manchas marrones encima; el texto y los acentos siguen iguales. */
.tb-root.tb-fondo-gris { --bg: #1a1b1f; --bg-2: #1e1f24; --panel: #23242a; --panel-2: #2a2b32; --panel-3: #34353d;
  --border: #33343c; --border-2: #45464f;
  background: var(--bg); }
.tb-root.tb-fondo-gris .tb-other, .tb-root.tb-fondo-gris:not(.tb-layout-quad) .tb-field-in {
  background-color: var(--panel);
  background-image: linear-gradient(rgba(180,180,180,.04) 1px, transparent 1px), linear-gradient(90deg, rgba(180,180,180,.04) 1px, transparent 1px);
  background-size: 20px 20px; }
.tb-root.tb-fondo-gris .tb-mini-in { background-color: transparent; }
/* Mi fondo de Preferencias, solo en MI casillero (o en mi campo grande en Fila y Lateral): los demás siguen
   viendo el gris. Misma veladura que las mesas de Arena, salvo la madera, que ya es oscura. Va a `cover`
   sobre el casillero, que es casi 2:1 como las mesas (las de Arena quedaron en 2:1, ver mesas.mjs). */
.tb-root .tb-other.tb-mimat, .tb-root .tb-field.tb-mimat .tb-field-in {
  background-image: linear-gradient(rgba(0,0,0,.42), rgba(0,0,0,.42)), var(--tb-mymat, none);
  background-size: cover, cover; background-position: center, center; background-repeat: no-repeat, no-repeat; }
.tb-root .tb-other.tb-mimat-madera, .tb-root .tb-field.tb-mimat-madera .tb-field-in { background-image: var(--tb-mymat, none); background-size: cover; }
.tb-root .tb-other.tb-mimat .tb-mini-in { background-color: transparent; }
.tb-root .tb-other.tb-mimat-tocon, .tb-root .tb-field.tb-mimat-tocon .tb-field-in {
  background-color: var(--tb-bg-2);
  background-image: linear-gradient(rgba(255,255,255,.02) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,.02) 1px, transparent 1px), radial-gradient(120% 80% at 50% 110%, var(--tb-bg-1) 0%, var(--tb-bg-2) 55%, var(--tb-bg-3) 100%);
  background-size: 20px 20px, 20px 20px, 100% 100%; }
/* el cartel de "X propone jugar toda la mesa sobre …", arriba al medio y por encima de los casilleros */
.tb-matask { position: absolute; top: 52px; left: 50%; transform: translateX(-50%); z-index: var(--z-menu); display: flex; align-items: center; gap: var(--s2);
  max-width: min(640px, calc(100% - 32px)); padding: var(--s2) var(--s2) var(--s2) var(--s4); border-radius: var(--r-pill); font-size: var(--fs-3); font-weight: 600; animation: drop var(--t-base) var(--ease); }
.tb-matask .btn { flex: none; }
.tb-ell { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tb-danger { color: color-mix(in srgb, var(--wine-2) 70%, white); }
.tb-num { display: inline-flex; align-items: center; justify-content: center; min-width: 18px; height: 18px; padding: 0 var(--s1); border-radius: var(--r-1); background: var(--panel-3); color: var(--text-2); font-size: var(--fs-1); font-weight: 700; font-family: var(--font-mono); flex: none; cursor: pointer; }
.tb-hover-btn { opacity: 0; transition: opacity var(--t-fast) var(--ease); }
.tb-hover-host:hover .tb-hover-btn, .tb-hover-btn:focus-visible { opacity: 1; }

/* ---- cartas ----
   Transform siempre compuesto con variables; nada de !important. Campo: escala en el lugar alrededor del punto
   --ox/--oy (desplazamiento desde el centro, lo calcula table.js hacia el borde más cercano) y rotación aparte,
   así una carta girada no salta al agrandarse. Mano y mulligan: elevación (--arc por posición, --lift al hover). */
.tb-card { position: relative; overflow: visible; aspect-ratio: 80 / 112; cursor: grab; --hs: 1; --lift: 0px; --arc: 0px; z-index: var(--z, 0); transform-origin: center;
  transform: translate(var(--ox, 0px), var(--oy, 0px)) scale(var(--hs)) translate(calc(-1 * var(--ox, 0px)), calc(-1 * var(--oy, 0px))) rotate(var(--rot, 0deg)); }
/* la que no puedo tocar (de otro jugador, o soy espectador): no se agarra, así que sin la mano de agarrar; toma el
   cursor de lo que la contiene (en una zona, el de abrir la lista). Su F/R tampoco se clickea. */
.tb-card.tb-ajena, .tb-card.tb-ajena .tb-pt-v { cursor: inherit; }
/* girada: como en MTG Arena, bastante más oscura y con el símbolo de girar encima */
.tb-card.tb-tapped { --rot: 45deg; filter: brightness(.58) saturate(.7); }
/* girada pero atacando (le sale una flecha, .tb-glow): sigue a todo color con su resplandor hasta que se corta la
   flecha, que es cuando el ataque se resolvió. Recién ahí se oscurece como cualquier girada. */
.tb-card.tb-tapped.tb-glow { filter: none; }
/* marca de girar: la flecha de MTG Arena. Contrarrota con --rot para leerse derecha. */
.tb-tapmark { position: absolute; top: 50%; left: 50%; width: 40%; max-width: 42px; aspect-ratio: 1; display: none; pointer-events: none; opacity: .92;
  background: center / contain no-repeat url(/mtga/textures-bucket-card-parts-iconspart/tapped-icon.png);
  transform: translate(-50%, -50%) rotate(calc(-1 * var(--rot, 0deg)));
  filter: drop-shadow(0 1px 3px rgba(0,0,0,.8)); }
.tb-card.tb-tapped > .tb-tapmark { display: block; }
.tb-coords > .tb-card { position: absolute; aspect-ratio: auto; width: var(--cw, 80px); height: calc(var(--cw, 80px) * 1.4); transition: left var(--t-base) var(--ease), top var(--t-base) var(--ease), transform var(--t-base) var(--ease), box-shadow var(--t-base) var(--ease), filter var(--t-base) var(--ease); }
.tb-hand > .tb-card, .tb-zone-top > .tb-card, .tb-ohand-fan > .tb-card, .tb-ghost > .tb-card { position: absolute; aspect-ratio: auto; }
.tb-zone-top > .tb-card { inset: auto; left: 0; top: 0; width: 100%; height: calc(var(--zw, 64px) * 1.4); }
/* mano y mulligan: elevación (--arc por posición en el abanico, --lift al hover) + rotación + escala desde la base */
.tb-hand > .tb-card, .tb-mull-hand > .tb-card { transform: translateY(calc(var(--lift) + var(--arc))) rotate(var(--rot, 0deg)) scale(var(--hs)); }
.tb-card-img { width: 100%; height: 100%; object-fit: cover; border-radius: inherit; display: block; pointer-events: none; }
.tb-card-ph { position: absolute; inset: 0; border-radius: inherit; background: var(--panel-2); border: 2px solid var(--tone, var(--wood)); display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; text-align: center; padding: var(--s1); overflow: hidden; color: var(--text); font-size: calc(var(--fs-1) - 1px); line-height: 1.15; pointer-events: none; }
.tb-card-ph b { font-size: var(--fs-1); } .tb-card-ph span { color: var(--text-2); font-size: calc(var(--fs-1) - 2px); max-height: 5em; overflow: hidden; } .tb-card-ph i { font-style: normal; font-weight: 800; font-size: var(--fs-1); }
.tb-card-cost { position: absolute; top: -15px; left: 50%; transform: translateX(-50%); display: none; pointer-events: none; background: color-mix(in srgb, var(--bg) 70%, transparent); border-radius: var(--r-pill); padding: 1px 3px; white-space: nowrap; }
.tb-card-tags { position: absolute; left: 2px; right: 2px; bottom: 2px; display: flex; flex-wrap: wrap; gap: 2px; pointer-events: none; }
/* fuerza y resistencia: la pastilla de MTG Arena, apoyada sobre la esquina de abajo a la derecha para no
   taparle la línea de tipo. Los dos números se clickean por separado: click suma,
   click derecho resta. Si los contadores +1/+1 o −1/−1 cambian el número, se tiñe y sale un ícono al lado. */
.tb-card-pt { position: absolute; right: 2px; bottom: 2px; display: none; align-items: center; gap: 2px; pointer-events: auto; z-index: 3; }
.tb-field-in > .tb-card > .tb-card-pt, .tb-layout-quad .tb-mini-in > .tb-card > .tb-card-pt { display: flex; }
.tb-pt-pill[hidden] { display: none; }
.tb-pt-pill { display: inline-flex; align-items: center; justify-content: center; gap: 1px;
  width: calc(var(--cw, 80px) * .30); height: calc(var(--cw, 80px) * .148);
  background: center / 100% 100% no-repeat url(/mtga/arena-frame/pt-c.png);
  filter: drop-shadow(0 1px 2px rgba(0,0,0,.6)); }
.tb-pt-v { border: 0; background: none; padding: 0 1px; color: var(--bg); font-size: calc(var(--cw, 80px) * .09); font-weight: 700; font-family: var(--font-carta); /* la Beleren, la misma del estilo Arena */ line-height: 1; cursor: pointer; transition: color var(--t-fast) var(--ease); }
.tb-pt-v:hover { color: var(--wood); }
.tb-pt-sep { font-style: normal; color: color-mix(in srgb, var(--bg) 60%, transparent); font-size: calc(var(--cw, 80px) * .075); font-weight: 700; }
.tb-pt-up .tb-pt-v { color: var(--forest); } .tb-pt-down .tb-pt-v { color: var(--wine); }
.tb-pt-from { width: calc(var(--cw, 80px) * .1); height: calc(var(--cw, 80px) * .1); flex: none; filter: drop-shadow(0 1px 2px rgba(0,0,0,.8)); }
.tb-pt-up .tb-pt-from { color: var(--forest-2); } .tb-pt-down .tb-pt-from { color: var(--wine-2); }
.tb-card-tags .chip { padding: 0 var(--s1); height: 16px; min-width: 16px; white-space: nowrap; }
.tb-chip-rev, .tb-chip-fd { background: var(--gold); color: var(--on-accent); }
.tb-chip-rev .icon, .tb-chip-fd .icon { width: 11px; height: 11px; }
.tb-chip-note { background: var(--panel-3); }
.tb-chip-poison { background: color-mix(in srgb, var(--forest-2) 55%, var(--bg)); } .tb-chip-energy { background: color-mix(in srgb, var(--u) 55%, var(--bg)); } .tb-chip-experience { background: color-mix(in srgb, var(--purple) 55%, var(--bg)); } .tb-chip-rad { background: color-mix(in srgb, var(--gold) 55%, var(--bg)); } .tb-chip-tickets { background: color-mix(in srgb, var(--ember) 55%, var(--bg)); }
/* ---- carta recortada estilo MTG Arena ----
   En el campo y en las miniaturas la carta se corta en la fila 424 de 680 (medido): entra la barra del
   nombre, el arte y la línea de tipo, y el marco impreso de la propia carta es el que la cierra. No
   dibujamos ningún marco: solo recortamos. El 1,8% de las cartas (sagas, clases, casos, split, planos,
   flip y batallas) tiene el arte en otro lado y va entera (lo decide HS.wholeCard, sin .tb-tile). */
.tb-tile { --tone: var(--c); --r-t: calc(var(--cw, 80px) * .0475); border-radius: var(--r-t); background: none; }
/* la cara es la que recorta: la imagen y el borde de abajo van adentro, la F/R y los contadores afuera */
.tb-card-face { position: absolute; inset: 0; border-radius: inherit; overflow: hidden; background: var(--card-black); }
.tb-coords > .tb-card.tb-tile { height: calc(var(--cw, 80px) * (var(--cut, 424) + 20) / 488); }
.tb-tile .tb-card-img { height: calc(var(--cw, 80px) * var(--cut, 424) / 488); object-position: 50% 0; border-radius: 0; }
/* el cierre de abajo son las últimas 20 filas de la MISMA imagen: el borde negro impreso, con sus esquinas
   redondeadas de verdad. Por eso la carta termina como una carta y no como un recorte. */
/* dos clases: `.card > img` de style.css pone display:block y le ganaría a un solo `.tb-card-edge` */
.tb-card .tb-card-edge { display: none; }
/* dos clases: le tiene que ganar a `.card > img { width:100%; height:100% }` de style.css */
.tb-tile .tb-card-edge { display: block; position: absolute; left: 0; right: 0; bottom: 0; width: 100%; height: calc(var(--cw, 80px) * 20 / 488); object-fit: cover; object-position: 50% 100%; pointer-events: none; border-radius: 0; }
/* la F/R y los contadores se apoyan sobre el borde de abajo, como en MTG Arena */
.tb-tile > .tb-card-pt { bottom: calc(var(--cw, 80px) * -.055); right: calc(var(--cw, 80px) * -.01); }
/* las habilidades y los contadores van como en la carta Arena (carril izquierdo y orbes a la derecha): ver
   el bloque .tb-arena, que tiene las reglas compartidas con :is(.tb-arena, .tb-tile) */
.tb-card-tags, .tb-tapmark { z-index: 2; }
/* fichas de criatura (tokens): la tapa un poco más redondeada, como en MTG Arena */
.tb-tile.tb-token { border-radius: calc(var(--cw, 80px) * .085) calc(var(--cw, 80px) * .085) var(--r-t) var(--r-t); }

/* ---- carta del campo ARMADA al estilo MTG Arena (preferencia "Estilo Arena") ----
   Arena no guarda la carta del campo como imagen: la arma en 3D con la malla BattlefieldPart_Cardbase_Default
   y la pinta con tablas de color, y el prefab Scaffold_BAT dice dónde va cada pieza. Acá está esa misma carta,
   con las mismas piezas, horneadas a PNG por tools/mtga-piezas/hornear.mjs y tools/mtga-piezas/pastillas.mjs:

     bat-placa-<color>.png  la banda ancha de color, entre el marco negro y el arte. Arena NO la tiñe: le
                           cambia la textura entera por la del color, y son fotos —una hoja con nervaduras
                           la verde, roca agrietada la roja, agua la azul— así que vienen con su color.
                           Dos colores: las dos placas, mezcladas con el mismo degradé que el hilo.
     bat-hilo.png          el hilo macizo pegado al arte (otra malla, la del marco del arte, con la textura
                           CDC_Pinline). Ésa sí es clara y con detalle: va como máscara y se tiñe con
                           PinlineColors. Es una U abierta arriba: por arriba lo tapa la barra del nombre.
     bat-borde-negro.png   el marco negro entero, con la textura CDC_Border y el hueco del arte. Va ENCIMA
                           del arte: es el que le da la forma y las esquinas a la carta. Es negro de verdad,
                           no teñido: su material es Mat_Card_Border_Black con _UseMainColor = 0 y la
                           textura CDC_Border es un gris plano de #171717. En Arena el color de la carta
                           NUNCA llega al marco de afuera: llega a la placa y al hilo, que son los de arriba.
     bat-barra.png         el plato claro del nombre, y bat-barra-filete.png el filete de color que lo
     bat-barra-filete.png  rodea: las dos submallas de BattlefieldPart_Titlebar_Default, que es la barra
                           DEL CAMPO (no la de la carta de mano). El nombre va en negro encima.
     pt-<color>.png        la pastilla de fuerza/resistencia, que el juego ya guarda pintada por color.
     roundedrectangle-raised.png  el azulejo de las insignias de habilidad (plato claro fijo, no el color
                           de la carta: así lo pinta el prefab BadgeViewWithIcon).
     glass-counter-<x>.png  los orbes de contador, ya pintados: azul suma, rojo resta, gris el resto.

   Las medidas NO están a ojo: salen de la malla y de los anclajes del prefab, que están en
   m_AnchoredPosition. Las imprime tools/mtga-piezas/hornear.mjs. De afuera para adentro:
   marco negro 0..3,86 % · placa 3,86..6,09 % · hilo 6,09..7,71 % · arte 7,71..92,29 % (y 18,02..88,32 %).
   Los porcentajes verticales miden contra el ALTO de la carta; los de margen, contra el ancho de su caja. */
.tb-arena { --r-t: calc(var(--cw, 80px) * .0476); border-radius: var(--r-t); background: var(--ar-base); overflow: visible;
  font-family: var(--font-carta);
  /* apoyada en la mesa, no flotando: la sombra de contacto del juego, medida en una captura */
  box-shadow: 0 calc(var(--cw, 80px) * .0114) calc(var(--cw, 80px) * .0295) var(--ar-sombra-tinta);
  /* la caja del texto del título, en fracciones del ancho de la carta. Vive acá y no repartida porque
     T.fitArenaName la lee de acá para saber cuánto le queda al nombre: una sola fuente. Sale del
     RectTransform "Battlefield Title - Toho" (sizeDelta 3,6 × 0,35, sin márgenes) sobre la caja de la
     carta, 4,2697773 × 3,7479377; el tamaño de letra, de su m_fontSize 2,6. */
  --ar-name-w: .843136; --ar-name-em: .060893;
  /* La línea de tipo del pie, en fracciones del ancho de la carta. La letra es la de la línea de tipo de
     Arena en proporción a su título: 2 contra 2,6 (m_fontSize de "Type Line" y de "TitleText Toho"), o sea
     .060893 × 2/2,6. El hueco es el de la barra, y con la pastilla de F/R al lado llega hasta donde ésta
     empieza (61,7133 %) menos el mismo aire que tiene a la izquierda (1,735 %). */
  --ar-type-em: .046841; --ar-type-w: .843136; --ar-type-w-pt: .521353; }
.tb-arena.tb-ar-conpt > .tb-ar-type { width: 52.1353%; }
.tb-coords > .tb-card.tb-arena { height: calc(var(--cw, 80px) * .87793); }
/* 1 · la placa de color, debajo de todo. Ya viene con la forma y con la foto del color, así que va de
   fondo y no como máscara. La de dos colores son las dos placas, la segunda entrando con el mismo degradé
   que el hilo: el color de vértice de la malla, cortado en x = ±0,25 de la caja de la carta, o sea del
   44,1449 % al 55,8551 % del ancho con el cruce en el medio. */
.tb-ar-plate { position: absolute; inset: 0; pointer-events: none;
  background: var(--ar-placa, url(/mtga/arena-frame/bat-placa-c.png)) 0 0 / 100% 100% no-repeat; }
.tb-ar-plate::after { content: ''; position: absolute; inset: 0;
  background: var(--ar-placa-2, none) 0 0 / 100% 100% no-repeat;
  -webkit-mask-image: linear-gradient(90deg, transparent 44.1449%, #000 55.8551%);
          mask-image: linear-gradient(90deg, transparent 44.1449%, #000 55.8551%); }
/* 2 · el arte. La imagen impresa es de 488×680 y su arte vive en x 38..450, y 76..378: se agranda a
   118,4466 % del ancho del hueco y se corre para que entre justo. El hueco quedó casi con la misma
   proporción que el arte impreso (0,7294 contra 0,7330), así que casi no se recorta nada. */
.tb-arena > .tb-card-face { inset: auto; left: 7.7094%; top: 18.0246%; width: 84.5812%; height: 70.2695%; border-radius: 0; background: #000; }
.tb-arena .tb-card-face .tb-card-img { position: absolute; left: 0; top: 0; width: 118.4466%; height: auto; max-width: none;
  margin-left: -9.2232%; margin-top: -18.6284%; object-fit: fill; border-radius: 0; }
.tb-arena .tb-card-edge { display: none; }   /* el marco negro de Arena ya cierra la carta */
/* 2b · el hilo, encima del arte (en el juego también va delante: su z es −0,05 contra −0,025 del arte) */
.tb-ar-hilo { position: absolute; inset: 0; pointer-events: none; z-index: 1;
  background: var(--ar-pin, var(--ar-pin-c));
  -webkit-mask: url(/mtga/arena-frame/bat-hilo.png) 0 0 / 100% 100% no-repeat;
          mask: url(/mtga/arena-frame/bat-hilo.png) 0 0 / 100% 100% no-repeat; }
/* 3 · el marco negro del juego, encima del arte */
.tb-ar-edge { position: absolute; inset: 0; pointer-events: none; z-index: 2;
  background: url(/mtga/arena-frame/bat-borde-negro.png) 0 0 / 100% 100% no-repeat; }
/* 4 · la barra del nombre, que son TRES capas. La malla del campo no es la de la carta de mano: es
   BattlefieldPart_Titlebar_Default, puesta en el anclaje "Anchor Point - Title" de Scaffold_BAT. Sus dos
   piezas llevan dos colores distintos: el FILETE de afuera el de PinlineColors (el mismo del hilo del
   marco, con el que sigue por los costados) y el PLATO de adentro el de TitleBarColors, que es claro.
   Los PNG traen el gris de la textura de Arena en el RGB y la silueta en el alfa, así que el color sale
   de multiplicar (background-blend-mode) y no de teñir por alfa: debajo de la barra está la placa de
   color de la carta, no negro, y teñir por alfa ahí daría cualquier cosa.
   El nombre va NEGRO sobre el plato, a la izquierda, y **sin el coste de maná**: en
   Bucket_Card.Parts.TitleContentPart la pieza "Battlefield Title - Toho" es la única sin hijo ManaCost.
   Medidas horneadas: filete x 3,320..96,680 % y 4,672..19,577 %; plato x 6,152..93,848 % y 7,675..16,574 %. */
.tb-ar-bar-pin { position: absolute; inset: 0; pointer-events: none; z-index: 3;
  background-image: url(/mtga/arena-frame/bat-barra-filete.png), var(--ar-pin, linear-gradient(90deg, var(--ar-pin-c), var(--ar-pin-c)));
  background-size: 100% 100%, 100% 100%; background-repeat: no-repeat, no-repeat;
  background-blend-mode: multiply, normal;
  -webkit-mask: url(/mtga/arena-frame/bat-barra-filete.png) 0 0 / 100% 100% no-repeat;
          mask: url(/mtga/arena-frame/bat-barra-filete.png) 0 0 / 100% 100% no-repeat; }
.tb-ar-bar { position: absolute; inset: 0; pointer-events: none; z-index: 3;
  background-image: url(/mtga/arena-frame/bat-barra.png);
  background-size: 100% 100%; background-repeat: no-repeat;
  background-color: var(--ar-bar, var(--ar-bar-c)); background-blend-mode: multiply;
  -webkit-mask: url(/mtga/arena-frame/bat-barra.png) 0 0 / 100% 100% no-repeat;
          mask: url(/mtga/arena-frame/bat-barra.png) 0 0 / 100% 100% no-repeat; }
/* la caja del texto: el RectTransform 3,6 × 0,35 centrado en el anclaje. Queda un pelo más alta que el
   plato y con 1,735 % de aire a cada lado. Arena corta sin puntos suspensivos (m_overflowMode = 3). */
/* Centrado a ojo, no por la caja: el plato tiene abajo un labio oscuro de 5 filas (de 80) que no se lee
   como plato, así que el centro visible queda 0,35 % de la carta más arriba que el de la caja; y la
   Beleren lleva casi todo el peso en las minúsculas, así que con la caja centrada el renglón se ve caído.
   Por eso la caja sube hasta el centro visible y el texto se levanta .08em más (padding-bottom .16em). */
.tb-ar-name { position: absolute; left: 7.843%; width: 84.314%; top: 7.12%; height: 9.339%; padding-bottom: .16em; box-sizing: border-box;
  display: flex; align-items: center; z-index: 3; pointer-events: none; overflow: hidden;
  font-family: var(--font-carta); font-weight: 700; font-size: calc(var(--cw, 80px) * var(--ar-name-em));
  line-height: 1; color: var(--ar-ink-titulo); white-space: nowrap; }
/* la línea de tipo, en el pie. Arena NO la dibuja en el campo (el prefab Scaffold_BAT tiene anclas de
   Title y de PT, y ninguna de TypeLine), pero acá va porque sin ella el pie de una carta sin fuerza ni
   resistencia —un Sol Ring, un conjuro— queda vacío. Va en la misma caja que el nombre, corrida hasta el
   pie: el plato de arriba empieza en 7,675 % y el de abajo en 85,095 %, así que la caja baja 77,42 %.
   Si al lado está la pastilla de F/R, el hueco se corta donde ésta empieza (la clase tb-ar-conpt). */
.tb-ar-type { position: absolute; left: 7.843%; width: 84.314%; top: 84.49%; height: 9.339%; padding-bottom: .16em; box-sizing: border-box;
  display: flex; align-items: center; z-index: 3; pointer-events: none; overflow: hidden;
  font-family: var(--font-carta); font-weight: 700; font-size: calc(var(--cw, 80px) * var(--ar-type-em));
  line-height: 1; color: var(--ar-ink-titulo); white-space: nowrap; }
/* 4b · el PIE, que es LA MISMA barra del nombre puesta abajo: el prefab Scaffold_BAT cuelga la misma malla
   en dos anclajes, "Anchor Point - Title" (y = +1,525) y "Anchor Point - PT" (y = −1,375). Por eso arriba y
   abajo se ven iguales. Tapa el travesaño de abajo del hilo del arte, que por eso parecía sobrar.
   Horneadas: filete x 3,320..96,680 % y 81,980..96,997 %; plato x 6,152..93,848 % y 85,095..93,993 %. */
.tb-ar-pie-pin { position: absolute; inset: 0; pointer-events: none; z-index: 3;
  background-image: url(/mtga/arena-frame/bat-pie-filete.png), var(--ar-pin, linear-gradient(90deg, var(--ar-pin-c), var(--ar-pin-c)));
  background-size: 100% 100%, 100% 100%; background-repeat: no-repeat, no-repeat;
  background-blend-mode: multiply, normal;
  -webkit-mask: url(/mtga/arena-frame/bat-pie-filete.png) 0 0 / 100% 100% no-repeat;
          mask: url(/mtga/arena-frame/bat-pie-filete.png) 0 0 / 100% 100% no-repeat; }
.tb-ar-pie { position: absolute; inset: 0; pointer-events: none; z-index: 3;
  background-image: url(/mtga/arena-frame/bat-pie.png);
  background-size: 100% 100%; background-repeat: no-repeat;
  background-color: var(--ar-bar, var(--ar-bar-c)); background-blend-mode: multiply;
  -webkit-mask: url(/mtga/arena-frame/bat-pie.png) 0 0 / 100% 100% no-repeat;
          mask: url(/mtga/arena-frame/bat-pie.png) 0 0 / 100% 100% no-repeat; }
/* 5 · fuerza y resistencia: sobre el pie, a la derecha, en el anclaje del prefab
   (Anchor Point - PT, x 58,314 %..99,534 %, y 77,774 %..101,254 %: asoma un poco por abajo).
   En el juego va centrada —el CDCSmartAnchor recalcula esa X y en la copia ya armada de
   Bucket_Browser.CardVFX_1 el clon tiene lp.x = 0—, pero acá va a la derecha porque Gus la quiere ahí.
   La pastilla sí es la del campo: la malla Card_PowerToughness (la que hornea pastillas.mjs es la de la
   carta de mano) con el MISMO atlas CDC_TitleTypePT que el plato del pie. Es una máscara clara, así que
   lleva el mismo TitleBarColors y no hay una imagen por color. Tamaño = la malla × la escala 1,1 del
   anclaje: 37,8207 % × 18,4917 % del ANCHO de la carta.
   Los números en Beleren, y en azul o rojo si los contadores los cambiaron (Text_LightGreyBlueRed). */
.tb-arena > .tb-card-pt { right: .466%; left: auto; top: auto; bottom: -1.254%; z-index: 4; gap: 0; }
:is(.tb-arena, .tb-tile) .tb-pt-pill { width: calc(var(--cw, 80px) * .378207); height: calc(var(--cw, 80px) * .184917);
  background-image: url(/mtga/arena-frame/bat-pt.png); background-size: 100% 100%;
  background-color: var(--ar-bar, var(--ar-bar-c)); background-blend-mode: multiply;
  -webkit-mask: url(/mtga/arena-frame/bat-pt.png) 0 0 / 100% 100% no-repeat;
          mask: url(/mtga/arena-frame/bat-pt.png) 0 0 / 100% 100% no-repeat; filter: none; }
/* la letra, un 25 % más grande que la del juego (.098): Gus la quería más legible sin agrandar la pastilla. Con
   números de dos cifras (10/10) vuelve a la del juego para que entre (.tb-pt-largo, lo pone T.fillCard). */
:is(.tb-arena, .tb-tile) .tb-pt-v { font-family: var(--font-carta); font-size: calc(var(--cw, 80px) * .1225); font-weight: 700; color: var(--ar-ink); padding: 0 2%; }
:is(.tb-arena, .tb-tile) .tb-pt-largo .tb-pt-v { font-size: calc(var(--cw, 80px) * .098); }
/* negrita suave: la Beleren ya viene en su peso más grueso, así que un borde del mismo color engrosa el trazo */
:is(.tb-arena, .tb-tile) .tb-pt-v, :is(.tb-arena, .tb-tile) .tb-pt-sep { -webkit-text-stroke: .05em currentColor; }
:is(.tb-arena, .tb-tile) .tb-pt-sep { font-family: var(--font-carta); font-size: calc(var(--cw, 80px) * .105); color: color-mix(in srgb, var(--ar-ink) 55%, transparent); }
:is(.tb-arena, .tb-tile) .tb-pt-up .tb-pt-v { color: var(--ar-sube); } :is(.tb-arena, .tb-tile) .tb-pt-down .tb-pt-v { color: var(--ar-baja); }
/* el hover va después y con la misma cuenta de clases, para que le gane al azul y al rojo de arriba */
:is(.tb-arena, .tb-tile) .tb-pt-v:hover, :is(.tb-arena, .tb-tile) .tb-pt-up .tb-pt-v:hover, :is(.tb-arena, .tb-tile) .tb-pt-down .tb-pt-v:hover { color: var(--wood); }
:is(.tb-arena, .tb-tile) .tb-pt-from { display: none; }   /* el color del número ya dice que lo cambiaron */
/* 6 · insignias. Las de habilidad van en el ESCUDO del juego (malla Card_Keyword_Badge, de la carta de campo
   ya armada de Bucket_Browser.CardVFX_1), montado sobre el borde del pie y asomando por fuera, como en el
   juego. Son dos piezas: el aro, con el color de PinlineColors, y el plato, con el de TitleBarColors.
   Del prefab: Icons - BAT → IconRoot → KeywordIconRoot (y = −1,4) → KeywordLeft (x = −1,8) / KeywordRight
   (x = +1,8) → Backing con escala 0,75. O sea 23,4267 % × 27,3768 % del ancho de la carta, con los centros
   en x 7,8432 % y 92,1568 % e y 90,1814 % del alto.
   Arena usa las dos puntas y nada más; acá, cuando hay más de una habilidad, siguen en fila hacia adentro
   desde la punta izquierda y, si no entran antes de la pastilla de F/R, se apilan hacia arriba
   (`flex-wrap: wrap-reverse`): no se esconden ni se achican.
   Anclaje Counters: las que llevan número, en columna arriba a la derecha, sobre los orbes de vidrio que
   Arena guarda ya pintados (azul suma, rojo resta, gris el resto). */
:is(.tb-arena, .tb-tile) > .tb-card-tags { inset: auto; right: auto; width: auto;
  /* en el carril de la IZQUIERDA, espejo del de los contadores: el pie ahora lleva la línea de tipo, así
     que las habilidades no pueden seguir montadas sobre el borde de abajo. Arrancan pegadas al pie y
     crecen hacia arriba; cuando no entran, la fila siguiente va hacia adentro. */
  left: -5.59%; top: 17.474%; bottom: 19.5%;
  flex-direction: column; flex-wrap: wrap; align-items: center; align-content: flex-start;
  justify-content: flex-end; gap: calc(var(--cw, 80px) * .012); z-index: 4; }
:is(.tb-arena, .tb-tile) > .tb-ar-ctrs { position: absolute; inset: auto; right: -5.59%; top: 17.474%; bottom: 2.482%; display: flex;
  flex-direction: column; flex-wrap: wrap-reverse; align-items: center; align-content: flex-start;
  justify-content: flex-start; gap: calc(var(--cw, 80px) * .012); z-index: 4; pointer-events: none; }
.tb-ar-badge { display: inline-flex; align-items: center; justify-content: center; position: relative;
  flex: none;
  width: calc(var(--cw, 80px) * .152); height: calc(var(--cw, 80px) * .152); padding: 0; border: 0; border-radius: 0;
  color: #fff; font-family: var(--font-carta); font-weight: 700; font-size: calc(var(--cw, 80px) * .072);
  line-height: 1; letter-spacing: -.02em; text-shadow: 0 1px 2px rgba(0,0,0,.8);
  background: center / contain no-repeat var(--ar-badge, url(/mtga/counters/glass-counter-grey.png)); }
/* el azulejo del juego (prefab BadgeViewWithIcon): un cuadradito de esquinas redondeadas con el ícono
   oscuro adentro. El plato NO lleva el color de la carta: es #E7E7E7 si la habilidad es de la carta y
   #8ACEFF si es ganada con un contador. Arena en el campo usa un escudo más grande (la malla
   Card_Keyword_Badge, horneada en bat-escudo-*.png), pero acá va el azulejo porque se lee mejor. */
.tb-ar-badge.tb-ar-tile { width: calc(var(--cw, 80px) * .152); height: calc(var(--cw, 80px) * .1438);
  background: var(--ar-badge-ganada); color: var(--ar-ink); text-shadow: none;
  -webkit-mask: url(/mtga/textures-bucket-ability-badgeview/roundedrectangle-raised.png) center / contain no-repeat;
          mask: url(/mtga/textures-bucket-ability-badgeview/roundedrectangle-raised.png) center / contain no-repeat; }
.tb-ar-badge.tb-ar-tile.tb-ar-propia { background: var(--ar-badge-propia); }
.tb-ar-badge.tb-ar-gris { color: var(--ar-ink); text-shadow: none; }   /* el orbe gris es claro: tinta oscura */
.tb-ar-badge .icon, .tb-ar-badge .micon { width: calc(var(--cw, 80px) * .105); height: calc(var(--cw, 80px) * .105); flex: none; }
.tb-ar-badge .icon + span, .tb-ar-badge .micon + span { margin-left: calc(var(--cw, 80px) * .006); }
/* carta sin imagen (fichas hechas a mano): el texto ocupa solo el hueco del arte, el marco y la barra quedan */
.tb-arena > .tb-card-ph { inset: auto; left: 7.7094%; top: 18.0246%; width: 84.5812%; height: 70.2695%;
  border: 0; background: color-mix(in srgb, var(--bg) 80%, transparent); border-radius: 0; font-family: var(--font); }
/* el símbolo de girar: en el campo de Arena es grande, 2,672 de las 4,2698 unidades de ancho de la carta
   (sprite tapped_icon de 1,67 por la escala 1,6 del prefab TappedIcon). En los otros dos estilos queda el
   tamaño de siempre, que es el que va con una carta vertical. */
.tb-arena > .tb-tapmark { width: 62.6%; max-width: none; }
.tb-arena > .tb-card-ph b { display: none; }   /* el nombre ya está en la barra */
.tb-arena > .tb-card-ph .tb-ph-tipo { display: none; }   /* y la línea de tipo, en el pie */
/* la F/R del texto sobra solo donde está la pastilla; en los casilleros de Fila y Lateral no hay pastilla */
.tb-field-in > .tb-arena > .tb-card-ph i, .tb-layout-quad .tb-mini-in > .tb-arena > .tb-card-ph i { display: none; }

/* al pasar el mouse la carta no se agranda: se marca con un contorno claro y la carta entera se lee en la
   vista previa del costado (el dorado queda para la carta seleccionada, así no se confunden) */
body:not(.tb-dragging) .tb-field-in > .tb-card:is(:hover, .tb-hov) { --hs: 1.04; z-index: calc(var(--z-float) * 10); box-shadow: 0 0 0 2px color-mix(in srgb, var(--text) 70%, transparent), var(--sh-3); }
body:not(.tb-dragging) .tb-mini-in > .tb-card:is(:hover, .tb-hov) { --hs: 1.3; z-index: calc(var(--z-float) * 10); box-shadow: 0 0 0 1px color-mix(in srgb, var(--text) 70%, transparent), var(--sh-2); }
.tb-mini-in:has(> .tb-card:is(:hover, .tb-hov)), .tb-mini:has(.tb-card:is(:hover, .tb-hov)), .tb-other:has(.tb-card:is(:hover, .tb-hov)) { overflow: visible; }
/* mano: en reposo asoma la mitad de arriba (el resto no se lee igual); al hover sube un poco, no del todo */
.tb-hand > .tb-card { bottom: calc(var(--ch, 126px) * -0.5); transform-origin: bottom center; transition: left var(--t-base) var(--ease), transform var(--t-base) var(--ease), box-shadow var(--t-base) var(--ease); }
.tb-hand > .tb-card .tb-card-cost, .tb-mull-hand > .tb-card .tb-card-cost { display: block; }
body:not(.tb-dragging) .tb-hand > .tb-card:hover { --lift: -30px; --hs: 1.06; z-index: calc(var(--z-float) * 10); }
/* zona de hit anclada abajo mientras la carta está levantada: cubre el hueco que dejó (con --lift 0 mide 0), así el hover no parpadea ni arranca un rectángulo de selección */
.tb-hand > .tb-card::after, .tb-mull-hand > .tb-card::after { content: ''; position: absolute; left: 0; right: 0; top: 100%; height: calc(-1 * var(--lift)); }
.tb-card.tb-selected, .tb-card.tb-selected:hover { box-shadow: 0 0 0 2px var(--gold), 0 0 12px color-mix(in srgb, var(--gold) 50%, transparent); }
/* arrastre como EDHPlay: la carta se va con el puntero y no queda un fantasma en su lugar */
.tb-card.tb-ghosted { visibility: hidden; }
.tb-card.tb-attached { filter: saturate(.9); }
.tb-card.tb-arrow-target, .tb-card.tb-arrow-target:hover { box-shadow: 0 0 0 3px var(--gold), 0 0 18px color-mix(in srgb, var(--gold) 60%, transparent); }
[data-player].tb-arrow-target { box-shadow: 0 0 0 2px var(--gold), 0 0 14px color-mix(in srgb, var(--gold) 55%, transparent); }
.tb-field.tb-arrow-target { box-shadow: none; }
.tb-field.tb-arrow-target .tb-field-in { box-shadow: inset 0 0 0 2px var(--gold), 0 0 14px color-mix(in srgb, var(--gold) 55%, transparent); }
.tb-hidden { cursor: default; }
.tb-dropover { box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--gold) 60%, transparent); background-color: color-mix(in srgb, var(--gold) 6%, transparent); }
.tb-field.tb-dropover, .tb-mini.tb-dropover { box-shadow: none; background: none; }
.tb-field.tb-dropover .tb-field-in, .tb-mini.tb-dropover .tb-mini-in { background-color: color-mix(in srgb, var(--gold) 8%, transparent); }
.tb-marquee { position: absolute; border: 1px solid var(--gold); background: color-mix(in srgb, var(--gold) 20%, transparent); z-index: var(--z-float); pointer-events: none; }
.tb-ghost { position: fixed; left: 0; top: 0; z-index: var(--z-drag); pointer-events: none; }
.tb-ghost { will-change: transform; }
/* la carta que se arrastra va levantada: un poco más grande y con sombra, como si estuviera en la mano */
.tb-ghost > .tb-card { box-shadow: var(--sh-3), 0 12px 28px rgba(0,0,0,.55); scale: 1.05; }
.tb-ghost-n { position: absolute; top: -10px; right: -10px; background: var(--gold); color: var(--on-accent); font-weight: 800; font-size: var(--fs-2); min-width: 22px; height: 22px; border-radius: var(--r-pill); display: flex; align-items: center; justify-content: center; }

/* ---- lienzo lógico (1000×560) ----
   El lienzo ocupa TODO su contenedor (nada de marco ni franjas negras a los costados): las posiciones son
   porcentajes de los dos ejes y solo el tamaño de la carta usa una escala uniforme (min de las dos), así
   una carta nunca se deforma ni se sale por abajo. Lo calcula T.fit en table.js. */
.tb-coords { position: absolute; inset: 0; overflow: hidden; isolation: isolate; border-radius: var(--r-3); }
.tb-field-in { border-radius: 0; }

/* ---- fila / columna de otros jugadores ---- */
.tb-others { flex: none; display: flex; gap: var(--s2); padding: var(--s2); height: clamp(170px, 26vh, 300px); overflow-x: auto; overflow-y: hidden; }
.tb-other { flex: 1 1 0; min-width: 190px; max-width: 50vw; min-height: 0; display: flex; flex-direction: column; gap: 3px; padding: var(--s1) var(--s2) var(--s2); position: relative; --pc: var(--gold); transition: box-shadow var(--t-base) var(--ease), border-color var(--t-base) var(--ease); }
.tb-others.tb-solo > .tb-other { max-width: none; } /* un solo rival: el mini ocupa toda la fila */
.tb-other.tb-active { border-color: var(--gold); box-shadow: 0 0 0 1px var(--gold), 0 0 14px color-mix(in srgb, var(--gold) 30%, transparent); }
.tb-other.tb-conceded { opacity: .55; } .tb-other.tb-offline .tb-other-name { color: var(--muted); }
.tb-other-head { display: flex; align-items: center; gap: 2px var(--s1); flex-wrap: wrap; overflow: hidden; font-size: var(--fs-2); min-height: 22px; flex: none; }
.tb-other-name { background: none; border: 0; padding: 0 2px; font-weight: 700; font-size: var(--fs-3); color: var(--text); cursor: pointer; max-width: 140px; min-width: 56px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; border-radius: var(--r-1); }
.tb-other-name:hover { color: var(--gold-2); }
.tb-other-name::before { content: ''; display: inline-block; width: 7px; height: 7px; border-radius: var(--r-pill); background: var(--pc); margin-right: 5px; vertical-align: middle; }
.tb-crown { color: var(--gold); display: inline-flex; }
.tb-other-life { display: inline-flex; align-items: center; gap: 2px; margin-left: 2px; }
.tb-other-life b { font-size: var(--fs-5); min-width: 24px; text-align: center; }
.tb-pcounters, .tb-pmana { display: inline-flex; gap: 3px; flex-wrap: nowrap; }
.tb-pcounters .chip { white-space: nowrap; }
.tb-manachip { display: inline-flex; align-items: center; gap: 2px; font-size: var(--fs-1); font-weight: 700; } .tb-manachip .pip { width: 11px; height: 11px; }
.tb-other-head .badge { flex: none; }
.tb-mini { width: 100%; flex: 1; min-height: 0; position: relative; overflow: hidden; }
.tb-mini-in { background-color: color-mix(in srgb, var(--bg) 40%, transparent); }
.tb-active .tb-mini-in { box-shadow: inset 0 0 0 1px var(--gold), inset 0 0 24px color-mix(in srgb, var(--gold) 10%, transparent); }
.tb-other-zones { display: flex; align-items: flex-end; gap: var(--s2); height: 42px; flex: none; padding: 0 2px 1px; }
.tb-ozone { position: relative; width: 28px; height: 39px; border-radius: var(--r-1); background: var(--panel-2); flex: none; }
.tb-ozone img { width: 100%; height: 100%; object-fit: cover; border-radius: var(--r-1); }
.tb-ozone-top { position: absolute; inset: 0; } .tb-ozone-top > .tb-card { position: absolute; inset: 0; width: 100%; height: 100%; aspect-ratio: auto; }
.tb-ozone-n { position: absolute; right: -6px; bottom: -6px; min-width: 16px; height: 16px; padding: 0 var(--s1); border-radius: var(--r-pill); background: var(--panel-3); border: 1px solid var(--border-2); color: var(--text); font-size: calc(var(--fs-1) - 1px); font-weight: 700; display: flex; align-items: center; justify-content: center; }
.tb-ogy, .tb-oex { cursor: pointer; } .tb-ogy:hover, .tb-oex:hover { box-shadow: 0 0 0 1px var(--gold); }
.tb-ohand { width: 62px; background: none; isolation: isolate; } /* contexto propio: el contador apila sobre los dorsos sin competir con el resto */
.tb-ohand .tb-ozone-n { z-index: var(--z-float); } /* encima de cualquier dorso (--z por carta) */
.tb-ohand-fan { position: relative; width: 100%; height: 100%; }
.tb-ohand-fan > .tb-card { width: var(--ofw, 22px); height: calc(var(--ofw, 22px) * 1.4); margin-left: calc(var(--ofw, 22px) / -2); bottom: 3px; transform-origin: bottom center; cursor: default; }
.tb-ohand-fan > .tb-card .tb-card-tags, .tb-ohand-fan > .tb-card .tb-card-ph { display: none; }
.tb-ocmd { width: auto; display: flex; gap: 3px; background: none; }
.tb-ocmd > .tb-card { position: relative; width: 28px; height: 39px; aspect-ratio: auto; }
.tb-ocmd > .tb-card .tb-card-tags { display: none; }
/* en las miniaturas las etiquetas se achican para que entren. La carta estilo Arena no: sus insignias ya se
   miden contra el --cw del casillero, que de por sí es más chico, y achicarlas de nuevo las dejaba desparejas
   (la fila de abajo encogida y la columna de la derecha no). */
.tb-mini-in > .tb-card:not(.tb-arena):not(.tb-tile) .tb-card-tags { transform: scale(.7); transform-origin: left bottom; }
.tb-react { position: absolute; top: 40%; left: 50%; transform: translate(-50%, -50%); font-size: calc(var(--fs-8) * 2); line-height: 1; pointer-events: none; z-index: var(--z-float); filter: drop-shadow(0 4px 10px rgba(0,0,0,.6)); }
.tb-main > .tb-react { top: 30%; font-size: calc(var(--fs-8) * 3); }
.tb-react.tb-pop { animation: tb-pop var(--t-slow) var(--ease); }
@keyframes tb-pop { from { transform: translate(-50%, -50%) scale(.3); opacity: 0; } to { transform: translate(-50%, -50%) scale(1); opacity: 1; } }

/* Distribución en grilla: la pantalla partida en casilleros iguales, uno por jugador, y cada casillero es una mesa
   entera (vida con sus contadores arriba a la izquierda, nombre al centro, zonas abajo a la derecha). El mío va abajo
   a la izquierda y adentro viven mi mano y mis zonas de verdad, así los cuatro se ven igual y el mío se juega.
   Lo que queda flotando sobre todo el lienzo —turno, menú, pila, maná— se apoya sobre las esquinas de los
   casilleros, como en EDHPlay, en vez de reservarse una franja: reservarla se comía hasta el 22 % del ancho. */
.tb-layout-quad { display: grid; grid-template-columns: repeat(var(--qc, 2), minmax(0, 1fr)); grid-auto-rows: minmax(0, 1fr);
  gap: var(--s1); padding: var(--s1); }
.tb-layout-quad .tb-others { display: contents; }
.tb-layout-quad .tb-other { flex: none; min-width: 0; max-width: none; padding: 0; }
.tb-layout-quad.tb-q3 .tb-others > .tb-other:last-child { grid-column: span 2; } /* tres jugadores: el último toma la fila entera, sin huecos */
.tb-layout-quad .tb-main { position: fixed; inset: 0; z-index: calc(var(--z-raise) + 2); pointer-events: none; } /* +2: por encima de las zonas de cada casillero (z-raise + 1), si no el panel del cementerio quedaba detrás de las zonas del rival */
.tb-layout-quad .tb-main > *:not(.tb-handwrap) { pointer-events: auto; }
.tb-layout-quad .tb-field, .tb-layout-quad .tb-name, .tb-layout-quad .tb-life { display: none; } /* no hay campo grande: cada uno tiene su casillero */
.tb-layout-quad .tb-mini { position: absolute; inset: 0; }
.tb-layout-quad .tb-mini-in { border-radius: var(--r-3); }
/* cabecera del casillero: no ocupa lugar, flota sobre el lienzo */
.tb-qhead { position: absolute; top: var(--s2); left: var(--s2); right: var(--s2); z-index: var(--z-raise); display: block; overflow: visible; pointer-events: none; }
.tb-qhead > * { pointer-events: auto; }
.tb-qlife { position: absolute; top: 0; left: 0; display: flex; flex-direction: column; align-items: center; gap: 2px; }
.tb-qlife .tb-life-main { gap: var(--s1); padding: 0 var(--s2); }
.tb-qlife .tb-life-more { position: absolute; top: calc(100% + 2px); left: 0; }
.tb-qname { position: absolute; top: 0; left: 50%; transform: translateX(-50%); display: flex; align-items: center; gap: var(--s2); max-width: 66%; }
.tb-name-pill { display: inline-flex; align-items: center; gap: var(--s1); max-width: 100%; padding: 0 var(--s2); }
.tb-qname .tb-other-name { max-width: 180px; }
.tb-qname .badge, .tb-qname .chip { flex: none; }
/* zonas ajenas abajo a la derecha, del tamaño de una mesa de verdad */
.tb-layout-quad .tb-other-zones { position: absolute; right: var(--s2); bottom: var(--s2); z-index: var(--z-raise); height: 52px; padding: 0; }
.tb-layout-quad .tb-ozone { width: 37px; height: 52px; }
.tb-layout-quad .tb-ohand { width: 92px; --ofw: 30px; }
.tb-layout-quad .tb-ocmd > .tb-card { width: 37px; height: 52px; }
.tb-layout-quad .tb-hasmine > .tb-other-zones { display: none; } /* en mi casillero ese lugar lo ocupan mis zonas de verdad */
/* la mano de cada rival: la misma franja que la mía (T.layoutOtherHand), de dorso y sin arrastre. Se recorta
   en el borde de abajo del casillero para que no se meta en el de abajo; arriba y a los costados, no, por
   el arco y el giro de las cartas. */
.tb-ohandwrap { clip-path: inset(-200px -60px 0 -60px); }
.tb-ohand-cards > .tb-card { cursor: default; }
.tb-ohand-n { pointer-events: none; }
.tb-layout-quad.tb-spect .tb-zones { display: none; } /* de espectador no hay casillero propio: las zonas ya se ven en cada casillero */

/* distribución en fila: el campo grande abajo y los otros en una franja arriba. Cuando el turno es de un rival,
   su casillero se lleva el ancho y la franja entera crece (`.tb-foe`), así se le ve la mesa casi tan grande como
   la propia; al pasar el turno se acomoda solo, con transición. El tamaño de carta lo reajusta T.roMini. */
.tb-layout-row .tb-other { transition: flex-grow var(--t-slow) var(--ease), border-color var(--t-base) var(--ease), box-shadow var(--t-base) var(--ease); }
.tb-layout-row .tb-others { transition: height var(--t-slow) var(--ease); }
.tb-layout-row.tb-foe .tb-others { height: clamp(240px, 42vh, 420px); }
.tb-layout-row.tb-foe .tb-other.tb-active { flex-grow: 2.4; }

/* distribución lateral: los otros en columna a la derecha *//* distribución lateral: los otros en columna a la derecha */
.tb-layout-sidebar { flex-direction: row; }
.tb-layout-sidebar .tb-others { order: 2; flex-direction: column; width: 290px; height: auto; min-height: 0; overflow-x: hidden; overflow-y: auto; }
.tb-layout-sidebar .tb-other { flex: none; min-width: 0; max-width: none; }
.tb-layout-sidebar .tb-mini { flex: none; aspect-ratio: 1000 / 560; }
.tb-layout-sidebar .tb-main { min-width: 0; }

/* ---- zona principal ---- */
.tb-main { flex: 1; position: relative; min-height: 0; min-width: 0; }
.tb-field { position: absolute; inset: 0; } /* el campo es toda la zona principal; la vida, el turno y el nombre flotan encima */
.tb-field-in { background: none; transition: box-shadow var(--t-base) var(--ease); }
.tb-field-in::before { content: ''; position: absolute; inset: 0; pointer-events: none; background: radial-gradient(60% 60% at 50% 100%, color-mix(in srgb, var(--pc, var(--gold)) 10%, transparent), transparent); }
.tb-field.tb-active .tb-field-in { box-shadow: inset 0 0 0 2px var(--gold); }
.tb-banner, .tb-modehint { position: absolute; top: calc(52px + var(--tb-ph-drop, 0px)); left: 50%; transform: translateX(-50%); z-index: var(--z-raise); height: 28px; padding: 0 var(--s3); font-weight: 600; font-size: var(--fs-2); white-space: nowrap; }
.tb-banner { border-color: var(--ember); color: var(--ember-2); }
.tb-modehint { border-color: var(--gold); color: var(--gold-2); }

/* vida (arriba a la izquierda). Las tres cajas de arriba van con esquina recta, no redondeada: se ve más sobrio. */
.tb-life-main, .tb-turn-pill, .tb-name-btn { border-radius: var(--r-2); }
.tb-life { position: absolute; top: var(--s2); left: var(--s3); z-index: var(--z-raise); display: flex; flex-direction: column; align-items: center; gap: 2px; --pc: var(--gold); }
.tb-life-main { gap: var(--s1); padding: 0 var(--s2) 0 var(--s2); }
.tb-life.tb-active .tb-life-main { border-color: var(--gold); }
.tb-lifeval { background: none; border: 0; font-size: var(--fs-7); font-weight: 800; min-width: 48px; text-align: center; padding: 0 2px; color: var(--text); letter-spacing: -.02em; border-radius: var(--r-1); }
.tb-lifeval:hover { color: var(--gold-2); }
.tb-lifeinput { width: 64px; font-size: var(--fs-6); font-weight: 800; text-align: center; background: var(--bg-2); border: 1px solid var(--gold); border-radius: var(--r-2); color: var(--text); padding: 2px var(--s1); }
.tb-life-more { display: flex; flex-direction: column; gap: 2px; min-width: 248px; padding: var(--s2) var(--s3); animation: pop var(--t-fast) var(--ease); }
.tb-life-row { display: flex; align-items: center; gap: var(--s2); min-height: 26px; font-size: var(--fs-2); color: var(--text-2); }
.tb-life-row > span:first-child { flex: 1; min-width: 0; display: flex; align-items: center; gap: var(--s2); }
.tb-life-row b { min-width: 22px; text-align: right; color: var(--text); font-size: var(--fs-3); font-variant-numeric: tabular-nums; }
.tb-life-name .icon { color: var(--muted); }
.tb-life-btns { display: flex; gap: 2px; flex: none; }
.tb-life-sep { height: 1px; background: var(--border); margin: var(--s2) calc(-1 * var(--s3)); }
.tb-life-cap { margin-top: var(--s1); }
/* La píldora "♥ +6" de EDHPlay (medida en su mesa: negra, redonda, corazón y número del mismo rojo, suba o baje):
   flota a la derecha de la vida sin correr nada (en la cabecera de Fila empujaría un renglón y achicaría el
   casillero). T.lifeFxEnd la apaga con .tb-out. Se rearma en cada render: nada de animación de entrada. */
.tb-life-main, .tb-other-life { position: relative; }
.tb-lifefx { position: absolute; left: calc(100% + var(--s2)); top: 50%; transform: translateY(-50%); z-index: var(--z-raise);
  display: inline-flex; align-items: center; gap: 3px; height: 18px; padding: 0 var(--s2) 0 6px; border-radius: var(--r-pill);
  background: var(--bg); box-shadow: var(--sh-1); color: var(--rojo-vida);
  font-size: var(--fs-3); font-weight: 800; font-variant-numeric: tabular-nums; line-height: 1; white-space: nowrap;
  pointer-events: none; transition: opacity var(--t-slow) var(--ease); }
.tb-lifefx .icon { width: 12px; height: 12px; }
.tb-lifefx.tb-lifefx-l { left: auto; right: calc(var(--lfx-r, 100%) + var(--s2)); } /* no entraba a la derecha (T.fitLifeFx) */
.tb-lifefx.tb-out { opacity: 0; }

/* nombre enfocado (arriba al centro) */
.tb-name { position: absolute; top: var(--s2); left: 50%; transform: translateX(-50%); z-index: var(--z-raise); display: flex; align-items: center; gap: var(--s2); --pc: var(--gold); }
.tb-name-btn { cursor: pointer; color: var(--text); }
.tb-name-btn:hover { background: color-mix(in srgb, var(--panel-3) 88%, transparent); }
.tb-name-btn .dot { background: var(--pc); }
.tb-mullback { position: absolute; top: 52px; left: 50%; transform: translateX(-50%); z-index: var(--z-raise); }

/* fases del turno (las cinco de EDHPlay, la actual abierta en sus pasos). Cuelgan a la derecha del nombre sin correrlo
   del centro: el de arriba en fila y lateral, el del casillero del que tiene el turno en la grilla. Si ahí no entran,
   T.layoutPhases las pasa abajo del nombre (.tb-ph-below) y, si tampoco, deja solo el paso actual (.tb-ph-tight). */
.tb-phases { position: absolute; top: 0; left: calc(100% + var(--s2)); border-radius: var(--r-2); white-space: nowrap; }
.tb-phases.tb-ph-below { top: calc(100% + var(--s1)); left: 50%; transform: translateX(-50%); }
.tb-phases button { min-height: 28px; padding: 0 var(--s2); font-size: var(--fs-2); }
.tb-phases .tb-ph-g { min-width: 28px; padding: 0 var(--s1); }
.tb-ph-cur { display: inline-flex; align-items: center; gap: 3px; padding-left: var(--s1); }
.tb-ph-cur > .icon { color: var(--pc); }
.tb-phases button.on, .tb-phases.tb-ro button { cursor: default; }
.tb-phases.tb-ro button:hover:not(.on) { background: transparent; color: var(--text-2); }
.tb-phases.tb-ph-tight .tb-ph-cur button:not(.on) { display: none; }

/* turno y menú (arriba a la derecha) */
.tb-topright { position: absolute; top: var(--s2); right: var(--s3); z-index: var(--z-raise); display: flex; flex-direction: column; align-items: flex-end; gap: var(--s2); }
.tb-turn { display: flex; flex-direction: column; align-items: center; gap: 2px; }
.tb-turn-pill { flex-direction: column; justify-content: center; gap: 0; height: auto; min-height: 36px; padding: var(--s1) var(--s3); text-align: center; }
.tb-turn-n { font-size: var(--fs-1); font-weight: 800; letter-spacing: .1em; line-height: 1.2; }
.tb-turn-num { font-size: var(--fs-6); font-weight: 800; line-height: 1.1; }
.tb-turn.tb-mine .tb-turn-pill { cursor: pointer; }
.tb-turn.tb-mine .tb-turn-pill:hover { background: color-mix(in srgb, var(--forest) 30%, var(--panel-2)); }
.tb-turn-who { font-size: var(--fs-1); color: var(--muted); max-width: 140px; } .tb-turn.tb-mine .tb-turn-who { color: var(--forest-2); font-weight: 700; }
.tb-turn-timer { font-family: var(--font-mono); font-size: var(--fs-1); color: var(--text-2); } .tb-turn-timer.tb-over { color: var(--wine-2); font-weight: 700; }

/* ---- pila: el contenedor flotante de EDHPlay ----
   Vive en .tb-root (no en .tb-main): se arrastra por toda la pantalla en las tres distribuciones. left/top reales:
   layoutStack (donde lo dejó cada uno, en localStorage). Encima de la grilla (.tb-main de la grilla va a +2) y debajo
   de las flechas, los menús, la vista previa y el fantasma del arrastre. Las cartas van enteras, del ancho del asa
   (--sw, EDHPlay usa 147 px), encimadas: top de cada una y alto de la lista, también de layoutStack. */
.tb-stack { position: absolute; left: 50%; top: 30%; z-index: calc(var(--z-raise) + 3); --sw: clamp(140px, 10.5vw, 200px); --cw: var(--sw);
  width: var(--sw); display: flex; flex-direction: column; gap: var(--s1); }
.tb-stack-head { display: flex; align-items: center; gap: var(--s1); height: 32px; padding: 0 var(--s1); border-radius: var(--r-2); cursor: grab; touch-action: none; }
.tb-stack-head b { flex: 1; min-width: 0; text-align: center; font-size: var(--fs-3); }
.tb-stack-grip { display: inline-flex; padding: 0 var(--s1); color: var(--text-2); }
.tb-stack.tb-dropover .tb-stack-head { border-color: var(--gold); }
.tb-stack-list { position: relative; }
/* --sz y no --z: --z se hereda y la carta de adentro (z-index: var(--z)) tapaba el nombre y los botones */
.tb-stack-item { position: absolute; left: 0; width: 100%; z-index: var(--sz, 0); animation: pop var(--t-base) var(--ease); }
.tb-stack-item > .tb-card { width: 100%; height: calc(var(--sw) * 1.4); aspect-ratio: auto; z-index: 0; }
/* la de otro también se saca arrastrando (resolverla es de todos); el espectador no */
.tb-stack-item > .tb-card.tb-ajena { cursor: grab; }
.tb-spect .tb-stack-item > .tb-card { cursor: inherit; }
/* en la pila se lee la carta: sin contadores ni marca (esos van en la carta de la mesa), con su F/R de solo lectura */
.tb-stack-item > .tb-card > :is(.tb-card-tags, .tb-mark) { display: none; }
.tb-stack-item > .tb-card > .tb-card-pt { display: flex; }
.tb-stack-item .tb-pt-v { cursor: inherit; }
/* quien la puso, arriba a la izquierda (el "Player 1" de EDHPlay) */
.tb-stack-who { position: absolute; top: 2px; left: 2px; max-width: calc(100% - 4px); z-index: 5; padding: 0 var(--s1); border-radius: var(--r-1);
  background: color-mix(in srgb, var(--bg) 64%, transparent); color: var(--text); font-size: var(--fs-1); line-height: 16px; pointer-events: none; }
/* ↗ ⧉ ✓: cuelgan de la carta de arriba, asomando por debajo */
.tb-stack-btns { position: absolute; top: calc(100% - 6px); left: 50%; transform: translateX(-50%); z-index: 6; display: flex; gap: 2px; padding: 2px; border-radius: var(--r-2); }

/* ---- resplandor de MTG Arena ----
   La silueta de la carta con su degradé, difuminada, que el juego pone detrás de la carta cuando está
   pasando algo con ella: `cardshape-opaque-orange-a01.png` (Textures_Bucket_Card.Highlight). Se usa en dos
   momentos: la carta de ARRIBA de la pila (la que se resuelve) y la carta de la que SALE una flecha (fijada o
   mientras se elige el destino). Va en un ::before con z-index negativo: dentro del contexto de apilado de la carta se pinta
   después del fondo pero antes de los hijos, así que se ve solo lo que asoma por afuera. */
.tb-card.tb-glow::before, .tb-stack-item.tb-top > .tb-card::before {
  content: ''; position: absolute; inset: calc(var(--cw, 80px) * -.09); z-index: -1; pointer-events: none;
  background: url(/mtga/textures-bucket-card-highlight/cardshape-opaque-orange-a01.png) 0 0 / 100% 100% no-repeat; }

/* ---- ping: la carta señalada con un click (como EDHPlay) ----
   Dos aros que salen de la carta y se desvanecen, con los números de EDHPlay (dos, .8 s, el segundo apenas después,
   de .9 a 2 y a 1,7 veces). El aro es el contorno de carta de MTG Arena, `card-ttp-frame-outline-grad-gray.png`
   (Textures_Bucket_Card.Highlight): como máscara, teñido con el color del que señaló (--pc) y con el degradé gris
   del propio dibujo encima (multiply). El inset pone la línea media del aro del dibujo (x 90–423, y 30–481 de 512)
   sobre el borde de la carta. Capa fija (T.showPing en table.js): nada la recorta. Sin animaciones queda quieto. */
.tb-pings { position: fixed; inset: 0; pointer-events: none; z-index: var(--z-arrows); }
.tb-ping { position: absolute; pointer-events: none; rotate: var(--rot, 0deg); }
.tb-ping > i { position: absolute; inset: -6.65% -26.73% -6.87% -27.03%;
  --aro: url(/mtga/textures-bucket-card-highlight/card-ttp-frame-outline-grad-gray.png);
  background: var(--aro) 0 0 / 100% 100% no-repeat, var(--pc); background-blend-mode: multiply;
  -webkit-mask: var(--aro) 0 0 / 100% 100% no-repeat; mask: var(--aro) 0 0 / 100% 100% no-repeat;
  animation: tb-ping-1 var(--t-lento) var(--ease) both; }
.tb-ping > i + i { animation-name: tb-ping-2; animation-delay: var(--t-fast); }
@keyframes tb-ping-1 { from { scale: .9; opacity: 1; } to { scale: 2; opacity: 0; } }
@keyframes tb-ping-2 { from { scale: .9; opacity: .8; } to { scale: 1.7; opacity: 0; } }

/* maná (columna abajo a la izquierda, encima del chat) */
.tb-mana { position: absolute; left: var(--s3); bottom: 68px; z-index: var(--z-raise); display: flex; flex-direction: column; gap: 2px; padding: var(--s1); }
.tb-mana-row { display: flex; align-items: center; gap: 3px; height: 22px; padding: 0 2px; border-radius: var(--r-1); }
.tb-mana-row .pip { width: 16px; height: 16px; font-size: calc(var(--fs-1) - 2px); }
.tb-mana-row b { min-width: 16px; text-align: center; font-size: var(--fs-2); }
.tb-mana-row.tb-zero b { color: var(--muted); }
.tb-mana-clear { margin-top: 2px; }
/* sumar/restar con el click: click izquierdo +1, derecho −1 (maná, contadores, daño de comandante, impuesto) */
.tb-step { cursor: pointer; transition: filter var(--t-fast) var(--ease); }
.tb-step:hover { filter: brightness(1.3); }
.tb-step:active { filter: brightness(.8); }

/* mano (abajo al centro) */
.tb-handwrap { position: absolute; left: 300px; right: 340px; bottom: 0; z-index: var(--z-raise); pointer-events: none; } /* left/right reales: layoutHandWrap (maná y zonas) */
.tb-hand { pointer-events: none; position: relative; width: 100%; height: calc(var(--ch, 126px) * 0.5 + 34px); border-radius: var(--r-3); transition: background-color var(--t-fast) var(--ease); } /* asoma la mitad de la carta; --ch lo pone layoutHand */
.tb-hand > .tb-card { pointer-events: auto; }
body.tb-dragging .tb-hand { pointer-events: auto; }
.tb-hand.tb-collapsed { height: 28px; }
.tb-hand.tb-collapsed > .tb-card { display: none; }
.tb-handtoggle { pointer-events: auto; position: absolute; right: 0; bottom: var(--s2); white-space: nowrap; z-index: var(--z-raise); height: 28px; padding: 0 var(--s2) 0 var(--s1); border-radius: var(--r-pill); font-size: var(--fs-2); color: var(--text-2); gap: 2px; }
.tb-handtoggle:hover { color: var(--text); }
.tb-handwrap.tb-revealed .tb-handtoggle { border-color: var(--gold); color: var(--gold-2); box-shadow: var(--sh-2), var(--glow-gold); }
.tb-hand.tb-dropover { background-color: color-mix(in srgb, var(--gold) 6%, transparent); box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--gold) 40%, transparent); }

/* zonas (abajo a la derecha) */
/* Biblioteca, cementerio, exilio y comandante: del mismo tamaño que las cartas del campo (--zw lo pone
   T.layoutField para las mías y T.fit para las de cada rival), con el nombre ARRIBA y la carta asomando por
   abajo, cortada como en EDHPlay: se ve el 52 % de arriba. Como en EDHPlay van pegadas entre sí (2 px) y
   contra el borde derecho del casillero: antes llevaban 12 px entre una y otra y se comían media franja. */
.tb-zones { position: absolute; right: var(--s2); bottom: 0; z-index: calc(var(--z-raise) + 1); display: flex; align-items: flex-end; gap: 2px; }
.tb-zone { display: flex; flex-direction: column-reverse; align-items: center; gap: 3px; cursor: pointer; }
.tb-zone-box { position: relative; width: var(--zw, 64px); height: calc(var(--zw, 64px) * 1.4 * .52); overflow: hidden;
  border-radius: var(--r-card) var(--r-card) 0 0; }
.tb-zone-box > img { width: 100%; height: calc(var(--zw, 64px) * 1.4); object-fit: cover; object-position: 50% 0; border-radius: var(--r-card) var(--r-card) 0 0; box-shadow: var(--sh-1); }
.tb-zlib.tb-revealed .tb-zone-box > img { display: none; }
.tb-zone-top { position: absolute; left: 0; top: 0; right: 0; height: calc(var(--zw, 64px) * 1.4); }
.tb-zone-empty { position: absolute; inset: 0; border-radius: var(--r-card) var(--r-card) 0 0; background: var(--panel-2); display: flex; align-items: flex-start; justify-content: center; padding-top: 14%; color: var(--muted); }
.tb-zone-empty .icon { width: 20px; height: 20px; }
/* el nombre no pasa del ancho de la carta: con cartas chicas se achica en vez de pisar a la de al lado */
.tb-zone-label { font-size: min(var(--fs-3), calc(var(--zw, 64px) * .12)); color: var(--text-2); font-weight: 600; white-space: nowrap; max-width: var(--zw, 64px); overflow: hidden; text-overflow: ellipsis; }
.tb-zone:hover .tb-zone-label { color: var(--text); }
.tb-zone:hover .tb-zone-box { box-shadow: 0 0 0 1px color-mix(in srgb, var(--gold) 50%, transparent); }
.tb-zone.tb-dropover { background: none; box-shadow: none; }
.tb-zone.tb-dropover .tb-zone-box { box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--gold) 60%, transparent), 0 0 12px color-mix(in srgb, var(--gold) 30%, transparent); }
/* comandante: las cartas apiladas en un solo lugar, cada una corrida un 14 % de la carta (como en EDHPlay
   con los compañeros), y no una al lado de la otra. La de arriba es la última; al pasar el mouse sube. */
.tb-zcmd { --paso: calc(var(--zw, 64px) * .14); }
.tb-cmd-box { width: calc(var(--zw, 64px) + (var(--k, 1) - 1) * var(--paso)); }
.tb-cmd-slot { position: absolute; top: 0; left: calc(var(--i, 0) * var(--paso)); width: var(--zw, 64px); height: calc(var(--zw, 64px) * 1.4); z-index: calc(var(--i, 0) + 1); }
/* el hueco del que salió va debajo de los que están: arriba queda la carta que se toca (su click derecho no abre nada) */
.tb-cmd-slot.tb-away { z-index: 0; }
.tb-cmd-slot:hover { z-index: var(--z-raise); }
.tb-cmd-slot > .tb-zone-top > .tb-card { inset: auto; left: 0; top: 0; width: 100%; height: calc(var(--zw, 64px) * 1.4); }
/* el comandante que salió deja su frente apagado encima de la corona: una imagen quieta (T.fillCmdGhost), no una
   carta, así que no se gira con la del campo ni recibe clicks. El radio, la sombra y el fondo los da .card. */
.tb-cmd-ghost { position: absolute; left: 0; top: 0; width: 100%; height: calc(var(--zw, 64px) * 1.4); opacity: .4; pointer-events: none; }
/* el impuesto, arriba del nombre "Comandante": una moneda por comandante. Antes iba montado sobre la carta y
   el recorte de la zona lo cortaba por la mitad. */
.tb-taxes { display: flex; align-items: center; justify-content: center; gap: var(--s2); min-height: 16px; }
.tb-tax { display: inline-flex; align-items: center; gap: 3px; font-size: var(--fs-2); font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; }
.tb-tax .icon { width: 13px; height: 13px; color: var(--gold); }
.tb-tax.tb-step { cursor: pointer; } .tb-tax.tb-step:hover { color: var(--gold-2); }
.tb-zsideboard .tb-zone-box { display: flex; align-items: flex-start; justify-content: center; padding-top: 14%; color: var(--muted); }

/* panel de zona (cementerio / exilio / sideboard / biblioteca): flotante, debajo del bloque de turno y encima de las zonas;
   top y bottom reales: layoutZonePanel (se corta arriba de mis zonas si están abajo de él) */
.tb-zonepanel { position: absolute; top: 140px; right: var(--s3); bottom: var(--s3); width: 320px; z-index: calc(var(--z-raise) + 2); display: flex; flex-direction: column; overflow: hidden; animation: pop var(--t-fast) var(--ease); }
.tb-zp-head { display: flex; align-items: center; justify-content: space-between; gap: var(--s2); padding: var(--s2) var(--s2) var(--s2) var(--s3); border-bottom: 1px solid var(--border); font-size: var(--fs-3); flex: none; }
.tb-zp-head b { display: inline-flex; align-items: center; gap: var(--s2); min-width: 0; overflow: hidden; }
.tb-zp-head .muted { font-weight: 500; }
/* filtros del panel (tipo, coste convertido y texto), como los del cementerio de EDHPlay */
.tb-zp-filters { display: flex; flex-wrap: wrap; gap: var(--s2); padding: var(--s2) var(--s2) 0; flex: none; }
.tb-zp-filters .select { height: 28px; font-size: var(--fs-2); flex: 1 1 110px; min-width: 0; padding: 0 var(--s5) 0 var(--s2); }
.tb-zp-filters .input { height: 28px; font-size: var(--fs-2); flex: 1 1 100%; }
.tb-zp-filters .btn-icon-sm { flex: none; }
.tb-zp-grid { flex: 1; overflow: auto; padding: var(--s2); display: grid; grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); gap: var(--s2); align-content: start; }
.tb-zp-grid > .tb-card { width: 100%; }
.tb-zp-grid > .empty { grid-column: 1 / -1; }
/* panel de la biblioteca, como el de EDHPlay: la carta grande arriba (su alto lo pone layoutZonePanel, --tb-pv-h, para
   que queden al menos cuatro filas), los filtros, la lista de nombres con su ⋮ y el pie Cerrar / Cerrar y barajar */
.tb-lib-pv { flex: none; display: flex; justify-content: center; padding: var(--s2) var(--s3) 0; }
.tb-lib-pv:empty { display: none; }
.tb-lib-pv .card, .tb-lib-pv .card-placeholder { height: var(--tb-pv-h, 240px); width: auto; max-width: 100%; aspect-ratio: 488 / 680; cursor: zoom-in; }
.tb-lib-pv .card > img { width: 100%; height: 100%; }
.tb-lib-list { flex: 1; min-height: 0; overflow: auto; margin-top: var(--s2); border-top: 1px solid var(--border); }
.tb-lib-list > .empty { padding: var(--s5) var(--s3); }
.tb-lib-row { display: flex; align-items: center; gap: var(--s2); height: 40px; padding: 0 var(--s2) 0 var(--s3); font-size: var(--fs-3); color: var(--text); cursor: grab; user-select: none; transition: background var(--t-fast) var(--ease); }
.tb-lib-row.tb-land { background: var(--panel-3); } /* EDHPlay aclara las filas de tierra */
.tb-lib-row:hover, .tb-lib-row.tb-hov { background: color-mix(in srgb, var(--gold) 12%, var(--panel-3)); }
.tb-lib-row.tb-ghosted { opacity: .4; }
.tb-lib-name { flex: 1; min-width: 0; }
.tb-lib-list[data-src='libview-ro'] .tb-lib-row { cursor: default; }
/* dónde cae lo que se arrastra sobre la lista: una raya dorada entre filas */
.tb-lib-row.tb-ins { box-shadow: inset 0 2px 0 var(--gold); }
.tb-lib-row.tb-ins-after { box-shadow: inset 0 -2px 0 var(--gold); }
.tb-lib-rand { display: grid; gap: var(--s1); padding: var(--s2) var(--s2) 0; flex: none; }
.tb-lib-foot { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s2); padding: var(--s2); border-top: 1px solid var(--border); flex: none; }
.tb-lib-foot:has(> :only-child) { grid-template-columns: 1fr; }
/* la biblioteca que me revelaron: el nombre de la zona en dorado, se abre con un click */
.tb-zlib.tb-libshown .tb-zone-label { color: var(--gold-2); }
.tb-olib.tb-libshown { cursor: pointer; }

/* chat (abajo a la izquierda) */
/* chat: hijo de .tb-root después del mulligan y del menú lateral, así C funciona con el overlay encima */
.tb-chatbtn { position: absolute; left: var(--s3); bottom: var(--s3); z-index: var(--z-menu); width: 44px; height: 44px; }
.tb-chatbtn .icon { width: 20px; height: 20px; }
.tb-unread { position: absolute; top: -4px; right: -4px; min-width: 18px; height: 18px; border-radius: var(--r-pill); background: var(--wine-2); color: var(--text); font-size: var(--fs-1); font-weight: 800; display: flex; align-items: center; justify-content: center; padding: 0 5px; }
.tb-chat { position: absolute; left: var(--s3); bottom: 64px; /* left real: layoutChat (a la derecha del maná) */ width: 340px; height: 400px; max-height: calc(100% - 80px); z-index: var(--z-menu); display: flex; flex-direction: column; animation: pop var(--t-fast) var(--ease); }
.tb-chat-tabs { display: flex; align-items: center; gap: var(--s2); padding: var(--s2); border-bottom: 1px solid var(--border); }
.tb-chat-tabs .seg { flex: 1; }
.tb-chat-list { flex: 1; overflow: auto; padding: var(--s2) var(--s3); display: flex; flex-direction: column; gap: var(--s1); font-size: var(--fs-2); user-select: text; -webkit-user-select: text; }
.tb-msg { line-height: 1.35; word-break: break-word; } .tb-msg-time { color: var(--muted); font-size: var(--fs-1); margin-right: 5px; font-family: var(--font-mono); }
.tb-msg b { color: var(--pc, var(--gold)); }
.tb-msg-sys { color: var(--text-2); font-style: italic; }
.tb-chat-form { display: flex; gap: var(--s2); padding: var(--s2); border-top: 1px solid var(--border); }

/* menú lateral */
.tb-side { position: absolute; top: var(--s2); right: var(--s2); bottom: var(--s2); width: 280px; z-index: var(--z-menu); padding: var(--s2) var(--s3) var(--s3); overflow: auto; display: flex; flex-direction: column; gap: 2px; animation: tb-slide var(--t-base) var(--ease); }
@keyframes tb-slide { from { transform: translateX(16px); opacity: 0; } }
.tb-side-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--s2); font-size: var(--fs-5); }
.tb-side .caps { margin: var(--s3) 0 var(--s1); }
.tb-side-item { display: flex; align-items: center; gap: var(--s2); width: 100%; text-align: left; background: none; border: 0; border-radius: var(--r-2); padding: var(--s2) var(--s2); color: var(--text); font-size: var(--fs-3); font-weight: 600; transition: background var(--t-fast) var(--ease); }
.tb-side-item .icon { color: var(--text-2); }
.tb-side-item:hover { background: var(--panel-3); }
.tb-side-item.tb-danger .icon { color: inherit; }
.tb-side-react { display: flex; gap: var(--s2); padding: var(--s1) var(--s2); }
.tb-side-emoji { font-size: var(--fs-7); background: var(--panel-2); border: 1px solid var(--border); border-radius: var(--r-2); width: 44px; height: 40px; transition: background var(--t-fast) var(--ease); }
.tb-side-emoji:hover { background: var(--panel-3); }

/* mulligan */
.tb-mull { position: absolute; inset: 0; z-index: var(--z-menu); background: color-mix(in srgb, var(--bg) 92%, transparent); backdrop-filter: blur(2px); -webkit-backdrop-filter: blur(2px); display: flex; align-items: center; justify-content: center; overflow: auto; animation: fade var(--t-base) var(--ease); }
.tb-mull-in { text-align: center; padding: var(--s4); width: 100%; max-width: 100%; }
.tb-mull-in h1 { font-family: var(--font-display); font-size: var(--fs-8); font-weight: 600; letter-spacing: .06em; text-transform: uppercase; margin-bottom: 2px; }
.tb-mull-sub { color: var(--text-2); font-size: var(--fs-2); }
.tb-mull-hand { display: flex; justify-content: center; align-items: flex-end; padding: 100px var(--s5) var(--s6); min-height: 300px; } /* arriba: arco 30 + lift 24 + escala 1.08 + pip del coste (~16), para no pisar el título ni el subtítulo */
.tb-mull-hand > .tb-card { flex: none; transform-origin: bottom center; transition: transform var(--t-base) var(--ease), box-shadow var(--t-base) var(--ease); }
.tb-mull-hand > .tb-card:hover { --lift: -24px; --hs: 1.08; z-index: calc(var(--z-float) * 10); }
.tb-mull-hand > .tb-card.tb-picked, .tb-mull-hand > .tb-card.tb-picked:hover { --lift: -30px; box-shadow: 0 0 0 3px var(--ember), var(--sh-3); }
.tb-mull-bottom .tb-mull-hand > .tb-card { cursor: pointer; }
.tb-mull-actions { display: flex; justify-content: center; align-items: center; gap: var(--s3); flex-wrap: wrap; }
.tb-mull-msg { width: 100%; font-size: var(--fs-5); font-weight: 700; margin-bottom: var(--s2); }
.tb-mull-wait { margin-top: var(--s5); display: flex; flex-wrap: wrap; gap: var(--s2); justify-content: center; font-size: var(--fs-2); color: var(--text-2); }
.tb-mull-p { display: inline-flex; align-items: center; gap: var(--s2); }
.tb-mull-p b { color: var(--text); }
.tb-mull-menu { position: absolute; top: var(--s2); right: var(--s3); }

/* flechas de objetivo, al estilo MTG Arena: resplandor + halo que corre + cuerpo con degradé + hilo claro */
.tb-arrows { position: fixed; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: var(--z-arrows); }
.tb-arrows path { fill: none; stroke-linecap: round; }
.tb-arrow-glow { stroke-width: 15; opacity: .3; filter: url(#tb-arrow-blur); }
.tb-arrow-halo { stroke: var(--arrow-2); stroke-width: 9; opacity: .45; stroke-dasharray: 24 40; filter: url(#tb-arrow-blur); animation: tb-arrow-flow 1.1s linear infinite; }
.tb-arrow-line { stroke-width: 6; opacity: .95; animation: tb-arrow-pulse 1.6s ease-in-out infinite; }
.tb-arrow-core { stroke: var(--arrow-core); stroke-width: 1.8; opacity: .85; }
/* la punta de la flecha: la textura del juego usada como máscara sobre un rectángulo teñido, y latiendo al mismo
   ritmo que el cuerpo. Vive en el <defs>, que no se rehace en cada repintado, así el latido no se corta. */
.tb-arrows .tb-arrow-headglow { fill: var(--arrow-2); opacity: .65; }
.tb-arrows .tb-arrow-headfill { fill: var(--arrow-3); animation: tb-arrow-pulse 1.6s ease-in-out infinite; }
@keyframes tb-arrow-flow { to { stroke-dashoffset: -64; } }
@keyframes tb-arrow-pulse { 0%, 100% { opacity: .78; } 50% { opacity: 1; } }
/* la flecha propia se puede cortar: el puntero es una tijera y el click la borra */
.tb-arrow-mine { pointer-events: stroke; cursor: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='26' height='26' viewBox='0 0 24 24' fill='none' stroke-linecap='round'%3E%3Cg stroke='%23000' stroke-opacity='.6' stroke-width='4.5'%3E%3Ccircle cx='6.5' cy='6.5' r='2.8'/%3E%3Ccircle cx='6.5' cy='17.5' r='2.8'/%3E%3Cpath d='M20 4 9 15M14.5 14.5 20 20M9 9 12 12'/%3E%3C/g%3E%3Cg stroke='%23fff' stroke-width='2'%3E%3Ccircle cx='6.5' cy='6.5' r='2.8'/%3E%3Ccircle cx='6.5' cy='17.5' r='2.8'/%3E%3Cpath d='M20 4 9 15M14.5 14.5 20 20M9 9 12 12'/%3E%3C/g%3E%3C/svg%3E") 6 6, pointer; }
.tb-arrow-mine:hover { stroke: var(--wine-2); }
.tb-arrow-new { animation: tb-draw var(--t-slow) var(--ease), tb-arrow-pulse 1.6s ease-in-out infinite; }
@keyframes tb-draw { from { stroke-dashoffset: var(--len); } to { stroke-dashoffset: 0; } }

/* menú contextual */
.tb-menu { position: fixed; z-index: var(--z-menu); min-width: 200px; padding: var(--s1); animation: pop var(--t-fast) var(--ease); transform-origin: var(--origin, top left); user-select: none; }
.tb-menu-item { display: flex; align-items: center; gap: var(--s2); padding: 6px var(--s2); border-radius: var(--r-1); cursor: pointer; font-size: var(--fs-3); color: var(--text); white-space: nowrap; transition: background var(--t-fast) var(--ease); }
.tb-menu-item:hover { background: var(--panel-3); }
.tb-menu-item > .icon { width: 16px; height: 16px; color: var(--text-2); flex: none; }
.tb-menu-ico { width: 16px; height: 16px; flex: none; }
.tb-menu-label { flex: 1; }
.tb-menu-item kbd { height: 18px; min-width: 18px; font-size: var(--fs-1); padding: 0 var(--s1); color: var(--text-2); }
.tb-menu-arrow { color: var(--muted); }
.tb-menu-arrow .icon { width: 12px; height: 12px; }
.tb-menu-item.tb-disabled { opacity: .4; cursor: default; } .tb-menu-item.tb-disabled:hover { background: none; }
.tb-menu-item.tb-on .tb-menu-ico { color: var(--forest-2); }
.tb-menu-sep { height: 1px; background: var(--border); margin: var(--s1) var(--s2); }
.tb-menu-title { font-size: var(--fs-1); color: var(--muted); padding: var(--s1) var(--s2); text-transform: uppercase; letter-spacing: .06em; }

/* vista previa (HS.prefs.sidePreview, prendida por defecto): fija a un costado, centrada y grande.
   El lado lo decide table.js: siempre el opuesto a la carta, partiendo la mesa al medio. */
.tb-preview { position: fixed; left: var(--s4); right: auto; top: 50%; transform: translateY(-50%); z-index: calc(var(--z-float) * 10 + 1); width: clamp(220px, 25vw, 400px); max-height: calc(100vh - var(--s5)); pointer-events: none; display: flex; flex-direction: column; gap: var(--s2); padding: var(--s2); animation: fade var(--t-fast) var(--ease); }
.tb-preview.tb-preview-right { left: auto; right: var(--s4); }
.tb-preview .card { width: 100%; aspect-ratio: 80 / 112; }
.tb-preview .card > img { width: 100%; height: 100%; }
.tb-pv-ph { width: 100%; font-size: var(--fs-4); flex-direction: column; gap: var(--s2); } .tb-pv-ph span { font-weight: 400; } .tb-pv-ph p { font-weight: 400; font-size: var(--fs-2); margin: 0; }
.tb-pv-info { display: flex; flex-wrap: wrap; gap: var(--s1); }

/* modal de atajos */
.tb-sc-cap { margin: var(--s3) 0 var(--s1); }
.tb-sc-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 2px 14px; }
.tb-sc-row { display: flex; align-items: center; justify-content: space-between; gap: var(--s2); padding: var(--s1) var(--s2); border-radius: var(--r-2); cursor: pointer; font-size: var(--fs-3); }
.tb-sc-row:hover { background: var(--panel-2); }
.tb-sc-row.tb-capturing { box-shadow: var(--ring); } .tb-sc-row.tb-capturing kbd { color: var(--gold); }
@media (max-width: 720px) { .tb-sc-grid { grid-template-columns: 1fr; } }

/* fichas */
.tb-qty { width: 70px; } .tb-qty-lbl { white-space: nowrap; font-size: var(--fs-2); color: var(--text-2); }
/* Crear ficha (N): fichas de ~170px, como las de EDHPlay pero más chicas (las de ellos rondan 220 y a Gus le
   parecen grandes); el modal da para 6 por fila y la grilla usa casi todo el alto. En el teléfono, dos por fila. */
.modal.tb-tok-modal { width: min(1140px, 100%); }
.tb-tok-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(170px, calc(50% - var(--s2))), 1fr)); gap: var(--s2); max-height: 62vh; overflow: auto; margin: var(--s3) 0; }
.tb-tok-sec { grid-column: 1 / -1; color: var(--text-2); margin-top: var(--s1); }
.tb-tok { cursor: pointer; border-radius: var(--r-2); padding: var(--s1); } .tb-tok:hover { background: var(--panel-2); }
.tb-tok img, .tb-tok .card-placeholder { width: 100%; aspect-ratio: 488 / 680; }
.tb-tok .card-placeholder { font-size: var(--fs-3); flex-direction: column; }
.tb-tok-name { font-size: var(--fs-2); margin-top: var(--s1); text-align: center; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tb-tok-custom summary { cursor: pointer; font-weight: 700; padding: 6px 0; }
.tb-tok-form { display: flex; flex-direction: column; gap: var(--s2); padding-top: 6px; } .tb-tok-form .row .input { width: 70px; }
.tb-tok-colors { display: flex; gap: 6px; }
.tb-tok-color { width: 32px; height: 28px; border-radius: var(--r-2); border: 1px solid var(--border-2); background: var(--panel-2); display: inline-flex; align-items: center; justify-content: center; opacity: .5; }
.tb-tok-color.on { opacity: 1; border-color: var(--gold); background: var(--panel-3); }

/* dado */
.tb-dice { display: flex; flex-wrap: wrap; gap: 6px; }

/* "Elegir una al azar" (T.showRandom): la carta, su nombre y Mover a: */
.tb-rand { display: flex; flex-direction: column; align-items: center; gap: var(--s2); }
.tb-rand .card, .tb-rand .card-placeholder { width: min(240px, 70vw); aspect-ratio: 488 / 680; }
.tb-rand-actions { display: flex; flex-wrap: wrap; gap: var(--s2); justify-content: center; }

@media (max-width: 1000px) {
  .tb-other { min-width: 150px; }
}

/* con la caja de F/R abajo a la derecha, los contadores dejan de ocupar el ancho entero de la carta */


/* ----- contadores: chip de la marca y buscador ----- */
/* El contador común (Ctrl+1), como EDHPlay: un círculo rojo con el número en blanco, abajo a la izquierda y
   adentro de la carta, en los tres estilos (T.fillCard, fuera de las etiquetas). Cuando cambia, un "+1" sube
   desde ahí y se desvanece (.tb-mark-pop). Va en el mismo lugar en los tres estilos, aunque en la de Arena
   pise el comienzo de la línea de tipo: Gus lo quiere igual en todas. */
.tb-mark { position: absolute; left: 6%; bottom: 5%; z-index: 4; pointer-events: auto;
  width: max(16px, calc(var(--cw, 80px) * .17)); aspect-ratio: 1; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--rojo-contador); color: var(--text); box-shadow: 0 1px 4px rgba(0,0,0,.6);
  font-family: var(--font); font-weight: 800; font-size: max(10px, calc(var(--cw, 80px) * .105)); line-height: 1; font-variant-numeric: tabular-nums; }
.tb-mark[hidden] { display: none; }
.tb-hand > .tb-card > .tb-mark, .tb-zone-top .tb-mark { width: 18px; font-size: 11px; }
.tb-mark-pop { position: absolute; left: 6%; bottom: 22%; z-index: 5; pointer-events: none;
  color: var(--text); font-family: var(--font); font-weight: 800; font-size: max(12px, calc(var(--cw, 80px) * .12));
  text-shadow: 0 1px 3px rgba(0,0,0,.9), 0 0 6px rgba(0,0,0,.6); animation: tb-mark-pop 900ms var(--ease) forwards; }
.tb-mark-pop.tb-mark-baja { color: color-mix(in srgb, var(--rojo-contador) 45%, white); }
@keyframes tb-mark-pop { 0% { opacity: 0; transform: translateY(6px); } 20% { opacity: 1; transform: translateY(0); } 100% { opacity: 0; transform: translateY(-18px); } }
/* ficha: banda cruzada en la esquina de arriba a la derecha, como EDHPlay */
.tb-tokband { position: absolute; top: 0; right: 0; width: 46%; aspect-ratio: 1; overflow: hidden; pointer-events: none; z-index: 3;
  border-top-right-radius: calc(var(--cw, 80px) * .05); }
.tb-tokband > span { position: absolute; top: 22%; right: -34%; width: 120%; transform: rotate(45deg); text-align: center;
  background: color-mix(in srgb, var(--c) 45%, var(--bg)); color: var(--text); box-shadow: 0 1px 3px rgba(0,0,0,.5);
  font-size: calc(var(--cw, 80px) * .07); font-weight: 800; letter-spacing: .08em; line-height: 1.7; }
.tb-hand > .tb-card .tb-tokband > span, .tb-zone-top .tb-tokband > span { font-size: 9px; }
/* en la pila: la banda amarilla "PILA" cruzada arriba a la izquierda, como la "STACK" de EDHPlay (espejo de la de ficha) */
.tb-stackband { position: absolute; top: 0; left: 0; width: 46%; aspect-ratio: 1; overflow: hidden; pointer-events: none; z-index: 3;
  border-top-left-radius: calc(var(--cw, 80px) * .05); }
.tb-stackband[hidden] { display: none; }
.tb-stackband > span { position: absolute; top: 22%; left: -34%; width: 120%; transform: rotate(-45deg); text-align: center;
  background: var(--gold-2); color: var(--on-accent); box-shadow: var(--sh-1);
  font-size: calc(var(--cw, 80px) * .07); font-weight: 800; letter-spacing: .08em; line-height: 1.7; }
.tb-hand > .tb-card .tb-stackband > span, .tb-zone-top .tb-stackband > span { font-size: 9px; }
.tb-ctr-modal .modal-body { display: flex; flex-direction: column; gap: var(--s3); }
.tb-ctr-list { max-height: 46vh; overflow-y: auto; display: flex; flex-direction: column; gap: 2px; }
.tb-ctr-row { display: flex; align-items: center; gap: var(--s2); height: 32px; padding: 0 var(--s2); border-radius: var(--r-1); cursor: pointer; font-size: var(--fs-3); user-select: none; transition: background var(--t-fast) var(--ease); }
.tb-ctr-row:hover { background: var(--panel-3); }
.tb-ctr-row.tb-on { background: color-mix(in srgb, var(--gold) 10%, transparent); }
.tb-ctr-ico { width: 16px; height: 16px; flex: none; color: var(--text-2); }
.tb-ctr-name { flex: 1; }
.tb-ctr-n { min-width: 18px; text-align: right; color: var(--gold); font-variant-numeric: tabular-nums; }
.tb-ctr-custom { display: flex; gap: var(--s2); border-top: 1px solid var(--border); padding-top: var(--s3); }
.tb-ctr-custom .input { flex: 1; }
.tb-ctr-empty { color: var(--muted); font-size: var(--fs-2); padding: var(--s3); text-align: center; }
