/* ============================================================================
   Gacha Cockpit — panel de una máquina expendedora, no un dashboard.
   Metal gris + lectura ámbar de recreativa. Todo el color lo ponen las cartas.
   ========================================================================== */

:root{
  --void:#0b0d10;        /* chasis */
  --steel:#14181e;       /* panel */
  --steel-2:#1b212a;     /* panel elevado */
  --edge:#262e3a;        /* canto de chapa */
  --edge-hot:#394454;
  --ink:#e8ecf2;
  --ink-dim:#7b8798;
  --amber:#ffb020;       /* lectura de siete segmentos */
  --amber-dim:#8a6318;

  --epic:#ffc233;
  --rare:#b06bff;
  --uncommon:#3ee08c;
  --common:#5a6678;
  --up:#3ee08c;
  --down:#ff4d5e;

  --mono:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,monospace;
  --sans:-apple-system,BlinkMacSystemFont,"Segoe UI",system-ui,sans-serif;
}

*{box-sizing:border-box}
html,body{margin:0}
body{
  background:var(--void);
  color:var(--ink);
  font:13px/1.45 var(--sans);
  -webkit-font-smoothing:antialiased;
  /* Rejilla de chapa perforada, casi invisible: da materia sin ruido. */
  background-image:radial-gradient(var(--steel) 1px,transparent 1px);
  background-size:22px 22px;
}
.n{text-align:right;font-variant-numeric:tabular-nums}

/* ------------------------------------------------------------ riel superior */
.rail{
  position:sticky;top:0;z-index:30;
  display:flex;align-items:center;gap:22px;flex-wrap:wrap;
  padding:11px 20px;
  background:linear-gradient(180deg,#11151b,#0d1116);
  border-bottom:1px solid var(--edge);
  box-shadow:0 1px 0 #000a,0 8px 24px -18px #000;
}
.ident{display:flex;align-items:center;gap:10px}
.wordmark{
  font:700 15px/1 var(--mono);letter-spacing:.34em;
  color:var(--ink);text-indent:.34em;
}

/* ------------------------------------------------ banco de gachapones (firma) */
/*
 * Una sola fila, siempre, deslizable.
 *
 * Antes era una rejilla que se repartía el ancho, y con diez máquinas se
 * partía en dos filas de 110px cada una: media pantalla de escritorio para el
 * riel, con el feed empujado abajo. Y las de la segunda fila parecían de otra
 * categoría cuando solo estaban más frías.
 *
 * Con flex + scroll horizontal el riel mide siempre lo mismo, entren cinco
 * máquinas o quince, y el orden por racha decide qué se ve sin deslizar.
 */
.bank{
  display:flex;gap:1px;overflow-x:auto;overscroll-behavior-x:contain;
  scroll-snap-type:x proximity;
  scrollbar-width:none;-ms-overflow-style:none;
  background:var(--edge);border-bottom:1px solid var(--edge);
}
.bank::-webkit-scrollbar{display:none}

.unit{
  background:linear-gradient(180deg,var(--steel-2),var(--steel));
  padding:11px 15px 11px 11px;position:relative;overflow:hidden;
  display:flex;align-items:center;justify-content:flex-start;gap:11px;
  flex:0 0 auto;scroll-snap-align:start;
}
.gm{width:46px;height:72px;flex:none;transform-origin:50% 92%}
.gm .chassis{fill:#232b36;stroke:#39424f;stroke-width:2;transition:stroke .5s,filter .5s}
.gm .knob{fill:#39424f}
.gm .knob-slot{fill:#151a21}
.gm .flap{fill:#0a0d11;stroke:#39424f;stroke-width:1.5}
.gm .caps{transform-origin:32px 32px}

.tag{display:flex;flex-direction:column;gap:3px;min-width:0}
.tag b{font:700 20px/1 var(--mono);font-variant-numeric:tabular-nums;letter-spacing:-.02em}
.tag span i{display:block;font-style:normal;opacity:.72}
.tag span{
  font:9px/1.3 var(--mono);letter-spacing:.09em;text-transform:uppercase;
  color:var(--ink-dim);transition:color .5s;
}

/*
 * El borde sube con la racha, con la misma escala que ya usa el chasis:
 * amarillo al acercarse, ámbar en el umbral con el que avisa el bot, rojo
 * pasado de vueltas. Va como box-shadow interior y no como border para no
 * mover el layout al aparecer.
 *
 * Nivel 1 no lleva borde a propósito: por debajo de 10 no ha pasado nada
 * todavía, y marcar seis máquinas a la vez es lo mismo que no marcar ninguna.
 */
.unit{transition:box-shadow .6s ease}

/*
 * La líder del ranking: siempre con borde y siempre respirando, aunque la
 * racha esté a cero. Es el ancla del riel. Sin ella el banco se quedaba
 * inmóvil por debajo de 10 seguidas, que es la mayor parte del tiempo.
 *
 * En frío va en amarillo apagado, para que se lea como "esta es la que hay que
 * mirar" y no como "aquí está pasando algo". Cuando la racha sube de verdad,
 * los niveles de abajo pisan este color y la rampa queda monótona:
 *   apagado -> amarillo -> ámbar -> rojo
 */
.unit.lead{box-shadow:inset 0 0 0 2px #ffd16659}
.unit.lead .gm{animation:breathe 3.6s ease-in-out infinite}
.unit.lead .caps{animation:rattle 2.6s ease-in-out infinite}

/* Más suave que `tremble`: es un latido de fondo, no un nervio. Si la líder en
   frío temblara como una a punto de romper, el temblor dejaría de ser el dato. */
@keyframes breathe{
  0%,100%{transform:translate(0,0) rotate(0)}
  30%{transform:translate(-.45px,.15px) rotate(-.32deg)}
  65%{transform:translate(.45px,-.15px) rotate(.32deg)}
}

.unit.lvl-2{box-shadow:inset 0 0 0 2px #ffd166}
.unit.lvl-3{box-shadow:inset 0 0 0 2px var(--amber)}
.unit.lvl-4{box-shadow:inset 0 0 0 2px var(--down)}
/* La elegida por filtro gana al calor: es una respuesta a algo que hiciste. */
.unit.picked{box-shadow:inset 0 0 0 2px var(--ink) !important}

/* --- cinco grados de nervio. El temblor ES el dato. --- */
.unit.lvl-1 .gm{animation:tremble 2.4s ease-in-out infinite}
.unit.lvl-1 .caps{animation:rattle 1.1s ease-in-out infinite}

.unit.lvl-2 .gm{animation:tremble 1.1s ease-in-out infinite}
.unit.lvl-2 .caps{animation:rattle .5s ease-in-out infinite}
.unit.lvl-2 .gm .chassis{stroke:#ffd166;filter:drop-shadow(0 0 4px #ffd16655)}
.unit.lvl-2 .tag span{color:#ffd166}
.unit.lvl-2 .gm .knob{fill:#5a5233}

.unit.lvl-3 .gm{animation:tremble .5s ease-in-out infinite}
.unit.lvl-3 .caps{animation:rattle .3s ease-in-out infinite}
.unit.lvl-3 .gm .chassis{stroke:var(--amber);filter:drop-shadow(0 0 6px #ffb02088)}
.unit.lvl-3 .tag span{color:var(--amber)}
.unit.lvl-3 .tag b{color:var(--amber)}

.unit.lvl-4 .gm{animation:tremble .22s linear infinite}
.unit.lvl-4 .caps{animation:rattle .16s linear infinite}
.unit.lvl-4 .gm .chassis{stroke:var(--down);filter:drop-shadow(0 0 10px #ff4d5ecc)}
.unit.lvl-4 .tag span,.unit.lvl-4 .tag b{color:var(--down)}
.unit.lvl-4::after{
  content:'';position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(120% 90% at 50% 120%,#ff4d5e1f,transparent 70%);
}

@keyframes tremble{
  0%,100%{transform:translate(0,0) rotate(0deg)}
  20%{transform:translate(-1.1px,.4px) rotate(-.9deg)}
  45%{transform:translate(1.1px,-.4px) rotate(.9deg)}
  70%{transform:translate(-.7px,.2px) rotate(-.5deg)}
}
@keyframes rattle{
  0%,100%{transform:translate(0,0)}
  30%{transform:translate(1.4px,-1.1px)}
  65%{transform:translate(-1.2px,1.3px)}
}

/* Entra una carta en esta máquina: la trampilla escupe y el chasis destella. */
.unit.bump .flap{animation:spit .4s ease-out}
.unit.bump{animation:panel .42s ease-out}
@keyframes spit{
  0%{transform:translateY(0)}
  35%{transform:translateY(4px) scaleY(.7)}
  100%{transform:translateY(0)}
}
@keyframes panel{0%{background:#232b36}100%{background:transparent}}

.unit.dead{opacity:.32}
.unit.dead .gm{animation:none}

/* ------------------------------------------------------------------ vistas */
main{padding:16px 20px 70px}
.view{display:none}
.view.on{display:block}
.note{color:var(--ink-dim);font:10px/1.5 var(--mono);letter-spacing:.04em;margin:0 0 12px}
.empty{color:var(--ink-dim);text-align:center;padding:70px 0;font:11px/1 var(--mono);letter-spacing:.1em}

.filters{margin-bottom:14px}
.filters-row{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin-top:10px}
input[type=search]{
  background:var(--void);border:1px solid var(--edge);color:var(--ink);
  padding:7px 11px;border-radius:2px;width:250px;font:11px/1 var(--mono);
}
input[type=search]:focus{outline:none;border-color:var(--amber)}
.chk{display:flex;align-items:center;gap:6px;color:var(--ink-dim);font:10px/1 var(--mono);letter-spacing:.06em;cursor:pointer}
.tally{color:var(--ink-dim);font:10px/1 var(--mono);letter-spacing:.06em}

.chips{display:flex;gap:1px;flex-wrap:wrap;background:var(--edge);padding:1px;border-radius:2px;width:fit-content}
.chip{
  background:var(--steel);border:0;color:var(--ink-dim);cursor:pointer;
  padding:6px 11px;font:10px/1 var(--mono);letter-spacing:.06em;
  font-variant-numeric:tabular-nums;white-space:nowrap;
}
.chip:hover:not(:disabled){color:var(--ink)}
.chip.on{background:var(--amber);color:#0b0d10;font-weight:700}
.chip:disabled{opacity:.3;cursor:default}

/* ------------------------------------------------------------------- chute */
.chute{display:grid;grid-template-columns:repeat(auto-fill,minmax(184px,1fr));gap:14px}

.slab{
  background:var(--steel);border:1px solid var(--edge);
  position:relative;cursor:pointer;
  /* El transform lo pilota el FLIP en JS con su propia duración; dejarlo aquí
     a .12s le recortaba el deslizamiento a un tirón. Solo queda el color. */
  transition:border-color .12s;
}
.slab:hover{border-color:#3a4553}

/* Cabecera del slab: imita la etiqueta de la carcasa de gradeo. */
.slab .label{
  display:flex;justify-content:space-between;align-items:center;gap:6px;
  padding:5px 8px;border-bottom:1px solid var(--edge);
  font:9px/1 var(--mono);letter-spacing:.1em;text-transform:uppercase;
}
.slab .label .tier{font-weight:700}
.slab .label .pack{color:var(--ink-dim);font-variant-numeric:tabular-nums}

.slab .img{aspect-ratio:5/7;width:100%;object-fit:cover;display:block;background:#0c0f13}
.slab .body{padding:8px 9px 10px}
.slab .nm{font:11px/1.35 var(--sans);height:2.7em;overflow:hidden;margin-bottom:7px;color:#cfd6e0}
.slab .row{display:flex;justify-content:space-between;align-items:baseline;gap:6px}
.slab .val{font:600 15px/1 var(--mono);font-variant-numeric:tabular-nums}
.slab .mult{font:600 11px/1 var(--mono)}
.slab .meta{font:9px/1 var(--mono);color:var(--ink-dim);letter-spacing:.04em;margin-top:5px;display:flex;justify-content:space-between}

.good{color:var(--up)} .bad{color:var(--down)}

/* Rareza: el canto del slab, no un badge de color. */
.slab.t-common{border-color:var(--edge)}
.slab.t-common .label .tier{color:var(--common)}
.slab.t-uncommon{border-color:#256b4a}
.slab.t-uncommon .label .tier{color:var(--uncommon)}
.slab.t-rare{border-color:#6b3fb0;box-shadow:0 0 0 1px #b06bff22,0 0 22px -10px var(--rare)}
.slab.t-rare .label .tier{color:var(--rare)}
.slab.t-epic{border-color:var(--epic);box-shadow:0 0 0 1px #ffc23333,0 0 30px -10px var(--epic)}
.slab.t-epic .label .tier{color:var(--epic)}

/* La epic respira. Una sola cosa en la página lo hace. */
.slab.t-epic{animation:pulse 3s ease-in-out infinite}
@keyframes pulse{
  0%,100%{box-shadow:0 0 0 1px #ffc23333,0 0 30px -12px var(--epic)}
  50%{box-shadow:0 0 0 1px #ffc23366,0 0 40px -4px var(--epic)}
}

/* Caída: entra por arriba con peso, no aparece. */
.slab.drop{animation:drop .42s cubic-bezier(.2,.8,.25,1)}
/*
 * Entrada de carta nueva.
 *
 * Antes caía 26px desde arriba con rebote, y tenía sentido cuando las de abajo
 * saltaban de golpe: el golpe tapaba el salto. Ahora que el hueco se abre solo
 * (FLIP en renderFeed), la caída pelea con ese movimiento y se ve dos veces la
 * misma idea. Se queda en aparecer: opacidad y un pelín de escala, en el mismo
 * tiempo que tarda el hueco en abrirse, así entra la carta a la vez que le
 * hacen sitio en vez de aterrizar encima.
 */
@keyframes drop{
  0%{opacity:0;transform:scale(.965)}
  100%{opacity:1;transform:none}
}
.slab.drop.t-rare{animation:drop .42s cubic-bezier(.2,.8,.25,1),shake .28s 2}
.slab.drop.t-epic{animation:drop .42s cubic-bezier(.2,.8,.25,1),shake .24s 4}
@keyframes shake{
  0%,100%{translate:0 0;rotate:0deg}
  25%{translate:-4px 0;rotate:-.7deg}
  75%{translate:4px 0;rotate:.7deg}
}

/* Destello de página: solo epic y rare muy alta. Breve, una vez. */
.flash{
  position:fixed;inset:0;pointer-events:none;z-index:50;opacity:0;
  background:radial-gradient(60% 45% at 50% 0%,var(--fc,#ffc233)55,transparent 70%);
}
.flash.go{animation:flash 1s ease-out}
@keyframes flash{0%{opacity:.5}100%{opacity:0}}

/* ------------------------------------------------------------------ tablas */
.grid{width:100%;border-collapse:collapse;font:11px/1.5 var(--mono)}
.grid th{
  text-align:left;color:var(--ink-dim);font-weight:400;font-size:9px;
  letter-spacing:.13em;text-transform:uppercase;
  padding:8px 10px;border-bottom:1px solid var(--edge);
  position:sticky;top:49px;background:var(--void);
}
.grid td{padding:8px 10px;border-bottom:1px solid #141920;font-variant-numeric:tabular-nums}
.grid tbody tr:hover{background:var(--steel)}
.clickable{cursor:pointer;color:var(--amber)}
.warn{color:var(--amber)}
.pill{display:inline-block;padding:1px 6px;background:var(--steel-2);border:1px solid var(--edge);font-size:9px}

/* ------------------------------------------------------------------ modal */
.modal{position:fixed;inset:0;background:#000d;display:grid;place-items:center;z-index:60;padding:20px}
.modal[hidden]{display:none}
.modal-inner{
  background:var(--steel);border:1px solid var(--edge);
  max-width:940px;width:100%;max-height:88vh;overflow:auto;padding:22px;position:relative;
}
.close{position:absolute;top:12px;right:14px;background:none;border:0;color:var(--ink-dim);font-size:16px;cursor:pointer}
/* ---------------------------------------------------- detalle de la carta */
/*
 * Antes era la carta, su reverso y una lista de trece etiquetas todas del
 * mismo tamaño: había que leerlas todas para encontrar lo que importa. Ahora
 * hay jerarquía: lo que salió, cuánto valió y de qué máquina, grande; el resto
 * en una rejilla tranquila debajo.
 */
.cd{display:grid;grid-template-columns:minmax(0,300px) minmax(0,1fr);gap:26px;align-items:start}
.cd-img img{width:100%;display:block;border-radius:3px}
.cd-none{aspect-ratio:5/7;background:var(--void);border:1px solid var(--edge);border-radius:3px}

.cd-tier{
  display:inline-block;font:700 9px/1 var(--mono);letter-spacing:.18em;
  text-transform:uppercase;padding:5px 9px;border-radius:2px;margin-bottom:11px;
  background:var(--steel-2);border:1px solid var(--edge);color:var(--ink-dim);
}
.cd-tier.t-uncommon{color:var(--uncommon);border-color:#256b4a}
.cd-tier.t-rare{color:var(--rare);border-color:#6b3fb0}
.cd-tier.t-epic{color:var(--epic);border-color:var(--epic)}

.cd-name{font:600 20px/1.3 var(--sans);letter-spacing:-.015em;margin:0 0 22px}

/* Lo que se mira primero: qué valió y si mereció la pena. */
.cd-hero{
  display:flex;gap:1px;background:var(--edge);
  border:1px solid var(--edge);border-radius:3px;margin-bottom:22px;
}
.cd-hero>div{flex:1 1 0;background:var(--steel-2);padding:12px 14px;min-width:0}
.cd-hero i{
  display:block;font-style:normal;font:8.5px/1 var(--mono);letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink-dim);margin-bottom:7px;
}
.cd-hero b{
  font:700 18px/1 var(--mono);font-variant-numeric:tabular-nums;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:block;
}

.cd-grid{display:flex;flex-direction:column}
.cd-row{
  display:flex;justify-content:space-between;align-items:baseline;gap:16px;
  padding:8px 0;border-bottom:1px solid var(--edge);
}
.cd-row:last-child{border-bottom:0}
.cd-row span{
  font:9px/1.4 var(--mono);letter-spacing:.12em;text-transform:uppercase;
  color:var(--ink-dim);flex:none;
}
.cd-row b{font:12px/1.4 var(--mono);text-align:right;min-width:0;word-break:break-word}

.cd-link{
  display:inline-block;margin-top:20px;color:var(--amber);text-decoration:none;
  font:700 11px/1 var(--mono);letter-spacing:.1em;text-transform:uppercase;
}
.cd-link:hover{text-decoration:underline}
.cd-mint{
  margin:16px 0 0;font:9px/1.5 var(--mono);color:#4b5563;word-break:break-all;
}

@media (max-width:700px){
  /* Una columna, y la imagen más pequeña: en un móvil la carta a ancho
     completo dejaba todos los datos por debajo del pliegue. */
  .cd{grid-template-columns:1fr;gap:18px;justify-items:center}
  .cd-img{width:62%;max-width:230px}
  .cd-info{width:100%}
  .cd-name{font-size:17px;margin-bottom:18px}
  .cd-hero{flex-direction:column}
  .cd-hero>div{display:flex;align-items:baseline;justify-content:space-between;gap:12px;padding:10px 13px}
  .cd-hero i{margin-bottom:0}
  .cd-hero b{font-size:15px;text-align:right}
}

/* --------------------------------------------------------- accesibilidad */
:focus-visible{outline:2px solid var(--amber);outline-offset:2px}
@media (prefers-reduced-motion: reduce){
  .slab.drop,.slab.drop.t-rare,.slab.drop.t-epic,.slab.t-epic{animation:none}
  .unit .gm,.unit .caps,.unit.bump,.unit.bump .flap{animation:none}
  .flash.go{animation:none}
}

/* ─────────────────────────────────────────────────────────────── LOADING
   El gesto del producto: la manivela gira, la cápsula cae. No un spinner. */
.boot{
  position:fixed;inset:0;z-index:99;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:22px;
  background:var(--void);
  background-image:radial-gradient(var(--steel) 1px,transparent 1px);
  background-size:22px 22px;
  transition:opacity .45s ease,visibility .45s;
}
.boot.gone{opacity:0;visibility:hidden;pointer-events:none}
.boot-gm{width:96px;height:auto}
.boot-gm .b-dome{transform-origin:32px 32px;animation:b-shake 1.6s ease-in-out infinite}
.boot-gm .b-caps{transform-origin:32px 32px;animation:b-rattle .42s ease-in-out infinite}
.boot-gm .b-knob{transform-origin:32px 72px;animation:b-turn 1.6s cubic-bezier(.6,0,.3,1) infinite}
.boot-gm .b-drop{opacity:0;animation:b-fall 1.6s ease-in infinite}

@keyframes b-shake{
  0%,55%,100%{transform:translate(0,0) rotate(0)}
  62%{transform:translate(-1.6px,.6px) rotate(-1.4deg)}
  72%{transform:translate(1.6px,-.6px) rotate(1.4deg)}
  82%{transform:translate(-.9px,.3px) rotate(-.7deg)}
}
@keyframes b-rattle{
  0%,100%{transform:translate(0,0)}
  35%{transform:translate(1.6px,-1.2px)}
  70%{transform:translate(-1.4px,1.4px)}
}
/* La manivela da media vuelta, se para, y entonces cae la cápsula. */
@keyframes b-turn{
  0%,45%{transform:rotate(0)}
  70%,100%{transform:rotate(180deg)}
}
@keyframes b-fall{
  0%,62%{opacity:0;transform:translateY(0) scale(.6)}
  70%{opacity:1;transform:translateY(4px) scale(1)}
  92%{opacity:1;transform:translateY(20px) scale(1)}
  100%{opacity:0;transform:translateY(26px) scale(.9)}
}

.boot-txt{
  margin:0;color:var(--ink-dim);
  font:10px/1 var(--mono);letter-spacing:.22em;text-transform:uppercase;
}
.boot-txt span{animation:b-dot 1.4s infinite}
.boot-txt span:nth-child(2){animation-delay:.2s}
.boot-txt span:nth-child(3){animation-delay:.4s}
@keyframes b-dot{0%,60%,100%{opacity:.2}30%{opacity:1}}

@media (prefers-reduced-motion:reduce){
  .boot-gm .b-dome,.boot-gm .b-caps,.boot-gm .b-knob,.boot-gm .b-drop,.boot-txt span{animation:none}
  .boot-gm .b-drop{opacity:1}
}


/* ---------------------------------------------------------------- marca */
.mark{display:flex;align-items:center;gap:11px;text-decoration:none;color:var(--amber)}
.mark span{font:700 14px/1 var(--mono);letter-spacing:.3em;text-indent:.3em;color:var(--ink)}
.logo{width:26px;height:26px;flex:none;overflow:visible}
.rail .logo{width:23px;height:23px;color:var(--amber)}
/* Las estelas caen al pasar el ratón: la cápsula está cayendo, no posando. */
.ident:hover .logo .sweep{animation:fall .9s cubic-bezier(.4,0,.6,1)}
@keyframes fall{
  0%{transform:translateY(-6px);opacity:0}
  35%{opacity:.85}
  100%{transform:translateY(9px);opacity:0}
}
@media (prefers-reduced-motion:reduce){.ident:hover .logo .sweep{animation:none}}

/* ------------------------------------------------------------------ móvil */
/*
 * El tablero se diseñó para escritorio y en un móvil quedaba al revés de lo
 * que interesa: banco de máquinas en rejilla de 2 columnas (3 filas para 5
 * máquinas) y chips de precio en 3 filas se comían la pantalla entera, y el
 * feed de cartas, que es el producto, empezaba por debajo del pliegue.
 *
 * Todo lo que aquí se hace es convertir en rieles horizontales lo que era
 * rejilla que crece hacia abajo. El alto es el recurso escaso; el ancho se
 * puede deslizar.
 */
@media (max-width: 700px){
  main{padding:12px 12px 60px}

  /* En móvil, un punto más compacto todavía. */
  .unit{padding:9px 14px 9px 10px;gap:10px}
  .gm{width:38px;height:60px}
  .tag b{font-size:15px}
  .tag span{font-size:9px;letter-spacing:.05em}

  /* Chips: una sola fila que se desliza, en vez de tres que empujan. */
  .chips{flex-wrap:nowrap;overflow-x:auto;width:auto;max-width:100%;
    scrollbar-width:none;-ms-overflow-style:none;}
  .chips::-webkit-scrollbar{display:none}
  .chip{padding:7px 10px}

  .filters-row{gap:9px;margin-top:8px}
  input[type=search]{width:100%}

  /*
   * El feed pasa de rejilla de cartas a lista, como pump.fun.
   *
   * Con dos columnas cabían 4 cartas en pantalla y había que mirarlas de una
   * en una. En lista caben 7 u 8 y se escanean de un vistazo, que es lo que
   * quieres de un flujo: ver qué está saliendo, no admirar cada carta. La
   * imagen sigue ahí, más pequeña, y quien quiera detalle toca y abre.
   *
   * Descarté el carrusel: oculta lo que no está a la vista y obliga a
   * deslizar para saber si te perdiste algo. En un feed que se mueve solo,
   * eso es justo lo contrario de lo que hace falta.
   */
  .chute{display:flex;flex-direction:column;gap:1px;background:var(--edge)}
  .slab{
    display:grid;grid-template-columns:52px minmax(0,1fr) auto;
    align-items:center;gap:11px;padding:8px 11px 8px 8px;
    border:0;border-left:2px solid transparent;
  }
  .slab:hover{transform:none}
  /* La etiqueta deja de ser una barra superior y pasa a columna derecha, como
     los números de pump.fun. Se conserva el precio del sobre: dice de qué
     máquina salió la carta y es de lo poco que se mira de un vistazo. El
     nombre del tier sí sobra, porque el canto de color ya lo dice. */
  .slab .label{
    grid-column:3;grid-row:1;flex-direction:column;align-items:flex-end;gap:3px;
    padding:0;border:0;
  }
  .slab .label .tier{display:none}
  .slab .label .pack{font-size:11px;color:var(--ink)}
  .slab .img{grid-column:1;grid-row:1;width:52px;aspect-ratio:5/7;border-radius:2px}
  .slab .body{grid-column:2;grid-row:1;padding:0;min-width:0}
  .slab .nm{
    font-size:12px;height:auto;margin-bottom:3px;
    display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
  }
  .slab .row{justify-content:flex-start;gap:8px}
  .slab .val{font-size:14px}
  .slab .meta{margin-top:2px;gap:8px;justify-content:flex-start}

  .slab.t-common{border-left-color:var(--edge)}
  /* La que rompe se distingue por el canto y por la etiqueta "BROKE N", no
     por un marco entero: en una lista, un recuadro alrededor de una fila se
     lee como "esta está seleccionada", que es otra cosa. */
  .slab.broke{border-left-width:3px}
  .slab.t-uncommon{border-left-color:var(--uncommon)}
  .slab.t-rare{border-left-color:var(--rare);box-shadow:none}
  .slab.t-epic{border-left-color:var(--epic);box-shadow:none;animation:none}

  .rail{gap:12px;padding:10px 12px}
  .wordmark{font-size:13px;letter-spacing:.24em;text-indent:.24em}
}

/* Pantallas estrechas de verdad: una sola carta por fila se lee mejor que dos
   ilegibles, pero solo por debajo de donde dos dejan de caber. */



/* CTA del bot en el riel. `margin-left:auto` lo empuja a la derecha sin tocar
   el layout del resto. En móvil se queda solo el icono más "BOT": el texto
   completo se comía el ancho que necesita el logotipo. */
.rail .tg{
  margin-left:auto;display:flex;align-items:center;gap:7px;flex:none;
  background:var(--amber);color:#0b0d10;text-decoration:none;
  padding:8px 13px;border-radius:2px;
  font:700 10px/1 var(--mono);letter-spacing:.12em;text-transform:uppercase;
  transition:filter .2s;
}
.rail .tg:hover{filter:brightness(1.12)}
@media (max-width: 700px){
  .rail .tg{padding:8px 11px;gap:6px;letter-spacing:.08em}
  .rail .tg span{font-size:9px}
}

/* ------------------------------------------------------ la carta que rompe */
/*
 * El suceso no es la rareza de la carta, es lo que le hizo a la racha. Una
 * uncommon de $30 que corta 22 seguidas es la noticia; una rare en una máquina
 * fría es un número. Esto marca la primera y deja la segunda como estaba.
 *
 * Borde completo del color del tier, no el canto: en la lista de móvil el
 * canto izquierdo lo lleva ya cada carta y no distinguiría nada.
 */
.slab.broke.t-uncommon{color:var(--uncommon)}
.slab.broke.t-rare{color:var(--rare)}
.slab.broke.t-epic{color:var(--epic)}
.slab.broke .label .tier{
  color:currentColor;font-weight:700;
  font-variant-numeric:tabular-nums;
}
/* El texto de dentro no hereda el color del borde. */
.slab.broke .nm{color:#cfd6e0}
.slab.broke .val{color:var(--ink)}

/*
 * Sacudida solo al llegar, y una vez. La máquina llevaba temblando cada vez
 * más fuerte según subía la racha; esto es el corte. Por eso termina en seco
 * en vez de desvanecerse: el frenazo después de la tensión es el momento.
 */
.slab.snap{animation:drop .42s cubic-bezier(.2,.8,.25,1), snap .5s .1s steps(1,end) 3}
@keyframes snap{
  0%{transform:translateX(0)}
  12%{transform:translateX(-4px) rotate(-.6deg)}
  25%{transform:translateX(4px) rotate(.6deg)}
  37%{transform:translateX(-3px)}
  50%{transform:translateX(3px)}
  62%{transform:translateX(-1.5px)}
  75%{transform:translateX(1.5px)}
  100%{transform:translateX(0)}
}
@media (prefers-reduced-motion:reduce){
  .slab.snap{animation:none}
}

/* ------------------------------------------------------- pulls en espera */
/*
 * Píldora al estilo pump.fun. Aparece solo cuando estás scrolleado: arriba del
 * todo el feed en vivo es el producto y esto sobraría.
 *
 * Va pegada arriba (sticky) y no fija, para que no tape cartas cuando vuelves
 * al principio: se retira sola con el scroll en vez de flotar siempre.
 */
.pendientes{
  position:sticky;top:60px;z-index:25;
  display:flex;align-items:center;justify-content:center;gap:10px;
  width:100%;margin:0 0 12px;padding:9px 16px;
  background:var(--steel-2);border:1px solid var(--edge);border-radius:999px;
  color:var(--ink);cursor:pointer;
  font:700 11px/1 var(--mono);letter-spacing:.1em;text-transform:uppercase;
  box-shadow:0 10px 26px -14px #000c;
  animation:asoma .3s cubic-bezier(.2,.8,.25,1);
}
.pendientes:hover{border-color:var(--amber);color:var(--amber)}
.pendientes[hidden]{display:none}
.pendientes .flecha{color:var(--up);font-size:13px}
.pendientes .caras{display:flex}
.pendientes .caras img,.pendientes .caras i{
  width:20px;height:20px;border-radius:50%;object-fit:cover;
  border:1.5px solid var(--steel-2);background:#0c0f13;
  margin-left:-7px;
}
.pendientes .caras img:first-child,.pendientes .caras i:first-child{margin-left:0}
@keyframes asoma{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){.pendientes{animation:none}}
@media (max-width:700px){
  .pendientes{top:52px;font-size:10px;padding:8px 13px;gap:8px}
}

/* Marca de la tienda. Solo aparece en las que no son de la escalera pokemon_*,
   porque ahí el precio ya no identifica la máquina: degen_100 y water_100 son
   las dos de $100. Va pequeña y encima, para que el precio siga mandando. */
.tag em{
  display:block;font-style:normal;
  font:700 8.5px/1.5 var(--mono);letter-spacing:.16em;text-transform:uppercase;
  color:var(--ink-dim);
}
.unit.lvl-3 .tag em,.unit.lvl-4 .tag em{color:inherit;opacity:.8}

/* ------------------------------------------------ modal de "añadir el bot" */
/* El botón del riel es <button>, no <a>: ya no lleva a Telegram directo sino
   que abre esto. Hereda el aspecto de .tg, así que solo hay que neutralizar lo
   que un botón trae de fábrica. */
.rail button.tg{border:0;font-family:var(--mono)}

.bot-t{font:600 19px/1.25 var(--sans);letter-spacing:-.015em;margin:0 0 14px}
.bot-p{color:#9aa5b3;font-size:13.5px;margin:0 0 12px}
.bot-p code,.bot-o code{
  font:11px var(--mono);background:var(--void);border:1px solid var(--edge);
  padding:1px 5px;color:var(--ink);
}
.bot-l{list-style:none;padding:0;margin:0 0 18px;display:flex;flex-direction:column;gap:9px}
.bot-l li{display:flex;flex-direction:column;gap:2px;font-size:13.5px;color:var(--ink)}
.bot-l li i{font-style:normal;color:var(--ink-dim);font-size:11.5px}
.bot-o{list-style:none;padding:0;margin:0 0 18px;display:flex;flex-direction:column;gap:11px}
.bot-o li{display:flex;align-items:flex-start;gap:11px;font-size:13.5px;color:#b3bcc9}
.bot-o li span{
  flex:none;width:21px;height:21px;display:grid;place-items:center;margin-top:1px;
  background:var(--amber);color:#0b0d10;font:700 10px/1 var(--mono);border-radius:50%;
}
.bot-cta{
  display:block;text-align:center;text-decoration:none;
  background:var(--amber);color:#0b0d10;padding:13px 18px;border-radius:2px;
  font:700 12px/1 var(--mono);letter-spacing:.12em;text-transform:uppercase;
  transition:filter .2s;
}
.bot-cta:hover{filter:brightness(1.12)}

/* Qué es esto, para quien llega de frío. Ahora que la portada es el tablero
   no hay ninguna otra frase que lo explique. */
.ident-txt{display:flex;flex-direction:column;gap:3px;min-width:0}
.claim{
  font:10.5px/1.2 var(--mono);letter-spacing:.04em;color:var(--ink-dim);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
/*
 * Se encoge antes de desaparecer.
 *
 * Lo escondí por debajo de 820px razonando que en móvil sobra, y me olvidé de
 * que una ventana de PWA en escritorio abre bastante más estrecha que eso: la
 * app instalada nunca lo enseñaba. Y es justo ahí donde más falta hace, porque
 * en la app no hay barra de direcciones ni pestaña que digan qué estás mirando.
 *
 * Ahora solo se retira por debajo de 480px, donde ni truncado se lee.
 */
@media (max-width:820px){
  .claim{font-size:9.5px;letter-spacing:.02em}
}
/*
 * En móvil ya no se esconde: se parte en dos líneas.
 *
 * Lo oculté dos veces por el mismo error de razonamiento, primero bajo 820px y
 * luego bajo 480px, pensando que no cabía al lado del logotipo y del botón. No
 * cabe, pero no tiene por qué caber ahí: puede ocupar dos líneas debajo del
 * logotipo y crecer la cabecera 11px. En la app instalada no hay barra de
 * direcciones ni pestaña, así que esta frase es lo ÚNICO que dice qué estás
 * mirando; es lo último que debería desaparecer, no lo primero.
 */
@media (max-width:480px){
  .claim{
    white-space:normal;font-size:9px;line-height:1.25;letter-spacing:0;
    display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
  }
  /* Sin esto el bloque de texto no puede encoger y empuja al botón fuera. */
  .rail .ident{min-width:0;flex:1 1 auto}
  /* Y sin esto el botón cae a una segunda fila y la cabecera crece el doble.
     Prefiero que la frase se parta en dos líneas dentro de su columna a que el
     CTA se descuelgue: el botón tiene que estar donde el pulgar lo espera. */
  .rail{flex-wrap:nowrap}
  .rail .tg{flex:none}
}

/* --------------------------------------------------------- barra de compra */
/*
 * Fija abajo, atada a la máquina de racha más larga.
 *
 * Dice "longest run", no "best": la racha describe lo que ya pasó y no predice
 * la siguiente tirada. Prometerlo en el botón principal contradiría el aviso
 * que el propio producto da en el bot y en el modal.
 */
.buybar{
  position:fixed;left:0;right:0;bottom:0;z-index:40;
  display:flex;align-items:center;gap:14px;
  padding:10px 16px;
  background:linear-gradient(180deg,#161b22,#0e1217);
  border-top:1px solid var(--edge);
  box-shadow:0 -14px 34px -20px #000;
  text-decoration:none;color:var(--ink);
  transition:background .2s;
}
.buybar[hidden]{display:none}
/* Es <button>, no <a>: todavía no lleva a ningún sitio. */
.buybar{border:0;border-top:1px solid var(--edge);font-family:inherit;text-align:left;cursor:pointer}
.buybar.soon .bb-go{background:var(--steel-2);color:var(--ink-dim)}
.buybar.soon .bb-go span::after{content:''}
.buybar.soon .bb-go{font-size:0}
.buybar.soon .bb-go::before{content:'Soon';font-size:11px}
.buybar.soon .bb-go svg{display:none}
.buybar:hover{background:linear-gradient(180deg,#1b212a,#11161c)}

.bb-run{display:flex;align-items:center;gap:5px;flex:none}
.bb-run b{font:700 17px/1 var(--mono);font-variant-numeric:tabular-nums;color:var(--amber)}
.bolt{
  width:17px;height:17px;flex:none;
  fill:var(--amber);
  filter:drop-shadow(0 0 5px #ffb02066);
}

.bb-txt{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1 1 auto}
.bb-txt i{
  font-style:normal;font:9px/1 var(--mono);letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink-dim);
}
.bb-txt b{font:700 14px/1 var(--mono);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

.bb-go{
  flex:none;display:flex;align-items:center;gap:7px;
  background:var(--amber);color:#0b0d10;
  padding:10px 15px;border-radius:2px;
  font:700 11px/1 var(--mono);letter-spacing:.12em;text-transform:uppercase;
}
.bb-go svg{width:14px;height:14px;fill:none;stroke:currentColor;stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round}

/* La barra tapa el final del feed; se le devuelve el sitio. */
main{padding-bottom:86px}
@media (max-width:700px){
  .buybar{gap:11px;padding:9px 12px}
  .bb-txt i{font-size:8.5px;letter-spacing:.1em}
  .bb-txt b{font-size:13px}
  .bb-go{padding:9px 12px;font-size:10px}
  main{padding-bottom:80px}
}

/* Nombre del bot, copiable. Va justo bajo el título porque es el dato que
   permite encontrarlo si el enlace profundo no engancha. */
.bot-handle{
  display:flex;align-items:center;gap:9px;
  background:var(--void);border:1px solid var(--edge);border-radius:2px;
  padding:9px 12px;margin:0 0 18px;cursor:pointer;
  color:var(--amber);font:700 13px/1 var(--mono);letter-spacing:.02em;
  transition:border-color .2s,color .2s;
}
.bot-handle:hover{border-color:var(--amber)}
.bot-handle svg{
  width:13px;height:13px;flex:none;fill:none;stroke:currentColor;
  stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round;opacity:.6;
}
.bot-handle.ok{color:var(--up);border-color:var(--up)}
.bot-handle.ok span::after{content:' · copied';font-weight:400;opacity:.75}

/* ------------------------------------- zonas seguras y aire de la cabecera */
/*
 * En la PWA el contenido llega hasta los bordes físicos: arriba se mete bajo
 * el reloj y abajo bajo el indicador de inicio. `viewport-fit=cover` en el
 * viewport es lo que habilita estos env(), sin él valen 0.
 */
.rail{
  padding-top:calc(11px + env(safe-area-inset-top));
  padding-left:calc(20px + env(safe-area-inset-left));
  padding-right:calc(20px + env(safe-area-inset-right));
  padding-bottom:13px;
}
.buybar{
  padding-bottom:calc(10px + env(safe-area-inset-bottom));
  padding-left:calc(16px + env(safe-area-inset-left));
  padding-right:calc(16px + env(safe-area-inset-right));
}
main{padding-bottom:calc(86px + env(safe-area-inset-bottom))}

/* El botón "All" del riel. Sin gachapón: no es una máquina, es quitar el
   filtro, y dibujarle una lo haría parecer una más. */
.unit.all{
  justify-content:center;padding-left:20px;padding-right:20px;
  border:0;font-family:inherit;
}
.unit.all .tag b{color:var(--ink)}
.unit.all.picked .tag b{color:var(--amber)}

/* Todas las unidades son botones ahora. */
button.unit{
  border:0;font-family:inherit;color:inherit;cursor:pointer;
  text-align:left;-webkit-tap-highlight-color:transparent;
}
button.unit:hover{filter:brightness(1.12)}

@media (max-width:700px){
  .rail{
    padding-top:calc(10px + env(safe-area-inset-top));
    padding-bottom:11px;
    padding-left:calc(12px + env(safe-area-inset-left));
    padding-right:calc(12px + env(safe-area-inset-right));
  }
  .buybar{padding-bottom:calc(9px + env(safe-area-inset-bottom))}
  main{padding-bottom:calc(80px + env(safe-area-inset-bottom))}
  .unit.all{padding-left:15px;padding-right:15px;min-width:0}
}
