
  :root{
    --bg:#0a0d13; --panel:#11161f; --panel2:#151c28; --line:#232c3b;
    --ink:#e6ebf2; --muted:#8b96a8; --dim:#5a6478;
    --you:#3fe0a0; --you-dim:#1e6e50; --foe:#d55cff; --foe-dim:#6b2e80;
    --oc:#d55cff; --oc-dim:#6b2e80;   /* violeta del CIFRADO: fijo, no es el color del rival */
    /* LA BANDA «▨ OCULTA» va en VERDE TERMINAL y no en el violeta del velo: en un
       móvil, violeta sobre violeta no se veía («me dicen que cuesta de ver»,
       28-ago). Es un token aparte a propósito — el velo sigue siendo violeta, que
       es la piel cifrada ya aprobada; lo que cambia es solo el aviso de estado, y
       en verde además suena a LA RED informando. */
    --ocb:#3aff6e; --ocb-bg:rgba(58,255,110,.10); --ocb-line:rgba(58,255,110,.38);
    --furia:#d55cff;                 /* el magenta de FURIA: fijo, ver header h1 span */
    --logo:var(--you);               /* el logo nace VERDE (ver historia.js · pintaLogo) */
    --amber:#ffc65c; --blue:#4a9dff; --red:#ff6b52;
    /* colores de ACCIÓN: el qué, no el quién */
    --rcont:#ff8c3b; --rcuar:#58b0ff; --rmut:#ffd84a;
    --mono:ui-monospace,"Cascadia Mono","JetBrains Mono",Menlo,Consolas,monospace;
    /* paleta de ARENA (canvas) — la lee render.js; cambia con el tema */
    --ar-bg:#070a10; --ar-grid:74,157,255; --ar-ink:#ffffff; --ar-ground:rgba(35,44,59,.9);
    --ar-hex:#cfd7e4; --ar-star-hi:#d2ddf2; --ar-star-lo:#9db2dc;
  }
  /* ══ TEMA CLARO (toggle en Configuración): mismos tokens, valores claros ══ */
  .claro{
    --bg:#eef1f8; --panel:#ffffff; --panel2:#f3f6fc; --line:#dde3ef;
    --ink:#1c2333; --muted:#5b6579; --dim:#93a0b5;
    --you:#0aa876; --you-dim:#8fdec2; --foe:#b13be0; --foe-dim:#dcaef0;
    --oc:#8a1fb5; --oc-dim:#c98fe0;
    /* en claro el fósforo desaparece: verde oscuro y fondo apenas teñido */
    --ocb:#0a7a3c; --ocb-bg:rgba(10,122,60,.12); --ocb-line:rgba(10,122,60,.42);
    --furia:#b13be0; --logo:var(--you);
    --amber:#d98f00; --blue:#2b7fe8; --red:#e04f38;
    --rcont:#f07316; --rcuar:#2b7fe8; --rmut:#d9a800;
    --mono:'Segoe UI',system-ui,-apple-system,Roboto,'Helvetica Neue',sans-serif;
    --ar-bg:#e7ebf5; --ar-grid:43,98,201; --ar-ink:#33415e; --ar-ground:rgba(28,35,51,.18);
    --ar-hex:#41506e; --ar-star-hi:#3a4a6a; --ar-star-lo:#5b6a8a;
  }
  .claro *{ text-shadow:none !important }
  .claro .stage{ background:#e7ebf5; border-color:transparent; box-shadow:0 6px 24px rgba(28,35,51,.10); border-radius:16px }
  .claro .slot{ background:rgba(255,255,255,.85) }
  .claro #vDelta b{ background:rgba(255,255,255,.96) }
  .claro .overlay{ background:rgba(233,237,246,.92) }
  .claro #pixgrid .px{ background:#e6ebf4 }
  .claro #pixgrid .px.bm{ background:#fdf3d8 }
  .claro #pixgrid .px.bc{ background:#ffe9d6 }
  .claro #pixgrid .px.bq{ background:#dcf2fd }
  .claro button, .claro .card, .claro .slot, .claro .box, .claro .bar, .claro #stepPanel, .claro .ccard{ border-radius:14px }
  .claro .card{ box-shadow:0 2px 10px rgba(28,35,51,.07) }
  .claro .card[aria-pressed="true"]{ box-shadow:0 6px 18px rgba(10,168,118,.25) }
  .claro #go{ box-shadow:0 6px 18px rgba(10,168,118,.30); border:0 }
  .claro #go:disabled{ box-shadow:none; background:var(--panel2) }
  .claro #again{ box-shadow:0 6px 18px rgba(10,168,118,.30); border:0 }
  .claro .ccard{ box-shadow:0 4px 14px rgba(28,35,51,.12); border-color:transparent }
  .claro .box{ box-shadow:0 10px 40px rgba(28,35,51,.18); border-color:transparent }
  .claro header h1 span{ color:var(--you) }
  .claro body.furia-revelada header h1 span{ color:var(--furia) }
  .claro .bar{ background:#e3e8f2; border-color:transparent }
  .claro .card.oc{
    background:
      repeating-linear-gradient(0deg, rgba(177,59,224,.13) 0 1px, transparent 1px 3px),
      repeating-conic-gradient(from 0deg at 50% 50%, rgba(177,59,224,.07) 0% 25%, transparent 0% 50%) 0 0/7px 7px,
      linear-gradient(160deg, rgba(226,208,246,.50), rgba(240,232,250,.36)) }
  .claro .card.oc::after{ background:rgba(177,59,224,.035) }
  .claro .card.oc .note b{ background:rgba(255,255,255,.66) }
  .claro .cifra .band{ background:var(--ocb-bg) }
  .claro .fxfull span{ background:rgba(255,255,255,.94); border-color:#ecd9a6 }
  .claro #go{ background:linear-gradient(180deg,#13c286,#0aa06b); color:#fff }
  .claro #again{ background:linear-gradient(180deg,#13c286,#0aa06b); color:#fff }
  .claro .modes button[aria-pressed="true"]{ background:#fff6df }
  .claro .targets button[aria-pressed="true"]{ background:#fff3d6 }
  /* legibilidad en claro: textos de acento y bordes de caja */
  .claro .cfgTog{ color:#0a7a55; border-color:#8fdec2; background:#eefaf5 }
  .claro .cfgTog.off{ color:var(--dim); border-color:var(--line); background:var(--panel2) }
  .claro .langBtn.on{ color:#0a7a55; border-color:#0aa876 }
  .claro .cards.haspick .card[aria-pressed="false"]{ opacity:.66; filter:saturate(.8) }
  .claro .card:disabled{ opacity:.66 }
  .claro .card:disabled .note b, .claro .cards.haspick .card[aria-pressed="false"] .note b{ background:rgba(255,255,255,.82) }
  .claro .card .cname{ color:var(--ink) }
  .claro .spiritCard{ border-color:#c7d2e6; box-shadow:0 2px 12px rgba(28,35,51,.06) }
  .claro .playCta{ border-color:#0aa876; box-shadow:0 4px 16px rgba(10,168,118,.18) }
  .claro .pillar{ border-color:#c7d2e6; box-shadow:0 2px 10px rgba(28,35,51,.05) }
  .claro #stageCap{ color:var(--ink) }
  .claro .card .r, .claro .card .n, .claro .card .m, .claro .card .v, .claro .card .encN,
  .claro .ccard .n, .claro .ccard .encN{ color:var(--ink) }
  /* legibilidad del contenido de la carta en claro: rol, número, chips, habilidad */
  .claro .card.rc-cont .role, .claro .card.rc-cont .num{ color:#c85a10 }
  .claro .card.rc-cuar .role, .claro .card.rc-cuar .num{ color:#1a5fb8 }
  .claro .card.rc-mut  .role, .claro .card.rc-mut  .num{ color:#9a7500 }
  .claro .card .abil{ color:#9a7500; opacity:1 }
  .claro .card .dom{ color:#5b6579 }
  .claro .card .note .ng{ color:#5b6579; border-color:#c7d2e6 }
  .claro .card .note .online{ color:#0a7a55; border-color:#0aa876 }
  .claro .card .note .ne, .claro .card .note .nab{ color:#9a7500; border-color:#d9a800 }
  .claro .card .note .combo-b{ color:#0a5b7a; border-color:#2c8cb0; background:rgba(10,120,160,.10) }
  .claro .targets button{ color:var(--ink) }
  *{box-sizing:border-box;margin:0;padding:0}
  html,body{background:var(--bg);color:var(--ink);font-family:var(--mono);
    -webkit-font-smoothing:antialiased}
  /* PWA: sin pull-to-refresh — el gesto de arrastrar hacia abajo recargaba
     la app y mataba la partida en curso. No afecta al scroll normal. */
  html,body{overscroll-behavior-y:none}
  body{min-height:100dvh;display:flex;flex-direction:column;align-items:center}
  button{font-family:var(--mono);color:var(--ink);background:var(--panel2);
    border:1px solid var(--line);border-radius:6px;cursor:pointer}
  button:focus-visible{outline:2px solid var(--amber);outline-offset:2px}
  button:disabled{opacity:.38;cursor:not-allowed}

  .wrap{width:100%;max-width:980px;padding:14px 12px 28px;display:flex;
    flex-direction:column;gap:12px}

  header{display:flex;align-items:baseline;justify-content:space-between;gap:10px;
    border-bottom:1px solid var(--line);padding-bottom:10px}
  header h1{font-size:20px;letter-spacing:.42em;font-weight:800}
  /* EL LOGO · «FU RIA»: la sílaba de FURIA nace VERDE y solo se vuelve magenta
     cuando la historia ya ha revelado el nombre del acto III (hecho('a3e2'),
     ver historia.js · pintaLogo). Antes tomaba var(--foe), que es el color del
     RIVAL y cambia en cada duelo: el logo salía magenta, cian o verde según con
     quién hubieras peleado la última vez, y parecía aleatorio (reporte 27-ago).
     El magenta es de FURIA y tiene que significar algo cuando llegue. */
  header h1 span{color:var(--you);transition:color 1.2s ease}
  body.furia-revelada header h1 span{color:var(--furia)}
  .sub{color:var(--muted);font-size:11px;letter-spacing:.14em;text-transform:uppercase}
  .btag{font:inherit;font-size:10px;letter-spacing:.08em;color:var(--muted);
    background:var(--panel2);border:1px solid var(--line);border-radius:5px;
    padding:1px 6px;margin-left:6px;cursor:pointer;vertical-align:middle;
    font-variant-numeric:tabular-nums;transition:color .15s,border-color .15s}
  .btag:hover,.btag:focus-visible{color:var(--ink);border-color:var(--you);outline:none}
  .btag.copied{color:var(--you);border-color:var(--you)}

  /* ---------- selección de equipo ---------- */
  #select h2{font-size:15px;margin:6px 0 2px;letter-spacing:.06em}
  #select p.lead{color:var(--muted);font-size:13px;line-height:1.55;max-width:60ch}
  .teams{display:grid;grid-template-columns:repeat(auto-fit,minmax(215px,1fr));gap:10px;margin-top:8px}
  .team{padding:12px;text-align:left;display:flex;flex-direction:column;gap:8px;
    border-radius:8px;transition:border-color .15s, transform .15s;
    min-width:0;overflow:hidden}
  .team:hover{border-color:var(--you);transform:translateY(-2px)}
  .team .tname{font-size:14px;font-weight:800;letter-spacing:.18em}
  .team .sin{color:var(--dim);font-size:10.5px;letter-spacing:.1em;text-transform:uppercase}
  .team .tag{color:var(--muted);font-size:11.5px;line-height:1.45;font-style:italic}
  .trow{display:grid;grid-template-columns:58px 13px minmax(0,1fr) auto;
    gap:2px 7px;align-items:center;font-size:11.5px}
  .trow .role{color:var(--dim);font-size:8.5px;letter-spacing:.05em}
  .trow .tn{min-width:0;display:flex;flex-direction:column;line-height:1.3}
  .trow .tn b{font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .trow .val{font-weight:800;font-size:13px}

  /* chip de naturaleza: azul=quieta rojo=movimiento · relleno=conectada hueco=aislada */
  .nat{width:9px;height:9px;flex:none;border-radius:2px;border:2px solid transparent}
  .nat.q{border-color:var(--blue)} .nat.m{border-color:var(--red)}
  .nat.q.c{background:var(--blue)} .nat.m.c{background:var(--red)}

  /* ---------- combate ---------- */
  #battle{display:none;flex-direction:column;gap:10px}
  /* stretch + .fname{flex:1}: los dos bandos miden lo mismo y el nombre absorbe
     la diferencia, así que BARRAS Y CIFRAS QUEDAN ALINEADAS SIEMPRE. El rival
     tiene una línea más («sin RUIDO»), y reservarle sitio con un min-height fijo
     se rompió cuatro veces seguidas: cada vez que cambiaba un font-size del
     marcador había que recalcular el número a mano. Esto no lleva números. */
  .hud{display:grid;grid-template-columns:1fr auto 1fr;gap:10px;align-items:stretch}
  .fighter{display:flex;flex-direction:column;gap:5px}
  .fname{flex:1}
  .fighter.enemy{text-align:right;align-items:flex-end}
  .fname{font-size:13px;font-weight:800;letter-spacing:.14em}
  .fname .who{color:var(--dim);font-size:9.5px;letter-spacing:.1em;display:block}
  /* debilidad del rival, persistente y compacta (antes vivía en el párrafo) */
  .fname .sinq{display:block;font-size:9px;font-weight:600;color:var(--dim);
    letter-spacing:.08em;margin-top:1px}
  .bar{width:100%;max-width:340px;height:14px;background:var(--panel2);
    border:1px solid var(--line);border-radius:4px;overflow:hidden;position:relative}
  .bar i{position:absolute;inset:0;width:0%;transition:width .45s ease}
  .bar.p i{background:linear-gradient(90deg,var(--foe-dim),var(--foe))}
  .bar.e i{background:linear-gradient(90deg,var(--you-dim),var(--you))}
  .bar b{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
    font-size:9.5px;font-weight:400;letter-spacing:.08em;color:var(--ink);
    text-shadow:0 1px 2px rgba(0,0,0,.8)}
  /* peligro: tu territorio casi colonizado NO debe leerse como "barra completa
     = bien". Aviso rojo que late + trama de riesgo sobre el relleno */
  .bar.danger{border-color:var(--red)}
  .bar.danger i::after{content:'';position:absolute;inset:0;
    background:repeating-linear-gradient(45deg,transparent 0 7px,rgba(0,0,0,.28) 7px 14px)}
  .bar.danger{animation:barDanger 1.05s ease-in-out infinite}
  @keyframes barDanger{0%,100%{box-shadow:0 0 0 1px rgba(255,80,80,.35),0 0 8px rgba(255,70,70,.25)}
    50%{box-shadow:0 0 0 1px rgba(255,80,80,.8),0 0 18px rgba(255,70,70,.6)}}
  .barTag.warn{color:var(--red)!important;font-weight:700}
  /* FURIA B · inestabilidad estructural: la barra late en ámbar mientras carga FURIA */
  .bar.inst{border-color:var(--amber);animation:barInst 1.2s ease-in-out infinite}
  @keyframes barInst{0%,100%{box-shadow:0 0 0 1px rgba(255,198,92,.3),0 0 6px rgba(255,198,92,.2)}
    50%{box-shadow:0 0 0 1px rgba(255,198,92,.75),0 0 16px rgba(255,198,92,.5)}}
  @media (prefers-reduced-motion:reduce){ .bar.danger,.bar.inst{animation:none} }
  .meta{font-size:11px;color:var(--muted);display:flex;gap:12px}
  .fighter.enemy .meta{flex-direction:row-reverse}
  .meta .en{color:var(--amber)}
  .nucleo{display:none;gap:3px}
  .nucleo.on{display:flex}
  .nucleo s{width:10px;height:10px;border:1px solid var(--amber);border-radius:2px;text-decoration:none}
  .nucleo s.lost{background:var(--foe);border-color:var(--foe)}
  .turno{align-self:center;text-align:center;color:var(--dim);font-size:10px;
    letter-spacing:.18em;text-transform:uppercase;padding-top:3px;line-height:1.8}
  .turno b{display:block;color:var(--ink);font-size:16px}

  .stage{position:relative;border:1px solid var(--line);border-radius:8px;overflow:hidden;
    background:#070a10}
  canvas{display:block;width:100%;height:auto}
  .scan{position:absolute;inset:0;pointer-events:none;opacity:.5;
    background:repeating-linear-gradient(0deg,transparent 0 2px,rgba(0,0,0,.16) 2px 3px)}
  .flashfx{position:absolute;inset:0;pointer-events:none;opacity:0;
    background:radial-gradient(circle at center, rgba(255,255,255,.3), transparent 62%)}
  .flashfx.on{animation:flashk .32s ease-out}
  @keyframes flashk{from{opacity:1}to{opacity:0}}
  /* capa de enlaces módulo↔ciberspírit (cables reales, no roba clics) */
  #linkfx{position:fixed;inset:0;pointer-events:none;z-index:4;display:none}
  #linkfx.on{display:block}
  /* CHASIS: canvas detrás de las cartas. Las cartas DOM (texto+botones) encima */
  .cardbay{position:relative}
  #chassisfx{position:absolute;left:-9px;top:-9px;pointer-events:none;z-index:0;display:none}
  #chassisfx.on{display:block}
  .cardbay .cards{position:relative;z-index:1}

  /* ═══ BANDA DE INTELIGENCIA RIVAL ══════════════════════════════════════════
     Tres ranuras fijas en el orden CONTAGIO · CUARENTENA · MUTACIÓN, y no se
     mueven al revelarse: la POSICIÓN es lo que enseña cuál es cuál, así que el
     nombre del rol no gasta ancho (decisión de Andreu, 28-ago).

     Antes eran tres chips en absolute sobre la arena, compartiendo su primera fila
     con «TURNO n/14»: 257px para tres ranuras, texto de 9px y el rango a 7,38px.
     Medido a 360px: ocupaban el 59% del ancho y no se leían. Ahora la banda tiene
     fila propia (332px útiles a 360) y el ancho se reparte: las desconocidas se
     quedan en su mínimo y las reveladas se lo llevan. */
  .arenaHead{display:flex;flex-direction:column;gap:5px;margin:0 0 6px}
  .arenaHead #stageCap{position:static;padding:0}
  .slots{display:flex;gap:6px;align-items:stretch}
  .slots.e{width:100%}
  /* los del jugador siguen dentro de la arena (en móvil están ocultos) */
  .slots.l{position:absolute;top:8px;left:8px}

  .slot{position:relative;display:flex;align-items:center;gap:7px;
    font-size:9px;letter-spacing:.06em;color:var(--muted);
    background:rgba(10,13,19,.82);border:1px solid var(--line);border-radius:5px;
    padding:4px 7px;text-align:left;font-family:inherit;
    /* el ancho es lo que cambia al revelarse, y ese movimiento ES la animación:
       la desconocida se queda en lo justo y la revelada se estira */
    flex:0 0 auto; min-width:0; transition:flex-grow .28s ease, background .2s}
  .slots.e .slot.known{flex:1 1 0}
  .slot .rl{font-size:14px;font-weight:800;line-height:1;flex:0 0 auto}
  /* LOS DATOS envuelven si el ancho aprieta: con tres reveladas la naturaleza baja
     a una segunda línea en vez de recortarse o desbordar */
  .slot .dat{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 6px;min-width:0}
  .slot .pot{font-size:13.5px;font-weight:800;color:var(--ink);font-variant-numeric:tabular-nums}
  .slot .int{font-size:12.5px;font-weight:700;color:var(--amber);font-variant-numeric:tabular-nums}
  .slot .sep{color:var(--dim);font-size:11px}
  .slot.unknown{color:var(--dim)}
  .slot.unknown .qm{font-size:14px;font-weight:800;color:var(--dim);line-height:1}
  /* ROTA · atenuada y con la letra tachada, pero en su sitio y consultable: lo que
     se destruyó es la Forma, no lo que el jugador aprendió de ella. */
  .slot.broken{opacity:.5}
  .slot.broken .rl{text-decoration:line-through}
  .slot .pot.rota{color:var(--dim);font-weight:700}
  /* y su borde vuelve al neutro: una rota no está EN LÍNEA ni puede romperse más */
  .slots.e .slot.broken{border-color:var(--line);box-shadow:none}

  /* DEVORADA · la identidad de la ranura NO cambia (sigue siendo su letra y su
     color); lo que cambió es su comportamiento, y eso se dice aquí. En rojo porque
     es una configuración ilegal, no una ventaja. */
  /* 10.5px como la naturaleza: a 9px se leía como parte de ella y no como el aviso
     que es. No añade línea, porque ocupa el hueco que le cede el rango. */
  .slot .devx{font-style:normal;font-size:10.5px;font-weight:800;letter-spacing:.06em;
    color:var(--red,#ff5c5c);white-space:nowrap;
    animation:devPulse 1.1s steps(1) infinite}
  @media (prefers-reduced-motion:reduce){ .slot .devx{animation:none} }
  .slots.e .slot.dev{border-color:var(--red,#ff5c5c);border-style:dashed}
  .slots.e .slot.showprops .sdrota{font-style:normal;font-size:8.5px;font-weight:800;
    letter-spacing:.12em;color:var(--red,#ff5c5c);white-space:nowrap}
  /* A1·E6 · rol DEVORADO: la ilegalidad se lleva puesta todo el duelo, pero SIN
     pintar el texto entero de rojo — eso borraba el color del rol, que es la
     identidad de la ranura (revisión con Codex, 28-ago). */
  .slot.dev{border-color:var(--red,#ff5c5c);border-style:dashed}
  @keyframes devPulse{50%{opacity:.25}}
  @media (prefers-reduced-motion:reduce){ .slot.dev i{animation:none} }
  #reloj{position:relative;height:22px;border:1px solid var(--line);border-radius:11px;
    background:#0c111a;overflow:hidden;align-items:center;justify-content:center;margin:0 auto 7px;max-width:360px}
  #reloj i{position:absolute;left:0;top:0;bottom:0;opacity:.5;
    background:linear-gradient(90deg,var(--you-dim),var(--you))}
  #reloj b{position:relative;font-size:12px;font-weight:800;letter-spacing:.1em;color:var(--ink);
    font-variant-numeric:tabular-nums}
  #reloj.urge i{background:linear-gradient(90deg,#7a2a1e,var(--red))}
  #reloj.urge b{color:#fff}
  /* EN LÍNEA vive en el BORDE y en el indicador de nivel, no en todo el texto:
     antes `color:var(--amber)` en el chip entero borraba la identidad del rol y una
     Forma expuesta se leía igual fuera cual fuera (petición de Andreu, 28-ago). */
  .slot.exp{border-color:var(--amber);box-shadow:0 0 7px rgba(255,198,92,.45)}
  .slot .expd{color:var(--amber);font-style:normal;animation:expPulse 1.3s ease-in-out infinite}
  @keyframes expPulse{0%,100%{opacity:.4}50%{opacity:1}}
  @media (prefers-reduced-motion:reduce){ .slot .expd{animation:none;opacity:.9} }

  /* --- el choque del turno: panel propio BAJO la arena (nunca la tapa) --- */
  .clash{display:flex;justify-content:center;align-items:flex-start;gap:12px;
    pointer-events:none;opacity:0;height:0;margin:0;overflow:hidden;
    transition:opacity .22s}
  .clash.on{opacity:1;height:auto;overflow:visible;margin-top:8px}
  /* los módulos jugados SUBEN de la reserva a la zona de resolución */
  .ccard{width:152px;background:
      radial-gradient(rgba(255,255,255,.04) 1px,transparent 1px) 0 0/9px 9px,
      linear-gradient(180deg,var(--panel2),var(--bg));
    border:1px solid var(--line);
    box-shadow:inset 0 0 0 1px rgba(255,255,255,.05),0 4px 12px rgba(0,0,0,.4);
    border-radius:8px;padding:9px 11px;display:flex;flex-direction:column;gap:3px;
    opacity:0;transform:translateY(30px) scale(.9);
    transition:transform .28s cubic-bezier(.2,1.3,.35,1), opacity .2s}
  .ccard.foeC{transition-delay:.06s}
  .clash.on .ccard{opacity:1;transform:translateY(0) scale(1)}
  .ccard .r{font-size:8.5px;color:var(--dim);letter-spacing:.14em}
  .ccard .n{font-size:12px;font-weight:800;display:flex;gap:6px;align-items:center;
    overflow-wrap:anywhere;min-width:0}
  .ccard .b{display:flex;justify-content:space-between;align-items:baseline}
  .ccard .v{font-size:20px;font-weight:800}
  .ccard .m{font-size:8.5px;letter-spacing:.1em;color:var(--amber)}
  .ccard.mine{border-color:var(--you-dim)}
  .ccard.enc{border-color:var(--foe-dim)}
  .ccard.enc .n{color:var(--foe);font-weight:400}
  .ccard .encN{display:block;white-space:nowrap;overflow:hidden;letter-spacing:.05em}
  .csep{display:block;height:1px;background:var(--line);margin:6px 0}
  /* oculto de verdad: sin .show no ocupa sitio (las cartas centran solas) */
  .verdict{max-width:300px;min-width:170px;text-align:center;padding-top:8px;
    display:none}
  .verdict.show{display:block;animation:vIn .25s ease both}
  @keyframes vIn{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
  .verdict b{display:block;font-size:15px;letter-spacing:.06em;line-height:1.35;
    text-wrap:balance;text-shadow:0 2px 10px rgba(0,0,0,.9)}
  .verdict span{display:block;font-size:10.5px;color:var(--muted);margin-top:4px;line-height:1.5;
    text-shadow:0 1px 6px rgba(0,0,0,.9)}
  .verdict.good>b{color:var(--you)} .verdict.bad>b{color:var(--foe)} .verdict.mix>b{color:var(--amber)}
  #vMatch{display:block;font-size:9.5px;color:var(--dim);letter-spacing:.14em;
    font-style:normal;margin-bottom:3px;text-shadow:0 1px 6px rgba(0,0,0,.9)}
  #vDelta{display:flex;gap:6px;justify-content:center;margin:7px 0 2px;flex-wrap:wrap}
  #vDelta b{font-size:14px;padding:3px 10px;border-radius:5px;
    background:rgba(10,13,19,.92);animation:pillPop .28s cubic-bezier(.2,1.6,.4,1)}
  #vDelta b.you{color:var(--you);border:1px solid var(--you-dim)}
  #vDelta b.foe{color:var(--foe);border:1px solid var(--foe-dim)}
  #vDelta b.amb{color:var(--amber);border:1px solid #5c4d22}
  @keyframes pillPop{from{transform:scale(.4);opacity:0}to{transform:scale(1);opacity:1}}
  #vChips{margin-top:7px}
  /* resumen compacto de efectos: una línea escaneable */
  .fxsum{display:flex;flex-wrap:wrap;gap:5px 9px;justify-content:center;align-items:baseline;
    font-size:10.5px;color:var(--amber);letter-spacing:.05em;line-height:1.5;
    text-shadow:0 1px 6px rgba(0,0,0,.9);animation:pillPop .25s ease-out}
  .fxdet{font-size:8.5px;color:var(--dim);border:1px solid var(--line);border-radius:4px;
    padding:2px 7px;background:transparent;cursor:pointer;letter-spacing:.08em;
    text-transform:uppercase;font-family:var(--mono)}
  .fxdet:hover{color:var(--ink);border-color:var(--muted)}
  /* desglose completo (plegado por defecto) */
  .fxfull[hidden]{display:none}   /* gana a display:flex: si está plegado, NO ocupa */
  .fxfull{display:flex;flex-direction:column;gap:4px;margin-top:6px;align-items:center}
  .fxfull span{display:flex;flex-direction:column;gap:1px;text-align:center;
    background:rgba(10,13,19,.88);
    border:1px solid #443a20;border-radius:4px;padding:4px 10px;max-width:310px}
  .fxfull span b{font-size:10.5px;color:var(--amber);letter-spacing:.06em}
  .fxfull span i{font-size:9.5px;color:var(--muted);font-style:normal}
  .bar.hitp{animation:barHit .55s ease-out}
  @keyframes barHit{0%{filter:brightness(2.4)}100%{filter:none}}

  .hist{display:flex;gap:5px;flex-wrap:wrap;font-size:8.5px;color:var(--dim);opacity:.85}
  .hist span{border:1px solid var(--line);border-radius:3px;padding:2px 6px;background:var(--panel)}
  .hist b{font-weight:800}
  .hist b.you{color:var(--you)} .hist b.foe{color:var(--foe)}

  .log{background:transparent;border:0;border-radius:0;
    padding:0 4px;min-height:36px;display:flex;flex-direction:column;gap:4px}
  .log.empty{min-height:0;padding:0}   /* tras la intro se colapsa: gana sitio */
  .log p{font-size:12px;line-height:1.5;color:var(--muted)}
  .log p.now{color:var(--ink)}
  .log p .flav{color:var(--amber);font-style:italic}

  /* ══ LA CAUSA DEL CHOQUE ══════════════════════════════════════════════════
     Visible SIN desplegar: es la respuesta a «¿por qué solo 1 de daño?». Una
     línea por dirección del daño, y nada si no hubo nada que explicar. */
  .causa{font-size:11px;line-height:1.45;margin:2px 0;color:var(--ink);opacity:.92}
  .causa b{font-weight:800;letter-spacing:.04em;color:var(--dim);margin-right:5px;
    font-size:9.5px}
  .causa.mia b{color:var(--cyan)}
  /* el desglose, en tres columnas: delta · causa · valor tras aplicarla.
     Va en el ORDEN REAL del motor, que no es el intuitivo. */
  .pasos{display:grid;grid-template-columns:auto 1fr auto;gap:1px 8px;
    font-size:11px;margin:4px 0 8px}
  .pasos span{display:grid;grid-template-columns:subgrid;grid-column:1/-1;
    align-items:baseline}
  .pasos i{font-style:normal;font-variant-numeric:tabular-nums;text-align:right;
    color:var(--amber);font-weight:700}
  .pasos b{font-weight:600;color:var(--ink);opacity:.9}
  .pasos u{text-decoration:none;font-variant-numeric:tabular-nums;color:var(--dim)}
  /* el instante en que aprendes una naturaleza: presencia, sin modal */
  .idnat{display:flex;align-items:baseline;gap:7px;margin:3px 0 5px}
  .idnat b{font-size:13px;font-weight:800;letter-spacing:.08em;color:var(--cyan)}
  .idnat span{font-size:9px;letter-spacing:.1em;color:var(--dim)}
  /* la naturaleza ya identificada, en el chip que ya existía: cuatro letras */
  .slot .natx{font-style:normal;font-size:10.5px;letter-spacing:.05em;
    color:var(--dim);margin-left:3px;opacity:.85}

  .controls{display:flex;flex-direction:column;gap:8px}
  /* ── RESERVA DE MÓDULOS-WEB: las webs de las que está hecho el ciberspírit ── */
  /* minmax(0,1fr): columnas realmente iguales — un dominio largo sin espacios
     (IGUALADATURISME.COM) no puede ensanchar su columna y desbordar la fila */
  .cards{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:9px;align-items:stretch}
  /* el CHASIS (fondo, marco, puertos, telemetría) lo pinta el canvas #chassisfx
     detrás; la carta DOM sólo aporta texto + botones, con fondo transparente */
  .card{padding:11px 10px 20px;text-align:left;display:flex;flex-direction:column;gap:3px;
    position:relative;min-height:106px;border-radius:9px;
    background:transparent;border:0;box-shadow:none;
    transition: transform .13s cubic-bezier(.2,.9,.3,1.35), box-shadow .13s, opacity .13s, filter .13s}
  .card[aria-pressed="true"]{   /* el glow del elegido lo pinta el chasis; aquí solo el «lift» */
    transform:translateY(-9px) scale(1.045);z-index:3}
  /* RECONSTRUIR: botón especial a lo ancho, sin chasis → fondo propio */
  .card.rebbtn{background:rgba(9,12,18,.85);border:1px solid var(--line);border-radius:9px}
  .card.rebbtn[aria-pressed="true"]{border-color:var(--you);box-shadow:0 0 14px rgba(63,224,160,.3)}
  /* las cartas de los extremos se amplían hacia dentro, no fuera de pantalla */
  .cards .card:first-child[aria-pressed="true"]{transform-origin:left center}
  .cards .card:last-child[aria-pressed="true"]{transform-origin:right center}
  .cards.haspick .card[aria-pressed="false"]{opacity:.66;filter:saturate(.7);transform:scale(.97)}
  /* carta en descanso / no elegida: marco atenuado, PERO los sellos de estado
     (EN LÍNEA, motor, ORDEN, YA JUGADA…) se leen igual — fondo sólido + negrita.
     Feedback Andreu (FURIA B): "difuminado sí, pero que los recuadros se vean". */
  .card:disabled{opacity:.66}
  .card:disabled .note b, .cards.haspick .card[aria-pressed="false"] .note b{
    font-weight:700; background:rgba(8,11,18,.82); border-width:1px}
  /* el texto va sobre el chasis (canvas): sombra para contraste garantizado */
  .card .role,.card .cname,.card .num,.card .abil,.card .dom,.card .prop-cost,.card .prop-combo{
    text-shadow:0 1px 3px rgba(0,0,0,.85),0 0 2px rgba(0,0,0,.6)}
  .card .role{font-size:9px;letter-spacing:.16em;color:var(--dim);text-transform:uppercase;
    padding-right:30px;display:inline-flex;align-items:center;gap:5px}   /* deja aire para el número */
  /* puerto de conexión: un pin pequeño junto al rol, del color de la web */
  .card .role::before{content:'';width:5px;height:5px;border-radius:1px;flex:none;
    background:currentColor;opacity:.5;box-shadow:0 0 4px currentColor}
  .card .cname{font-size:12.5px;font-weight:800;display:flex;align-items:center;gap:6px;
    margin-top:1px;padding-right:26px;min-width:0}
  .card .cname .nm{min-width:0;overflow-wrap:anywhere}   /* títulos con espacios: parten por palabra */
  .card .cname .nm.dom1{overflow-wrap:normal;white-space:nowrap;overflow:hidden;
    text-overflow:ellipsis}                              /* dominios: una línea, recorte con … */
  .card .dom{font-size:9.5px;color:var(--dim);font-style:italic;overflow:hidden;
    text-overflow:ellipsis;white-space:nowrap}
  .card .num{position:absolute;right:9px;top:11px;font-size:20px;font-weight:800;line-height:1}
  .card .note{display:flex;flex-wrap:wrap;gap:4px;margin-top:auto;min-height:12px}
  .card .note .ok{color:var(--dim)}
  .card.rc-cont{border-left:3px solid var(--rcont)}
  .card.rc-cuar{border-left:3px solid var(--rcuar)}
  .card.rc-mut{border-left:3px solid var(--rmut)}
  .card.rc-cont .role,.card.rc-cont .num{color:var(--rcont)}
  .card.rc-cuar .role,.card.rc-cuar .num{color:var(--rcuar)}
  .card.rc-mut .role,.card.rc-mut .num{color:var(--rmut)}
  /* ── PROPIEDADES bajo demanda: el módulo-web queda limpio (rol · nombre ·
        valor · sellos) y el dominio + habilidad viven tras el botón ⓘ ── */
  .card .props{display:none;flex-direction:column;gap:3px;margin-top:2px;
    padding-top:6px;border-top:1px dashed var(--line)}
  .card.showprops .props,.card.peek .props{display:flex}
  /* peek (long-press): la carta espiada se ve entera aunque esté atenuada */
  .cards.haspick .card.peek[aria-pressed="false"]{opacity:1;filter:none;transform:none}
  .card.peek{z-index:5}
  .card .abil{font-size:9.5px;color:var(--amber);opacity:.95;line-height:1.4}
  .card .prop-cost{font-size:9px;color:var(--dim);letter-spacing:.06em}
  /* qué hace el combo que la carta anuncia. El sello «◈ BRECHA» solo daba el
     nombre; tocarlo abre esto (en el móvil el ⓘ no cabe y nadie descubre el
     long-press por su cuenta). */
  .card .prop-combo{font-size:9px;color:#7ad7ff;letter-spacing:.05em;line-height:1.4}
  /* los sellos que explican algo se ven pulsables */
  .card .note .xplain{cursor:pointer;text-decoration:underline;
    text-decoration-style:dotted;text-underline-offset:2px}
  .card .propbtn{position:absolute;right:8px;bottom:5px;z-index:3;width:18px;height:18px;
    display:none;align-items:center;justify-content:center;border-radius:50%;
    font-size:11px;line-height:1;color:var(--dim);border:1px solid var(--line);
    background:var(--panel2);cursor:pointer}
  .card[aria-pressed="true"]:not(.oc):not(.rota) .propbtn{display:flex}
  .card.showprops .propbtn{color:var(--ink);border-color:var(--you)}
  /* la pista ↻ VOLTEAR se aparta del botón ⓘ (que sólo sale en abiertas) */
  .cards .card:not(.rebbtn):not(.oc)[aria-pressed="true"]::before{right:30px}
  /* sellos de estado: chips compactos, no frases */
  /* SE PARTEN CUANDO NO CABEN, y solo entonces. Llevaban `white-space:nowrap` porque un
     sello es de una palabra… pero varios no lo son: medido a 320px, «▨ OCULTAR ↻» ocupa
     104px dentro de una caja de 70, y «↻ RECONSTRUIR ⚡4» 112. Con nowrap el texto SALE
     del chip sin ensanchar su caja: ningún elemento excedía el viewport y el documento
     desbordaba 21px a 320 (8 a 360, 3 a 375). Por eso no lo encontraba ningún barrido de
     cajas — el que se salía era el NODO DE TEXTO, que no es un elemento.
     Dejar que se partan no cambia nada donde caben (el salto solo ocurre si no cabe), y
     donde no caben da dos líneas en vez de un desborde del documento. */
  .card .note b{font-size:8px;font-weight:700;letter-spacing:.05em;padding:2px 6px;
    border-radius:4px;border:1px solid currentColor;line-height:1.25;
    max-width:100%;overflow-wrap:anywhere}
  .card .note .nb{color:var(--red)}
  .card .note .ng{color:var(--dim);border-color:var(--line)}
  .card .note .ne{color:var(--amber)}
  /* el PRECIO de la MUTACIÓN (⚡3): clase propia (.n1c) para quedar FUERA de la
     regla que deja un solo estado en la carta sin elegir. Se ve siempre y no
     desplaza al chip que sí cambia turno a turno. Rojo = no llega. */
  .card .note .cost-b{color:var(--amber);border-color:#5c4d22;
    background:rgba(255,198,92,.07);font-variant-numeric:tabular-nums}
  .card .note .cost-b.off{color:var(--red);border-color:var(--red);background:transparent}
  /* poder persistente que da el módulo EN LÍNEA (mismo ✦ ámbar que la resolución) */
  .card .note .nab{color:var(--amber);border-color:#5c4d22;background:rgba(255,198,92,.06);
    font-variant-numeric:tabular-nums}
  /* EN LÍNEA = conectada y ejecutando: chip "vivo" con punto que late (verde) */
  .card .note .online{color:var(--you);border-color:var(--you-dim);
    position:relative;padding-left:15px}
  .card .note .online::before{content:'';position:absolute;left:5px;top:50%;
    transform:translateY(-50%);width:5px;height:5px;border-radius:50%;
    background:var(--you);box-shadow:0 0 5px var(--you);animation:onlinePulse 1.3s ease-in-out infinite}
  @keyframes onlinePulse{0%,100%{opacity:.45}50%{opacity:1}}
  @media (prefers-reduced-motion:reduce){ .card .note .online::before{animation:none} }
  /* FURIA B · motor escalable: el chip EN LÍNEA muestra I/II/III; SATURADO = caliente */
  .card .note .online.sat{color:var(--foe);border-color:var(--foe-dim);font-weight:700;letter-spacing:.04em}
  .card .note .online.sat::before{background:var(--foe);box-shadow:0 0 8px var(--foe);animation-duration:.6s}
  .card .note .nab.sat{color:#ff5ca8;border-color:#7c2450;background:rgba(255,92,168,.1)}
  /* H3 · combo disponible: este rol encadena con el anterior (destaca en cian) */
  .card .note .combo-b{color:#7ad7ff;border-color:#2c6d8c;background:rgba(122,215,255,.12);
    font-weight:700;letter-spacing:.03em;animation:comboPulse 1.4s ease-in-out infinite}
  @keyframes comboPulse{0%,100%{box-shadow:0 0 0 rgba(122,215,255,0)}50%{box-shadow:0 0 7px rgba(122,215,255,.5)}}
  .card .note .combo-b.furia-x2{color:#ffd23a;border-color:#8a6a00;background:rgba(255,210,58,.14)}
  @keyframes comboPulseX2{0%,100%{box-shadow:0 0 0 rgba(255,210,58,0)}50%{box-shadow:0 0 8px rgba(255,210,58,.6)}}
  .card .note .combo-b.furia-x2{animation:comboPulseX2 1s ease-in-out infinite}
  @media (prefers-reduced-motion:reduce){ .card .note .combo-b{animation:none} }
  /* el rango estaba a .82em de 9px = 7,38px: ilegible en un móvil */
  .slot .mlv{font-style:normal;font-weight:800;color:var(--amber);font-size:10.5px;
    letter-spacing:.06em}
  /* FURIA B · rango de la web (techo de motor = anillos·fama). En bruto = sin motor. */
  .card .note .rango-b{color:var(--amber);border-color:#5c4d22;letter-spacing:1px;font-size:9px}
  .card .note .rango-b.bruto{color:var(--dim);border-color:var(--line);letter-spacing:.04em}
  .card .repl-btn{align-self:flex-start;margin-top:4px;padding:3px 8px;font-size:9px;
    letter-spacing:.05em;border:1px solid var(--amber);border-radius:5px;color:var(--amber);
    background:rgba(255,198,92,.08);cursor:pointer}
  .card .repl-btn.on{background:var(--amber);color:#1a1305;font-weight:700}
  .card .conc-btn{align-self:flex-start;margin-top:4px;padding:3px 8px;font-size:9px;letter-spacing:.05em;
    border:1px solid var(--rmut);border-radius:5px;color:var(--rmut);background:rgba(255,216,74,.10);cursor:pointer;font-weight:700}
  .card .asc-btn{align-self:flex-start;margin-top:4px;padding:3px 8px;font-size:9px;letter-spacing:.05em;
    border:1px solid var(--good,#5fe0a8);border-radius:5px;color:var(--good,#5fe0a8);background:rgba(95,224,168,.10);
    cursor:pointer;font-weight:700;animation:ascpulse 1.6s ease-in-out infinite}
  @keyframes ascpulse{0%,100%{box-shadow:0 0 0 0 rgba(95,224,168,0)}50%{box-shadow:0 0 8px 1px rgba(95,224,168,.45)}}

  /* ── LA RED = la pantalla de la IA: aire de terminal CRT (biblia C1) ── */
  @font-face{font-family:'VT323';src:url('vt323.woff2') format('woff2');font-display:swap}
  #lared{position:relative}
  #lared::after{content:'';position:fixed;inset:0;pointer-events:none;z-index:8;
    background:repeating-linear-gradient(0deg, rgba(0,0,0,.13) 0 2px, transparent 2px 4px)}
  #lared h2{font-family:'VT323',var(--mono);letter-spacing:.05em;color:#3aff6e;
    text-shadow:0 0 8px rgba(58,255,110,.55)}
  #lared h2::before{content:'▚ RED NEURONAL // ÍNDICE';display:block;font-size:11px;
    letter-spacing:.28em;color:#1e8f45;margin-bottom:2px}
  #lared h2 #redInfoBtn{vertical-align:3px;margin-left:8px;border-color:#1e8f45;color:#3aff6e;
    font-family:var(--sans);font-size:12px;padding:2px 9px;border-radius:50%}
  /* banda de refresco CRT bajando (solo atmósfera: pointer-events none) */
  #lared::before{content:'';position:fixed;left:0;right:0;height:90px;pointer-events:none;z-index:8;
    background:linear-gradient(180deg, transparent, rgba(58,255,110,.05) 45%, rgba(58,255,110,.085) 50%, rgba(58,255,110,.05) 55%, transparent);
    animation:laredroll 7s linear infinite}
  @keyframes laredroll{0%{top:-12%}100%{top:112%}}
  body.reduce-fx #lared::before{display:none}
  /* cromo en verde terminal (los DATOS — tarjetas y sectores — conservan su color) */
  #lared #redResumen{font-family:'VT323',var(--mono);font-size:17px;color:#1e8f45;letter-spacing:.04em}
  #lared #redResumen b{color:#3aff6e}
  #lared .tbtns button{font-family:'VT323',var(--mono);letter-spacing:.08em;background:transparent;
    border:1px solid #1e8f45;color:#3aff6e;text-shadow:0 0 6px rgba(58,255,110,.45)}
  #lared .tbtns #toMired{border-color:#3aff6e;font-size:19px;
    box-shadow:0 0 12px rgba(58,255,110,.15), inset 0 0 12px rgba(58,255,110,.06)}
  #lared #buscaMsg{font-family:'VT323',var(--mono);color:#3aff6e}
  /* listado tipo `ls`: una línea por web, coloreada por naturaleza (como ls por tipo) */
  #lared .sgrid, #mired .sgrid{display:flex;flex-direction:column;gap:1px}
  #lared .wls, #mired .wls{display:flex;align-items:baseline;gap:10px;width:100%;background:transparent;
    border:0;border-left:2px solid transparent;padding:3px 8px;text-align:left;cursor:pointer;
    font-family:'VT323',var(--mono);font-size:19px;letter-spacing:.02em;color:var(--ink)}
  #lared .wls:active,#lared .wls:hover,
  #mired .wls:active,#mired .wls:hover{background:rgba(58,255,110,.06);border-left-color:var(--sc)}
  #lared .wls .st{flex:0 0 48px;color:var(--amber);font-size:17px}
  #mired .wls .st{flex:0 0 22px;color:var(--amber);font-size:17px}
  #lared .wls .st .ok, #mired .wls .st .ok{color:#3aff6e}
  #lared .wls .st .gr{color:#3aff6e;letter-spacing:.06em}
  /* ENLACE EN CURSO (018): la fila lo canta desde la lista, con su cuenta atrás
     bajando de verdad. El ◈ late mientras el canal está abierto. */
  #lared .wls .st .sinc{color:var(--amber);animation:sincLate 1.6s ease-in-out infinite}
  @keyframes sincLate{0%,100%{opacity:.45}50%{opacity:1}}
  @media (prefers-reduced-motion:reduce){ #lared .wls .st .sinc{animation:none} }
  #lared .wls .sincT{margin-left:auto;font-size:14px;color:var(--amber);
    font-variant-numeric:tabular-nums;letter-spacing:.04em}
  #lared .wls .sincT.listo{color:#3aff6e;font-weight:800;letter-spacing:.12em}
  #lared .wls.far .st{color:var(--faint)}
  #lared .wls.far .dom{opacity:.55}
  #lared .wls .dom, #mired .wls .dom{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;
    white-space:nowrap;color:var(--sc,#e8eef7)}
  #lared .wls.cap .dom{text-shadow:0 0 7px color-mix(in srgb,var(--sc) 55%,transparent)}
  #lared .wls .stx, #mired .wls .stx{color:var(--faint);font-size:16px}
  #lared .wls .pip, #mired .wls .pip{color:#3aff6e;font-size:13px}
  #lared .sector .shead .sname,
  #mired .sector .shead .sname{font-family:'VT323',var(--mono);font-size:20px;letter-spacing:.05em}

  /* ── MI RED: mismo lenguaje terminal que LA RED (biblia C1) ── */
  #mired{position:relative}
  #mired::after{content:'';position:fixed;inset:0;pointer-events:none;z-index:8;
    background:repeating-linear-gradient(0deg, rgba(0,0,0,.13) 0 2px, transparent 2px 4px)}
  #mired::before{content:'';position:fixed;left:0;right:0;height:90px;pointer-events:none;z-index:8;
    background:linear-gradient(180deg, transparent, rgba(58,255,110,.05) 45%, rgba(58,255,110,.085) 50%, rgba(58,255,110,.05) 55%, transparent);
    animation:laredroll 7s linear infinite}
  body.reduce-fx #mired::before{display:none}
  #mired h2{font-family:'VT323',var(--mono);letter-spacing:.05em;color:#3aff6e;
    text-shadow:0 0 8px rgba(58,255,110,.55)}
  #mired h2::before{content:'▚ RED NEURONAL // TEJEDOR';display:block;font-size:11px;
    letter-spacing:.28em;color:#1e8f45;margin-bottom:2px}
  #mired h2 #miredInfoBtn{vertical-align:3px;margin-left:8px;border-color:#1e8f45;color:#3aff6e;
    font-family:var(--sans);font-size:12px;padding:2px 9px;border-radius:50%}
  /* ── LA REJILLA Y SU PREVISUALIZACIÓN ──────────────────────────────────────
     En móvil, una columna: la rejilla arriba y el Tejido debajo. Desde 900px, en FILA:
     en PC sobra sitio a la derecha y el Tejido se veía diminuto dentro de una caja
     enorme y vacía (captura de Andreu, 2-sep). El motor no calca la silueta, la usa para
     esculpir, así que esta previsualización es lo único que conecta trazo y resultado —
     verla pequeña la hace inútil. */
  /* un pie vacío no deja hueco: `editor.bands` se vació al retirar las tres franjas */
  #editor .hint2:empty{display:none}
  #editor .avRow{display:flex;flex-direction:column;align-items:center;gap:10px}
  #editor .avCol{display:flex;flex-direction:column;align-items:center;gap:6px;min-width:0}
  #editor .avPrev{display:flex;flex-direction:column;align-items:center;gap:6px;
    padding:10px;border:1px dashed #233043;border-radius:8px}
  /* el lienzo se dibuja a 216×288 y se MUESTRA más pequeño en móvil: así el trazo del
     genoma sale nítido en las dos (bajar de resolución se ve bien; subirla, no) */
  #editor .avPrev canvas{width:108px;height:144px}
  #editor .avPrevLbl{font-family:ui-sans-serif,system-ui,sans-serif;font-size:11px;
    color:var(--dim);max-width:160px;line-height:1.35;text-align:center}
  @media (min-width:900px){
    #editor .avRow{flex-direction:row;align-items:flex-start;justify-content:center;gap:22px}
    #editor .avPrev canvas{width:216px;height:288px}
    #editor .avPrevLbl{max-width:216px}
  }
  /* el control del núcleo, bajo la previsualización de MI RED. Pequeño y permanente:
     no dibujar es un estado válido, así que ni «pendiente» ni porcentajes. */
  /* el control CABE en la columna del lienzo (72px) y no la ensancha: `width` fijo y
     `min-width:0`, o MI RED desborda a 360px. */
  #mired .mrNuc{display:flex;flex-direction:column;align-items:center;gap:3px;
    margin-top:5px;width:72px;min-width:0}
  #mired .mrNuc .mrNucSt{font-family:'VT323',var(--mono);font-size:12px;letter-spacing:.06em;
    color:var(--dim);text-transform:uppercase;line-height:1}
  #mired .mrNuc button{font-family:var(--mono);font-size:9px;letter-spacing:.04em;
    padding:5px 4px;min-height:30px;width:100%;border:1px solid #233043;border-radius:6px;
    background:transparent;color:var(--ink);cursor:pointer;white-space:nowrap}
  #mired .mrNuc button.on{border-color:#5fe0a8;color:#5fe0a8}
  /* la pista va DEBAJO del cuerpo, a todo el ancho: dentro de la columna la ensanchaba */
  #mired .mrNucHint{font-family:ui-sans-serif,system-ui,sans-serif;font-size:10.5px;
    line-height:1.35;color:var(--dim);text-align:center;margin:6px 0 0}
  #mired .mrNucHint:empty{display:none}
  #mired .budgetLbl{font-family:'VT323',var(--mono);color:#1e8f45;letter-spacing:.14em;font-size:15px}
  #mired .budgetNum{font-family:'VT323',var(--mono);color:#3aff6e;font-size:17px}
  #mired .msLbl{font-family:'VT323',var(--mono);color:#1e8f45;letter-spacing:.14em}
  #mired .tbtns button{font-family:'VT323',var(--mono);letter-spacing:.08em;background:transparent;
    border:1px solid #1e8f45;color:#3aff6e;text-shadow:0 0 6px rgba(58,255,110,.45)}
  #mired .tbtns #miredPlay{border-color:#3aff6e;font-size:19px;
    box-shadow:0 0 12px rgba(58,255,110,.15), inset 0 0 12px rgba(58,255,110,.06)}

  /* ── NÚCLEO COMPROMETIDO: LA RED te habla por su canal (terminal) ── */
  #nucOv .box{background:#020a04;border:1px solid #1e8f45;box-shadow:0 0 44px rgba(58,255,110,.13)}
  #nucOv h3{font-family:'VT323',var(--mono);color:#3aff6e;letter-spacing:.06em;
    text-shadow:0 0 8px rgba(58,255,110,.55)}
  #nucOv h3::before{content:'▚ LA RED · CANAL DIRECTO';display:block;font-size:12px;font-weight:400;
    letter-spacing:.26em;color:#1e8f45;margin-bottom:4px}
  #nucOv .box p{font-family:'VT323',var(--mono);font-size:19px;line-height:1.5;color:#9fdfb4}
  #nucOv .box p strong{color:#3aff6e}
  #nucOv .btns button{font-family:'VT323',var(--mono);letter-spacing:.08em;font-size:17px}
  #nucOv #nucOpen{background:transparent;border:1px solid #3aff6e;color:#3aff6e;
    text-shadow:0 0 7px rgba(58,255,110,.5);box-shadow:0 0 14px rgba(58,255,110,.18)}
  /* …tras la REVELACIÓN, el canal viene interferido: es el color del virus */
  body.furia-vir #nucOv .box{border-color:#8f1e4f;box-shadow:0 0 44px rgba(255,92,168,.15)}
  body.furia-vir #nucOv h3{color:#ff5ca8;text-shadow:0 0 8px rgba(255,92,168,.6)}
  body.furia-vir #nucOv h3::before{content:'▞ CANAL INTERFERIDO';color:#8f1e4f}
  body.furia-vir #nucOv .box p{color:#f3b9d2}
  body.furia-vir #nucOv .box p strong{color:#ff5ca8}
  body.furia-vir #nucOv #nucOpen{border-color:#ff5ca8;color:#ff5ca8;
    text-shadow:0 0 7px rgba(255,92,168,.5);box-shadow:0 0 14px rgba(255,92,168,.2)}

  /* ── MODO FURIA activo: el campo de batalla entra en CRT ── */
  body.furia-crt #battle::after{content:'';position:fixed;inset:0;pointer-events:none;z-index:9;
    background:
      radial-gradient(130% 110% at 50% 40%, rgba(58,255,110,.05), rgba(58,255,110,.11) 100%),
      repeating-linear-gradient(0deg, rgba(0,0,0,.14) 0 2px, transparent 2px 4px)}
  body.furia-crt #battle::before{content:'';position:fixed;left:0;right:0;height:110px;pointer-events:none;z-index:9;
    background:linear-gradient(180deg, transparent, rgba(58,255,110,.05) 45%, rgba(58,255,110,.09) 50%, rgba(58,255,110,.05) 55%, transparent);
    animation:laredroll 5.5s linear infinite}
  /* la verdad tiene otro color: el CRT del virus */
  body.furia-crt.furia-vir #battle::after{background:
      radial-gradient(130% 110% at 50% 40%, rgba(255,92,168,.05), rgba(255,92,168,.12) 100%),
      repeating-linear-gradient(0deg, rgba(0,0,0,.14) 0 2px, transparent 2px 4px)}
  body.furia-crt.furia-vir #battle::before{background:linear-gradient(180deg, transparent,
      rgba(255,92,168,.05) 45%, rgba(255,92,168,.09) 50%, rgba(255,92,168,.05) 55%, transparent)}
  body.reduce-fx #battle::before{display:none}
  #nucOv .nucCur{display:inline-block;width:.55em;height:1em;background:#3aff6e;vertical-align:-2px;
    animation:nuccur .9s steps(1) infinite;box-shadow:0 0 8px rgba(58,255,110,.8)}
  @keyframes nuccur{50%{opacity:0}}
  body.furia-vir #nucOv .nucCur{background:#ff5ca8;box-shadow:0 0 8px rgba(255,92,168,.8)}
  #nucOv .nucRules{font-family:'VT323',var(--mono);font-size:15px;color:#1e8f45;
    letter-spacing:.06em;text-align:center;margin:4px 0 2px}
  body.furia-vir #nucOv .nucRules{color:#8f1e4f}
  #nucOv .btns{transition:opacity .25s}
  #lared #buscaInp{border-color:#1e8f45;background:rgba(2,10,4,.6);color:#b8ffce;
    font-family:'VT323',var(--mono);font-size:17px}
  #lared #buscaInp::placeholder{color:#1e8f45}
  #lared #buscaBtn{border-color:#3aff6e;color:#3aff6e;background:transparent;
    font-family:'VT323',var(--mono);text-shadow:0 0 6px rgba(58,255,110,.5)}
  .redVacia{border:1px dashed #1e8f45;border-radius:10px;padding:26px 18px;margin:18px 0;
    text-align:center;font-family:'VT323',var(--mono)}
  .redVacia .rv1{color:#3aff6e;font-size:22px;letter-spacing:.14em;
    text-shadow:0 0 8px rgba(58,255,110,.55);margin-bottom:10px;animation:trmcur2 1.2s steps(1) infinite}
  @keyframes trmcur2{50%{opacity:.55}}
  .redVacia .rv2{color:var(--dim);font-family:var(--sans,inherit);font-size:14px;line-height:1.6;max-width:40ch;margin:0 auto}
  .redVacia .rv2 b{color:#3aff6e}
  /* ── celebración de ASCENSIÓN: carta dorada + banner central ── */
  .card.ascgold{animation:ascgold 3.2s ease-out;border-color:#ffd84a !important}
  @keyframes ascgold{
    0%{box-shadow:0 0 0 0 rgba(255,216,74,0);filter:brightness(1)}
    10%{box-shadow:0 0 38px 8px rgba(255,216,74,.9);filter:brightness(1.9) saturate(1.4)}
    28%{box-shadow:0 0 22px 4px rgba(255,216,74,.55);filter:brightness(1.25)}
    100%{box-shadow:0 0 0 0 rgba(255,216,74,0);filter:brightness(1)}}
  #ascBanner{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;
    z-index:70;pointer-events:none}
  #ascBanner .ab{display:flex;flex-direction:column;align-items:center;gap:6px;text-align:center;
    font-family:var(--mono,ui-monospace,monospace);animation:ascban 2.5s ease-out forwards}
  #ascBanner .ab1{font-weight:800;font-size:clamp(24px,8vw,44px);letter-spacing:.14em;color:#ffd84a;
    text-shadow:0 0 26px rgba(255,216,74,.9),0 0 60px rgba(255,216,74,.4)}
  #ascBanner .ab2{font-size:clamp(12px,3.4vw,16px);color:#e8eef7;letter-spacing:.06em}
  #ascBanner .ab3{font-size:clamp(13px,3.8vw,18px);font-weight:700;color:#ffd84a;letter-spacing:.3em}
  @keyframes ascban{
    0%{transform:scale(.35);opacity:0}
    12%{transform:scale(1.18);opacity:1}
    22%{transform:scale(1)}
    76%{opacity:1;transform:scale(1)}
    100%{opacity:0;transform:scale(1.06) translateY(-14px)}}
  .card .conc-note{font-size:8px;font-weight:700;letter-spacing:.05em;padding:2px 6px;border-radius:4px;
    border:1px solid var(--rmut);color:var(--rmut);background:rgba(255,216,74,.10);white-space:nowrap;
    animation:pillPop .28s cubic-bezier(.2,1.6,.4,1)}
  .card.replegando{opacity:.72}
  /* ── MÓDULO ROTO: corrupción física, no solo la palabra "ROTA" ── */
  .card.rota{filter:saturate(.2) brightness(.82);border-color:var(--foe-dim);border-style:dashed;
    box-shadow: inset 0 0 0 1px rgba(213,92,255,.22), 0 3px 0 rgba(0,0,0,.4)}
  .card.rota .cname{color:var(--muted);text-decoration:line-through}
  .card.rota .num{color:var(--foe-dim)}
  /* ══ PIEL CIFRADA · MI Forma oculta, sin esconderme nada a mí mismo ══
     Tres intentos. (1) Un velo opaco (::after inset:0 al 95%) que tapaba la
     carta entera: no se veía rol, valor, sellos ni botones. (2) Una piel que
     además CIFRABA el nombre con ████ — pero la bandeja #cards solo muestra las
     cartas del jugador que decide (S.active es S.p, o S.e en 2p tras pasar el
     móvil), así que cifrarlas era esconderme mi propia mano. El cifrado es lo
     que ve el RIVAL, y eso vive en clashCardHTML y en los chips del HUD.

     (3) Lo que hay ahora: la carta normal ENTERA —nombre, dominio, naturaleza,
     valor, integridad, combo, ascender, coste— con un VELO de transmisión
     cifrada encima. El velo va en `background` y no en un ::after opaco a
     propósito: el marco y el color del rol los dibuja drawChassis en un canvas
     DETRÁS, así que un fondo semitransparente lo deja pasar, y el contenido de
     la carta se pinta por encima del fondo sin pelearse por z-index. */
  .card.oc{border-style:dashed;   /* la franja del rol se queda: solo discontinua */
    border-radius:8px;
    background:
      repeating-linear-gradient(0deg, rgba(213,92,255,.085) 0 1px, transparent 1px 3px),
      repeating-conic-gradient(from 0deg at 50% 50%, rgba(213,92,255,.045) 0% 25%, transparent 0% 50%) 0 0/7px 7px,
      linear-gradient(160deg, rgba(46,18,72,.34), rgba(22,11,38,.24))}
  /* interferencia que respira, muy tenue: da vida sin apagar el texto */
  .card.oc::after{content:'';position:absolute;inset:0;z-index:1;pointer-events:none;
    border-radius:8px;background:rgba(213,92,255,.028);
    animation:cifWash 1.9s steps(2) infinite}
  @keyframes cifWash{0%,100%{opacity:.4}50%{opacity:1}}
  /* la banda de estado va justo bajo el rol: se percibe ENCIMA de la ficha */
  .cifra{display:none}
  .card.oc .cifra{display:block;position:relative;z-index:2}
  .cifra .band{display:block;font-size:8px;font-weight:800;letter-spacing:.1em;
    color:var(--ocb);background:var(--ocb-bg);
    border:1px dashed var(--ocb-line);border-radius:4px;
    padding:1px 4px;margin:1px 0 2px;text-align:center;
    white-space:nowrap;overflow:hidden;
    text-shadow:0 0 6px color-mix(in srgb, var(--ocb) 45%, transparent);
    animation:cifBlink 2.6s ease-in-out infinite}
  @keyframes cifBlink{0%,100%{opacity:1}47%{opacity:.6}}
  /* Bajo el velo los textos pequeños perdían legibilidad en móvil. Se les sube
     el contraste en vez de rebajar más el cifrado global (preferencia de Andreu,
     27-ago). Solo afecta a las cartas OCULTAS: la abierta no cambia. */
  .card.oc .cdom{color:var(--muted);opacity:1}          /* dominio */
  .card.oc .note b{background:rgba(8,11,18,.62)}        /* sellos: fondo propio */
  .card.oc .note .ng{color:var(--muted);border-color:var(--muted)}   /* integridad */
  .card.oc .cname .nat{opacity:1;filter:saturate(1.15) brightness(1.1)}  /* naturaleza */
  @media (prefers-reduced-motion:reduce){
    .card.oc::after, .cifra .band{animation:none} }
  .flipping{animation:flipC .22s ease}
  @keyframes flipC{0%{transform:scaleX(1)}50%{transform:scaleX(.05)}100%{transform:scaleX(1)}}
  /* pista de volteo integrada en la propia carta seleccionada */
  /* la ↻ va DENTRO del chip de modo desde la revisión de sellos: la pista
     flotante decía lo mismo una tercera vez (móvil ya la anulaba) */
  /* ── CONEXIÓN módulo ↔ ciberspírit ─────────────────────────────────────────
     Cada módulo tiene un enlace de datos que sube hacia la arena (el ciberspírit).
       · por defecto: corto y apagado (no está EN LÍNEA);
       · EN LÍNEA o seleccionado: se extiende, brilla y fluyen datos hacia arriba;
       · replegado: el enlace se apaga/corta;
       · roto: el enlace glitchea.
     El otro extremo (el segmento del cuerpo) late en drawSide. No son cartas:
     un módulo EN LÍNEA es una parte VIVA del ciberspírit. ── */
  .card.rc-cont{--jackc:var(--rcont)}
  .card.rc-cuar{--jackc:var(--rcuar)}
  .card.rc-mut{--jackc:var(--rmut)}
  #battle .card .jack{display:none}   /* el enlace ahora lo dibuja la capa #linkfx (cable real) */
  .card .jack{position:absolute;left:50%;top:-6px;transform:translateX(-50%);
    width:2px;height:6px;pointer-events:none;z-index:4;opacity:.2;
    background:linear-gradient(180deg,transparent,var(--jackc,var(--you)));
    transition:height .25s ease,top .25s ease,opacity .25s ease}
  .card .jack::before{content:'';position:absolute;left:50%;top:-2px;transform:translateX(-50%);
    width:4px;height:4px;border-radius:50%;background:var(--jackc,var(--you));opacity:.55}
  .card .jack::after{content:'';position:absolute;left:50%;transform:translateX(-50%);
    width:3px;height:3px;border-radius:50%;background:var(--jackc,var(--you));opacity:0}
  .card.oc .jack{display:none}                          /* módulo cifrado: sin enlace visible */
  /* EN LÍNEA (no elegido): PUERTO compacto y limpio — nodo que late, sin antena
     larga (una antena alta sobre una carta ya jugada quedaba rara) */
  .card.enlinea .jack{height:8px;top:-8px;opacity:.95;box-shadow:0 0 6px var(--jackc,var(--you))}
  .card.enlinea .jack::before{opacity:1;box-shadow:0 0 7px var(--jackc,var(--you));
    animation:portPulse 1.4s ease-in-out infinite}
  .card.enlinea .jack::after{opacity:0}
  @keyframes portPulse{0%,100%{transform:translateX(-50%) scale(1);opacity:.7}
    50%{transform:translateX(-50%) scale(1.35);opacity:1}}
  /* SELECCIONADO: uplink alto y con flujo de datos (canalizando ahora) */
  .card[aria-pressed="true"]:not(.oc):not(.rota) .jack{
    height:24px;top:-24px;width:3px;opacity:1;box-shadow:0 0 10px var(--jackc,var(--you))}
  .card[aria-pressed="true"]:not(.oc):not(.rota) .jack::before{
    opacity:1;box-shadow:0 0 8px var(--jackc,var(--you));animation:none}
  .card[aria-pressed="true"]:not(.oc):not(.rota) .jack::after{
    opacity:1;background:#fff;animation:jackflow 1.15s linear infinite}
  @keyframes jackflow{0%{top:24px;opacity:0}25%{opacity:1}100%{top:-2px;opacity:0}}
  /* replegada: se apaga el enlace */
  .card.replegando .jack{opacity:.12;height:5px;top:-5px;box-shadow:none}
  .card.replegando .jack::after{animation:none;opacity:0}
  /* rota: enlace roto que glitchea */
  .card.rota .jack{display:block;opacity:.35;box-shadow:none;
    animation:jackGlitch .5s steps(2) infinite}
  .card.rota .jack::after{animation:none;opacity:0}
  @keyframes jackGlitch{0%,100%{transform:translateX(-50%)}
    50%{transform:translateX(-50%) translateX(2px);opacity:.1}}
  @media (prefers-reduced-motion:reduce){ .card .jack::after{animation:none!important;opacity:0}
    .card.rota .jack{animation:none} .card.enlinea .jack::before{animation:none} }
  .modes{display:none!important}
  /* INCURSIÓN (capturar = puzle) */
  .incbox{max-width:440px}
  .inch{margin:0 0 6px;font-size:15px;letter-spacing:.03em}
  .incmeta{display:flex;align-items:center;gap:7px;font-size:12px;color:var(--dim);margin-bottom:10px}
  .incmeta .incsep{color:var(--line)}
  .incsensor{border:1px solid var(--line);border-radius:10px;padding:10px 12px;margin-bottom:12px;background:rgba(255,255,255,.02)}
  .incrow{display:flex;justify-content:space-between;gap:10px;font-size:11px;color:var(--muted);margin-bottom:4px}
  .incrow b{color:var(--ink);font-weight:600;text-align:right}
  .incahora{margin-top:8px;text-align:center;font-size:13px;letter-spacing:.02em}
  .incnow{color:var(--dim)} .incnow.leida{color:var(--amber);font-weight:700}
  .incbars{display:flex;justify-content:space-between;gap:8px;font-size:10.5px;color:var(--muted);
    letter-spacing:.08em;margin-bottom:12px;flex-wrap:wrap}
  .incbars b{letter-spacing:2px}
  .incnod{color:var(--you)} .incsin{color:var(--red)} .incturn{color:var(--dim);letter-spacing:.03em}
  .inctele{display:flex;flex-direction:column;align-items:center;gap:2px;padding:14px;margin-bottom:12px;
    border:1px solid var(--tc,var(--line));border-radius:12px;background:rgba(255,255,255,.02)}
  .inctele .ici{font-size:30px;color:var(--tc,var(--ink));line-height:1}
  .inctele .ict{font-family:var(--mono,monospace);font-weight:800;letter-spacing:.14em;color:var(--tc,var(--ink))}
  .inctele .icd{font-size:11px;color:var(--dim)}
  .inctele.oculto{--tc:var(--muted)} .inctele.oculto .ici{color:var(--muted)}
  .incverbs{display:flex;gap:7px;margin-bottom:12px}
  .incverb{flex:1;border:1px solid var(--line);border-radius:9px;background:transparent;color:var(--ink);
    padding:11px 5px;font-size:12px;font-weight:700;letter-spacing:.04em;cursor:pointer}
  .incverb small{display:block;color:var(--muted);font-size:8px;font-weight:400;margin-top:3px;letter-spacing:.02em}
  .incverb.v-cont{box-shadow:inset 0 0 0 1px var(--rcont,#ff5ca8)} .incverb.v-cont{color:var(--rcont,#ff5ca8)}
  .incverb.v-cuar{box-shadow:inset 0 0 0 1px var(--rcuar,#46d6ec);color:var(--rcuar,#46d6ec)}
  .incverb.v-mut{box-shadow:inset 0 0 0 1px var(--rmut,#c58bff);color:var(--rmut,#c58bff)}
  .incverb:active{transform:translateY(1px)}
  .inclog{font-size:10.5px;color:var(--dim);line-height:1.5;min-height:40px;margin-bottom:8px}
  .inclog div:first-child{color:var(--ink)}
  /* TUTORIAL · hub + asistente */
  .aprpart .aprnum{display:inline-block;min-width:1.4em;text-align:center;color:var(--amber);font-weight:800;margin-right:4px}
  .wizbox{max-width:420px}
  .wizeye{font-size:10px;letter-spacing:.28em;text-transform:uppercase;color:var(--faint,var(--muted));margin-bottom:10px}
  .wizdots{display:flex;gap:6px;margin-bottom:14px}
  .wizdots i{width:7px;height:7px;border-radius:50%;background:var(--line);transition:background .2s}
  .wizdots i.on{background:var(--amber)}
  .wizh{margin:0 0 8px;font-size:18px;letter-spacing:.01em}
  .wizt{font-size:14px;line-height:1.6;color:var(--dim);min-height:96px}
  .wizt b{color:var(--ink);font-weight:600}
  .wiznav{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:16px}
  .wizcta{flex:1;padding:12px;font-weight:700;letter-spacing:.04em}
  .wizx{display:block;margin:12px auto 0;opacity:.6}
  /* RETAR (duelos por turnos): desplegable de jugadores + toggle FURIA A/B */
  .retobox{border:1px solid var(--line);border-radius:10px;padding:12px;margin-bottom:12px;
    background:var(--panel2,rgba(255,255,255,.02))}
  .retorow{display:flex;flex-direction:column;gap:9px}
  #retoRival{width:100%}
  .retovar{display:flex;gap:6px}
  .retovar button{flex:1;border:1px solid var(--line);border-radius:7px;background:transparent;
    color:var(--dim);padding:9px 6px;font-size:11px;letter-spacing:.04em;cursor:pointer}
  .retovar button small{display:block;color:var(--muted);font-size:8.5px;margin-top:3px}
  .retovar button[aria-pressed="true"]{color:var(--ink);box-shadow:inset 0 0 0 1px var(--amber);background:rgba(255,198,92,.08)}
  #retoBtn{width:100%;margin-top:10px}
  .vbadge{font-style:normal;font-size:8.5px;letter-spacing:.05em;padding:1px 5px;border-radius:4px;
    border:1px solid;vertical-align:middle}
  .vbadge.vb-a{color:var(--dim);border-color:var(--line)}
  .vbadge.vb-b{color:#ff5ca8;border-color:#7c2450;background:rgba(255,92,168,.08)}
  .efly{position:fixed;width:6px;height:6px;border-radius:2px;background:var(--amber);
    box-shadow:0 0 7px var(--amber);z-index:60;pointer-events:none;
    transition:left .55s ease-in, top .55s ease-in, opacity .6s}
  .en.pop{animation:enPop .45s}
  @keyframes enPop{30%{transform:scale(1.6);color:#fff}}
  .ab2{color:var(--amber);font-size:8px;letter-spacing:.04em;font-style:normal}
  .ecoChip{color:var(--amber);font-size:10px}
  /* panel contextual = lectura de diagnóstico del objetivo del módulo */
  .targets{display:none;gap:6px;flex-wrap:wrap;align-items:center;
    padding-left:9px;border-left:2px solid var(--line)}
  .targets.on{display:flex}
  .targets.on::before{content:'◈ dirigir';font-family:var(--mono);font-size:9px;
    letter-spacing:.14em;text-transform:uppercase;color:var(--dim);margin-right:1px}
  .targets button{font-family:var(--mono);font-size:10px;padding:9px 11px;letter-spacing:.04em;
    color:var(--muted);border-radius:6px}
  .targets button[aria-pressed="true"]{border-color:var(--amber);background:#2a2338;color:var(--ink);
    box-shadow:inset 0 0 0 1px rgba(255,198,92,.35)}
  #stepPanel{display:none;flex-direction:column;gap:8px;background:var(--panel2);
    border-radius:8px;padding:10px}
  .modeQ{font-size:11.5px;color:var(--muted);letter-spacing:.04em}
  .modeQ b{color:var(--ink)}
  .modes{display:flex;border:1px solid var(--line);border-radius:6px;overflow:hidden}
  .modes button{flex:1;border:0;border-radius:0;padding:12px 4px;font-size:11px;
    letter-spacing:.12em;background:var(--panel)}
  .modes button[aria-pressed="true"]{background:#2a2338;color:var(--ink);box-shadow:inset 0 0 0 1px var(--amber)}
  .modes button small{display:block;color:var(--muted);font-size:8.5px;letter-spacing:.03em;margin-top:3px}
  #go{width:100%;padding:17px 10px;font-size:15px;font-weight:800;letter-spacing:.24em;
    border-radius:8px;background:linear-gradient(180deg,#17392b,#10281f);
    border:1px solid var(--you-dim);color:var(--ink)}
  #go:not(:disabled):hover{border-color:var(--you)}
  #go:disabled{background:var(--panel);border-color:var(--line);color:var(--dim);
    letter-spacing:.12em;opacity:1;animation:none}
  /* (las reglas de fase viven ahora en el bloque «JERARQUÍA POR FASE», al final) */
  /* ── cinemáticas de evento: barras de cine + rótulo con zoom ── */
  #cine{position:absolute;inset:0;z-index:6;pointer-events:none;display:none;overflow:hidden}
  #cine.on{display:block}
  #cine .cb{position:absolute;left:0;right:0;height:12.5%;background:rgba(4,6,10,.93);
    transform:scaleY(0);transition:transform .2s ease-out}
  #cine .cb.t{top:0;transform-origin:top}
  #cine .cb.b{bottom:0;transform-origin:bottom}
  #cine.on .cb{transform:scaleY(1)}
  #cine .ct{position:absolute;left:0;right:0;top:50%;transform:translateY(-50%);
    text-align:center;font-weight:800;letter-spacing:.14em;font-size:30px;
    padding:14px 0;text-shadow:0 2px 18px rgba(0,0,0,.75);
    background:linear-gradient(90deg,transparent,rgba(4,6,10,.82) 18% 82%,transparent);
    animation:cinePunch .5s cubic-bezier(.16,1.3,.3,1) both}
  #cine .cs{display:block;font-size:11px;letter-spacing:.24em;margin-top:7px;
    color:#cfd7e4;font-weight:600}
  @keyframes cinePunch{from{transform:translateY(-50%) scale(2.1);opacity:0;filter:blur(7px)}
    to{transform:translateY(-50%) scale(1);opacity:1;filter:blur(0)}}
  /* modo REVELACIÓN: título arriba y semitransparente → la animación se ve entera */
  #cine .ct.ct-top{top:9%;transform:none;animation-name:cinePunchTop}
  #cine .ct.ct-clear{background:linear-gradient(90deg,transparent,rgba(4,6,10,.42) 14% 86%,transparent)}
  @keyframes cinePunchTop{from{transform:scale(2.1);opacity:0;filter:blur(7px)}
    to{transform:scale(1);opacity:1;filter:blur(0)}}
  .vignfx{position:absolute;inset:0;pointer-events:none;opacity:0;z-index:5;border-radius:8px}
  .vignfx.on{animation:flashk .55s ease-out}
  /* ── entrenador del tutorial ── */
  #coach{display:none;margin-top:8px;border:1px solid var(--amber);border-radius:8px;
    background:var(--panel2);padding:9px 12px;gap:9px;align-items:flex-start;
    font-size:12px;line-height:1.6;color:var(--ink)}
  #battle.tut #coach{display:flex}
  #coach .cg{font-size:16px;line-height:1.2}
  #coach b{color:var(--amber)}
  @keyframes tutPulse{0%,100%{box-shadow:0 0 0 2px var(--amber),0 0 8px rgba(255,198,92,.2)}
    50%{box-shadow:0 0 0 3px var(--amber),0 0 20px rgba(255,198,92,.55)}}
  .tutGlow{animation:tutPulse 1.15s ease-in-out infinite;border-radius:8px}
  /* GUÍA — look unificado y "superpuesto" (coach de combate + tours de captura/montar) */
  #coach{box-shadow:0 0 0 1px var(--amber),0 0 14px rgba(255,198,92,.18)}
  /* ══ CIFRADA: la potencia que va a usar ══
     Al ocultar una Forma, el número de arriba a la derecha muestra ya el valor
     con el descuento aplicado, con su «−1» al lado. Idea de Andreu: que se VEA
     que ocultar cuesta potencia, en vez de tener que saberlo. El +1⚡ que gana ya
     estaba en el botón, así que las dos caras del intercambio quedan a la vista. */
  .num.cifrada{color:var(--muted)}
  .num .ocpen{font-size:.42em;font-style:normal;font-weight:800;color:var(--red);
    vertical-align:super;margin-left:1px;letter-spacing:0}
  /* ══ PROTOCOLO DE CALIBRACIÓN · no es LA RED quien habla ══
     La hija de Andreu no distinguía la historia de la instrucción, y con razón:
     esta caja está FIRMADA como LA RED, cuya voz el §0.2 obliga a ser seca.
     El ámbar se queda: ya significa «guía» en todo el juego —los tours de captura
     y de montar la red usan esta misma clase— y el PROTOCOLO es exactamente eso.
     Lo que cambia es la FIRMA: chip sólido con ▚ = una voz; etiqueta delineada y
     sin glifo = un estado del sistema. La tipografía tampoco se toca: la única
     alternativa cargada es la VT323 del terminal, que es la de LA RED. */
  /* ══ EL PROTOCOLO, ELEVADO ══
     Andreu, tras probarlo en familia: «los mensajes quedan como muy incrustados
     en el modo combate, no se ve que es algo que te está enseñando».
     NO se hace modal ni se difumina la mesa: la instrucción explica la mesa, así
     que taparla impediría seguirla mientras se lee —y hay una decisión previa de
     Andreu contra los modales durante el combate, que «interrumpen»—. Se eleva en
     su sitio: el coach ya vive ENCIMA de las cartas, entre el log y los mandos,
     así que sombra y raíl no tapan ni una carta ni el botón de confirmar.
     Y se puede plegar: queda la etiqueta como pestaña, que lo reabre. */
  #coach.flota{position:relative;z-index:3;margin:10px 0;padding:12px 14px 12px 13px;
    border-left:3px solid var(--amber);font-size:13px;line-height:1.62;
    box-shadow:0 10px 34px rgba(0,0,0,.58),0 0 0 1px var(--amber),
      0 0 24px rgba(255,198,92,.22)}
  #coach .protoX{display:none}
  #coach.flota .protoX{display:block;position:absolute;top:4px;right:6px;
    background:none;border:0;color:var(--dim);font-size:15px;line-height:1;
    padding:4px 7px;cursor:pointer;font-family:inherit}
  #coach.flota .protoX:hover{color:var(--amber)}
  /* plegado: solo la etiqueta, y toda la caja es la pestaña que lo reabre */
  #coach.flota.plegado{padding:5px 8px;cursor:pointer;box-shadow:0 0 0 1px var(--amber);
    border-left-width:3px;gap:6px}
  #coach.flota.plegado #coachTxt{display:none}
  #coach.flota.plegado .protoX{display:none}
  #coach.flota.plegado .guialbl::after{content:' ▸';letter-spacing:0}
  /* al cambiar de paso, un destello corto: es lo que hace que se note que te
     está diciendo algo nuevo sin interrumpir nada */
  @keyframes protoNuevo{0%{box-shadow:0 10px 34px rgba(0,0,0,.58),0 0 0 2px var(--amber),
      0 0 34px rgba(255,198,92,.55)}
    100%{box-shadow:0 10px 34px rgba(0,0,0,.58),0 0 0 1px var(--amber),
      0 0 24px rgba(255,198,92,.22)}}
  #coach.flota.nuevo{animation:protoNuevo .75s ease-out}
  @media (prefers-reduced-motion:reduce){ #coach.flota.nuevo{animation:none} }
  /* ══ TRES PRESENTACIONES DEL MISMO PANEL (fase 2 · 2-sep-2026) ═══════════════
     docs/tutorial-calibracion-dictamen.md. No son tres tutoriales: es el mismo protocolo
     con tres pesos, elegidos por el `kind` del paso (desde CSS no se puede: cuando llega
     un paso post-resolución la clase de fase ya ha vuelto a `ph-pick`).

     ACT · lo mínimo para decidir ahora. La instrucción se va al botón, así que casi
       siempre es UNA línea. Sin sombra grande: no tiene que reclamar la mirada, la
       reclama el foco del elemento que hay que tocar.
     OBSERVE · más ligero todavía: una idea sobre lo que acaba de cambiar. Sin raíl y en
       gris, para que no compita con el choque que se está mirando.
     RULE · el único que puede pesar: es cuando se está formando un modelo. Aquí sí lleva
       el raíl ámbar, la etiqueta entera y algo de aire. */
  /* NINGUNA PALABRA DESBORDA. «ASISTENCIA // RETIRADA» se salía 15px a 360px (lo pilló
     humo-calibracion): un token largo en negrita no tiene dónde partir. Red de seguridad
     para cualquier texto del protocolo, no parche para esa frase. */
  #coach #coachTxt{min-width:0;overflow-wrap:anywhere}
  #coach.flota.k-act{padding:7px 12px 7px 11px;font-size:12.5px;line-height:1.5;
    box-shadow:0 4px 14px rgba(0,0,0,.45),0 0 0 1px var(--amber)}
  #coach.flota.k-act:empty,#coach.flota.k-act #coachTxt:empty{margin:0}
  /* el paso 16 no dice nada: todo lo dice el botón. Sin texto, la caja es solo la
     etiqueta, y ocupa una línea en vez de dos. */
  #coach.flota.k-act #coachTxt:empty{display:none}
  #coach.flota.k-observe{padding:6px 12px 6px 11px;font-size:12.5px;line-height:1.5;
    border-left-color:var(--line2);color:var(--dim);
    box-shadow:0 3px 10px rgba(0,0,0,.4),0 0 0 1px var(--line2)}
  #coach.flota.k-observe b{color:var(--ink)}
  #coach.flota.k-observe .guialbl{color:var(--dim);border-color:var(--line2)}
  #coach.flota.k-rule{padding:12px 14px 12px 13px;font-size:13px;line-height:1.62}
  /* el ciclo, centrado y con aire: es un diagrama, no un párrafo */
  #coach.flota.k-rule #coachTxt b:first-child{letter-spacing:.14em}
  #coach.cal-proto .cg{display:none}
  #coach.cal-proto .guialbl{background:transparent;color:var(--amber);
    border:1px solid var(--amber);font-size:9px;letter-spacing:.12em}
  .guialbl{align-self:center;font-size:8.5px;letter-spacing:.18em;color:#0b0e15;background:var(--amber);
    padding:2px 6px;border-radius:4px;font-weight:800;flex:none}
  .guia-float{display:none;position:fixed;left:50%;bottom:18px;transform:translateX(-50%);z-index:120;
    width:min(360px,92vw);border:1px solid var(--amber);border-radius:12px;background:var(--panel2,#111828);
    padding:12px 14px;gap:9px;align-items:center;flex-wrap:wrap;
    box-shadow:0 0 0 1px var(--amber),0 8px 30px rgba(0,0,0,.5),0 0 22px rgba(255,198,92,.25);
    animation:guiaIn .2s ease-out}
  .guia-float.on{display:flex}
  @keyframes guiaIn{from{opacity:0;transform:translateX(-50%) translateY(10px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}
  .guia-float .cg{font-size:18px;line-height:1}
  .guia-txt{flex:1 1 100%;font-size:13.5px;line-height:1.55;color:var(--ink)}
  .guia-txt b{color:var(--amber)}
  .guia-nav{flex:1 1 100%;order:4;margin-top:2px}
  .guia-cta{width:100%;padding:11px;font-weight:700;letter-spacing:.03em}
  .guia-x{flex:1 1 100%;order:5;background:none;border:0;color:var(--dim);font-size:10.5px;margin-top:2px;cursor:pointer}
  @media (prefers-reduced-motion:reduce){ .guia-float{animation:none} }
  /* guía como POPUP centrado (usa .overlay para el fondo difuminado) */
  .guia-card{max-width:400px;border:1px solid var(--amber)!important;
    box-shadow:0 0 0 1px var(--amber),0 0 26px rgba(255,198,92,.28)!important}
  .guia-card .wizeye{color:var(--amber);letter-spacing:.2em}
  .guia-card .guia-txt{font-size:14.5px;line-height:1.65;color:var(--ink);margin:6px 0 14px}
  .guia-card .guia-txt b{color:var(--amber)}
  .guia-card .guia-cta{width:100%;padding:12px;font-weight:700;letter-spacing:.03em}
  .guia-card .guia-x{display:block;margin:10px auto 0;background:none;border:0;color:var(--dim);font-size:11px;cursor:pointer}
  /* banner de nueva versión */
  /* toast compacto, centrado abajo — no ocupa todo el ancho ni tapa el juego */
  #updBanner{position:fixed;left:50%;transform:translateX(-50%);bottom:14px;z-index:200;
    display:flex;align-items:center;gap:8px;
    background:var(--panel2);border:1px solid var(--amber);border-radius:999px;
    padding:6px 8px 6px 16px;font-size:12.5px;color:var(--ink);max-width:92vw;
    box-shadow:0 8px 30px rgba(0,0,0,.5);animation:pcIn .4s ease both}
  #updBanner button{border-color:var(--amber);color:var(--amber);font-weight:800;
    padding:6px 12px;font-size:11px;border-radius:999px}
  #updBanner #updX{padding:6px 9px;color:var(--dim);border-color:var(--line)}
  /* ── PRIMER CONTACTO: onboarding cinemático ── */
  #pc{position:fixed;inset:0;z-index:60;background:radial-gradient(ellipse at 50% 40%,
    #10131c 0%,#05070c 70%);display:none;overflow:hidden}
  #pc.on{display:flex;align-items:center;justify-content:center}
  #pcInner{width:min(560px,92vw);text-align:center;padding:24px;position:relative;z-index:2}
  #pcScene .big{font-size:clamp(26px,7vw,42px);font-weight:800;letter-spacing:.02em;
    line-height:1.15;text-wrap:balance;margin-bottom:14px}
  #pcScene .big b{color:var(--you)} #pcScene .big i{color:var(--foe);font-style:normal}
  #pcScene .sub{font-size:14px;color:var(--muted);line-height:1.6;text-wrap:balance}
  #pcScene .glyph{font-size:64px;margin-bottom:10px;filter:drop-shadow(0 0 20px rgba(63,224,160,.5))}
  #pcScene.in{animation:pcIn .6s cubic-bezier(.16,1,.3,1) both}
  @keyframes pcIn{from{opacity:0;transform:translateY(18px) scale(.96);filter:blur(6px)}
    to{opacity:1;transform:none;filter:blur(0)}}
  #pcCapture{display:none;margin-top:18px}
  #pcCapture.on{display:block;animation:pcIn .5s ease both}
  #pcInp{width:100%;background:var(--panel);border:1px solid var(--amber);border-radius:10px;
    color:var(--ink);font:inherit;font-size:16px;padding:13px 15px;text-align:center;letter-spacing:.02em}
  #pcInp:focus{outline:none;box-shadow:0 0 0 3px rgba(255,198,92,.25)}
  #pcGo{margin-top:10px;width:100%;border-color:var(--amber);color:var(--amber);
    font-size:15px;padding:12px}
  #pcHint{font-size:12px;color:var(--muted);margin-top:10px;min-height:16px;line-height:1.5}
  #pcBtns{margin-top:22px;justify-content:center}
  #pcNext{padding:11px 26px;font-size:15px}
  #pc canvas{position:absolute;inset:0;width:100%;height:100%;opacity:.5;z-index:1}
  /* ── LA RED: mapa de capturas ── */
  #lared,#mired{display:none}
  /* LA RED como mapa: fondo vivo + sectores por naturaleza */
  #lared{position:relative}
  #redSky{position:fixed;inset:0;width:100%;height:100%;z-index:0;pointer-events:none;opacity:1}
  #lared>*:not(#redSky){position:relative;z-index:1}
  #redResumen{font-size:11px;color:var(--muted);letter-spacing:.06em;margin:4px 0 2px}
  #redResumen b{color:var(--you)}
  /* cada sector como bloque intencionado: fondo tenue + acento de su naturaleza */
  .sector{margin:0;padding:12px 13px 13px;border:1px solid var(--line);border-radius:12px;
    background:linear-gradient(180deg,rgba(21,28,40,.5),rgba(10,13,19,.25));
    border-top:2px solid var(--sc,var(--line))}
  .sector .shead{display:flex;align-items:baseline;gap:8px;border-bottom:1px solid var(--line);
    padding-bottom:7px;margin-bottom:10px}
  .sector .sname{font-size:13px;font-weight:800;letter-spacing:.08em}
  .sector .sdesc{font-size:9.5px;color:var(--dim);letter-spacing:.04em}
  .sector .scount{margin-left:auto;font-size:10px;color:var(--muted)}
  .sector.s-ESTRUCTURA .sname{color:#5aa0ff} .sector.s-ESTRUCTURA{--sc:#5aa0ff}
  .sector.s-RUIDO .sname{color:#ff8c3b}      .sector.s-RUIDO{--sc:#ff8c3b}
  .sector.s-SEÑAL .sname{color:#ffd84a}      .sector.s-SEÑAL{--sc:#ffd84a}
  .sector.s-ECO .sname{color:#c07aff}        .sector.s-ECO{--sc:#c07aff}
  .sector .sgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:8px}
  .sector .wnode{border-left:3px solid var(--sc)}
  #buscaRow{display:flex;gap:8px;margin:10px 0 2px}
  #buscaRow input{flex:1;background:var(--panel);border:1px solid var(--line);
    border-radius:8px;color:var(--ink);font:inherit;font-size:12px;padding:9px 11px;
    letter-spacing:.03em}
  #buscaRow input:focus{outline:none;border-color:var(--amber)}
  #buscaRow button{border-color:var(--amber);color:var(--amber);white-space:nowrap}
  .ctain{display:block;width:100%;margin:7px 0;background:var(--panel2);
    border:1px solid var(--line);border-radius:8px;color:var(--ink);
    font:inherit;font-size:13px;padding:10px 12px}
  .ctain:focus{outline:none;border-color:var(--amber)}
  /* la portería: con servidor delante y sin sesión, no se juega */
  body.portazo #title .tbtns button{opacity:.3;pointer-events:none}
  body.portazo #title #ctaBtn, body.portazo #title #guideBtn,
  body.portazo #title #rulesBtn{opacity:1;pointer-events:auto}
  body.portazo #ctaBtn{border-color:var(--amber);color:var(--amber)}
  .wnode.desc{border-style:dashed}
  .bytes{color:var(--amber);font-size:13px;letter-spacing:.08em;margin-left:10px}
  #capsGrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));
    gap:8px;margin:12px 0}
  /* LA RED: los SECTORES son los hijos de #redGrid (no cartas). Apilados en móvil;
     en escritorio, 2×2 para aprovechar el ancho y que cada sector respire */
  #redGrid{display:grid;grid-template-columns:1fr;gap:16px;margin:14px 0}
  @media (min-width:760px){ #redGrid{grid-template-columns:1fr 1fr;gap:20px} }
  .wnode{text-align:left;padding:8px 10px;display:flex;flex-direction:column;gap:3px;
    border:1px solid var(--line);border-radius:8px;background:var(--panel)}
  .wnode .nd{font-size:9px;color:var(--dim);letter-spacing:.04em;
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .wnode .nn{font-size:11px;font-weight:800}
  .wnode .ns{font-size:9.5px;color:var(--muted);display:flex;gap:6px;align-items:center}
  .wnode .nc{font-size:10px;color:var(--amber);letter-spacing:.08em}
  .wnode.cap{border-color:var(--you-dim)}
  .wnode.cap .nc{color:var(--you)}
  .wnode.far{opacity:.55}
  .wnode.justcap{animation:pillPop .5s cubic-bezier(.2,1.6,.4,1)}
  .wnode.insel{border-color:var(--amber);box-shadow:0 0 10px rgba(255,198,92,.3)}
  #redInfo .rid{font-size:9.5px;color:var(--dim);letter-spacing:.06em}
  #redInfo .rin{font-size:17px;font-weight:800;margin:2px 0 6px}
  #redInfo .rst{display:flex;gap:14px;font-size:12px;color:var(--muted);margin:8px 0}
  #redInfo .rst b{color:var(--ink);font-size:15px}
  #redInfo .rd{font-size:11px;color:var(--muted);font-style:italic}
  /* ═══ INSPECCIÓN DE NODO · la ficha de una web ══════════════════════════════
     LA IDEA: la ficha es LA FILA DEL ÍNDICE, DESPLEGADA. Antes heredaba `.box`
     —la caja genérica que comparten la chuleta y la expedición— y al abrirla
     cambiaba de familia tipográfica, aparecían barras redondeadas y píldoras que
     LA RED no usa en ningún sitio, y se cortaba el hilo con la fila que acababas
     de tocar (reporte de Andreu, 28-ago: «se siente como un popup clásico de
     juego»). Ahora hereda de la fila lo que la identifica: la tipografía VT323,
     el acento de su naturaleza en el borde izquierdo y las scanlines. Lo que
     añade es PROFUNDIDAD, no otro lenguaje.

     Y respeta la regla que ya tenía el sistema (ver «cromo en verde terminal»,
     más arriba): el CROMO va en verde fósforo y los DATOS conservan su color —
     la naturaleza el suyo, la potencia rosa, el coste ámbar. Coherencia, no
     monotonía. */
  #redOv .box{background:#050806;border:1px solid #143d22;border-left:3px solid var(--sc,#1e8f45);
    border-radius:2px;padding:0;gap:0;max-width:520px;overflow:hidden;
    box-shadow:0 0 40px rgba(58,255,110,.07)}
  /* scanlines del sistema, como en #lared y #mired */
  #redOv .box::before{content:'';position:absolute;inset:0;pointer-events:none;z-index:2;
    background:repeating-linear-gradient(0deg, rgba(0,0,0,.16) 0 2px, transparent 2px 4px)}
  #redOv .box{position:relative}
  /* ── EL PANEL SE DESPLAZA Y EL BOTÓN DE SALIR NO SE VA NUNCA ──
     .box está limitada a 88vh y con overflow:hidden (lo necesita para el borde y
     las scanlines). Cuando la ficha es más larga que eso —una web capturada con
     rango, acceso y expedición lo es—, lo recortado era justo la fila de botones:
     medido a 360×640, redInfo 565px + btns 105px = 670 dentro de una caja de 563,
     y «× CERRAR INSPECCIÓN» caía en y=647 con la pantalla de 640. Sin scroll no
     había manera de llegar a él.
     Ahora el CONTENIDO se desplaza y los botones no se encogen, así que la salida
     está siempre a la vista. Lo vigila deploy/humo-ficha.mjs. */
  #redOv .box{flex-direction:column}
  #redOv #redInfo{overflow-y:auto;min-height:0;overscroll-behavior:contain}
  #redOv .box .btns{flex:0 0 auto}
  body.reduce-fx #redOv .box::before{display:none}
  /* el color de la naturaleza, LOS MISMOS valores que `.sector.s-*`. Si se
     separan, humo-ficha.mjs lo canta. */
  #redOv[data-nat="ESTRUCTURA"]{--sc:#5aa0ff}
  #redOv[data-nat="RUIDO"]{--sc:#ff8c3b}
  #redOv[data-nat="SEÑAL"]{--sc:#ffd84a}
  #redOv[data-nat="ECO"]{--sc:#c07aff}

  /* ── cabecera: bloque de inspección, no tarjeta ── */
  #redInfo{display:flex;flex-direction:column;gap:0;position:relative;z-index:1}
  #redInfo .rfHead{padding:11px 14px 10px;border-bottom:1px solid #143d22;
    background:linear-gradient(180deg, rgba(58,255,110,.05), transparent)}
  #redInfo .rfSys{font-family:'VT323',var(--mono);font-size:15px;letter-spacing:.14em;
    color:#1e8f45;display:flex;align-items:baseline;gap:8px}
  #redInfo .rfSys b{color:#3aff6e;font-weight:400;text-shadow:0 0 6px rgba(58,255,110,.4)}
  /* la ruta va en SU PROPIA LÍNEA. Al lado del título con `margin-left:auto` el
     título se partía en dos a 390px y la ruta quedaba flotando arriba a la
     derecha: en un móvil no caben las dos cosas en una línea. */
  #redInfo .rfRuta{display:block;font-family:'VT323',var(--mono);font-size:15px;
    color:#1e8f45;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
    letter-spacing:.02em;margin-top:1px}
  #redInfo .rin{font-family:'VT323',var(--mono);font-size:27px;line-height:1.05;
    font-weight:400;letter-spacing:.02em;color:var(--sc,#e8eef7);margin:4px 0 2px;
    text-shadow:0 0 10px color-mix(in srgb, var(--sc,#3aff6e) 38%, transparent)}
  #redInfo .rfEstado{font-family:'VT323',var(--mono);font-size:14.5px;color:#1e8f45;
    letter-spacing:.04em;display:flex;flex-wrap:wrap;gap:4px 12px}
  #redInfo .rfEstado b{font-weight:400;color:#3aff6e}
  #redInfo .rfEstado .ok{color:#3aff6e}

  /* ── bloques nombrados: se lee como salida de sistema ── */
  #redInfo .rfBloq{padding:9px 14px 11px;border-bottom:1px solid rgba(20,61,34,.7)}
  #redInfo .rfBloq:last-child{border-bottom:0}
  #redInfo .rfSec{font-family:'VT323',var(--mono);font-size:13.5px;letter-spacing:.16em;
    color:#1e8f45;display:flex;align-items:center;gap:8px;margin-bottom:6px}
  #redInfo .rfSec::after{content:'';flex:1;height:1px;background:rgba(30,143,69,.35)}

  /* naturaleza y rol-hogar */
  #redInfo .rfNat{display:flex;align-items:center;flex-wrap:wrap;gap:7px;font-size:13px}
  #redInfo .rfNat b{color:var(--sc,var(--ink));letter-spacing:.06em}
  #redInfo .rfEf{color:var(--amber);font-size:11.5px}
  #redInfo .rfHome{font-size:11.5px;color:var(--dim);margin-top:5px}
  #redInfo .rfHome b{color:var(--amber)}
  #redInfo .rfHome i{font-style:normal;color:var(--faint,var(--muted));font-size:10.5px}

  /* magnitudes: CELDAS, no barras redondeadas. Las celdas son un degradado
     repetido y no un glifo, así que no dependen de que la fuente lo tenga. */
  #redInfo .rfStats{display:flex;flex-direction:column;gap:5px}
  #redInfo .rfStat{display:flex;align-items:center;gap:9px}
  #redInfo .rfLbl{flex:0 0 104px;font-family:'VT323',var(--mono);font-size:14px;
    letter-spacing:.08em;color:#1e8f45}
  /* CELDAS DISCRETAS, una por punto: encender un % de un degradado dejaba el
     relleno y el fondo desfasados y pintaba 6 celdas para un valor de 3. Ahora
     hay nueve celdas y se encienden exactamente las que vale. */
  #redInfo .rfCel{flex:1;display:flex;gap:2px;align-items:stretch;height:10px}
  #redInfo .rfCel i{flex:1;background:rgba(255,255,255,.07)}
  #redInfo .rfCel i.on{background:currentColor;
    box-shadow:0 0 5px color-mix(in srgb, currentColor 55%, transparent)}
  #redInfo .rfCel.atk{color:var(--rcont,#ff5ca8)} #redInfo .rfCel.def{color:var(--amber)}
  #redInfo .rfV{flex:0 0 40px;text-align:right;font-family:'VT323',var(--mono);font-size:19px;
    color:var(--ink);font-variant-numeric:tabular-nums;letter-spacing:.02em}
  #redInfo .rfV.atk{color:var(--rcont,#ff5ca8)} #redInfo .rfV.def{color:var(--amber)}

  /* la rueda: tres líneas de salida, no píldoras */
  #redInfo .rfWheel{display:flex;flex-direction:column;gap:2px;margin-top:8px;
    font-family:'VT323',var(--mono);font-size:15px;letter-spacing:.03em}
  #redInfo .rfW{display:flex;gap:9px}
  #redInfo .rfW s{text-decoration:none;flex:0 0 96px;color:#1e8f45}
  #redInfo .rfW.good b{color:var(--you);font-weight:400}
  #redInfo .rfW.bad b{color:var(--red);font-weight:400}
  #redInfo .rfW.ch b{color:var(--amber);font-weight:400}

  /* acceso, coste y capacidad: pares etiqueta→valor alineados */
  #redInfo .rfPar{display:flex;align-items:baseline;gap:9px;font-family:'VT323',var(--mono);
    font-size:15px;letter-spacing:.03em;color:var(--muted)}
  #redInfo .rfPar s{text-decoration:none;flex:0 0 104px;color:#1e8f45;font-size:14px;letter-spacing:.08em}
  #redInfo .rfPar b{font-weight:400;color:var(--ink)}
  #redInfo .rfCoste b{color:var(--amber);font-size:20px}
  #redInfo .rfMinor{font-size:11px;color:var(--faint,var(--muted));font-family:'VT323',var(--mono);
    letter-spacing:.03em;padding-left:113px;margin-top:-1px}
  #redInfo .c-you{color:var(--you)} #redInfo .c-red{color:var(--red)} #redInfo .c-amber{color:var(--amber)}
  /* las líneas que se añaden después (rango, historia, retirar) hablan igual */
  #redInfo .rfNota{font-family:'VT323',var(--mono);font-size:14.5px;color:#1e8f45;
    letter-spacing:.03em;line-height:1.5}
  #redInfo .rfNota b{font-weight:400}
  #redOv .box .btns #rfQuitar{border-color:#143d22;color:#1e8f45;font-size:16px}

  /* registro (la descripción de la web): cita del sistema, no cursiva de card */
  #redInfo .rfFlavor{font-size:11.5px;color:var(--muted);line-height:1.6;
    border-left:2px solid rgba(30,143,69,.4);padding-left:9px}

  /* ── acciones: comandos del sistema ── */
  #redOv .box .btns{padding:11px 14px 13px;gap:6px;flex-direction:column;
    border-top:1px solid #143d22;background:rgba(58,255,110,.02);position:relative;z-index:1}
  #redOv .box .btns button{width:100%;flex:none;font-family:'VT323',var(--mono);
    font-size:18px;letter-spacing:.06em;padding:9px 12px;border-radius:2px;
    text-align:left;background:transparent}
  #redOv .box .btns #capBtn{border-color:#3aff6e;color:#3aff6e;
    text-shadow:0 0 7px rgba(58,255,110,.4)}
  #redOv .box .btns #capBtn:disabled{border-color:#143d22;color:#1e8f45;text-shadow:none}
  #redOv .box .btns #expBtn{border-color:var(--amber);color:var(--amber)}
  #redOv .box .btns #redOvX{border-color:#143d22;color:#1e8f45;font-size:16px}
  .wnode .nab{font-size:8.5px;color:var(--amber);font-style:normal;opacity:.85}
  /* BYTES del Tejido (019). Discretos y con su unidad: los bytes que ocupa una
     Forma no son el precio en fragmentos de capturar una web (⌬), y no deben
     leerse como lo mismo. */
  .wnode .nb{font-size:8.5px;font-style:normal;opacity:.7;
    color:var(--dim);letter-spacing:.02em}
  /* el detalle del acceso solo aparece cuando descuenta algo */
  .rfAccDet{opacity:.8}
  .wnode .natn{font-weight:700;letter-spacing:.03em;color:var(--ink);opacity:.9}
  .wnode .ns{flex-wrap:wrap}
  #budgetTag.over{color:var(--red)}
  @media (max-width:520px){ #cine .ct{font-size:19px;letter-spacing:.1em}
    #cine .cs{font-size:8.5px} }
  /* ══════════════ CÁMARA ESTABLE (UX3) ══════════════
     La arena NO se reencuadra entre fases. Antes la altura de .stage y la
     escala de #cv cambiaban en cada paso del turno (elegir → resolver →
     resultado), así que en un duelo de 14 turnos el tablero hacía 42 zooms y
     los Tejidos nunca estaban en el mismo sitio. Ahora hay UN encuadre:
       · .stage tiene altura fija (--camH)
       · #cv es más alto (--camH × --camK) y va anclado ABAJO
         → lo que se recorta es el cielo vacío, nunca los pies
     Los movimientos de cámara se reservan a lo excepcional: .zoomp (rotura de
     una Forma) y .cinez (cinemáticas: FURIA, núcleo, final, CARCELERO). */
  /* ── LA PROPORCIÓN NO SE NEGOCIA (medido el 31-ago) ──────────────────────
     La regla anterior era `aspect-ratio:960/430; max-height:var(--camH)`, y esa
     pareja se contradice: cuando `max-height` es la restricción que manda, el
     navegador ABANDONA el aspect-ratio en silencio y deja la caja con todo el
     ancho y el alto recortado. El lienzo son 960×430 fijos, así que los Tejidos
     salían achatados. Medido con CDP, y el estiramiento crece cuanto MÁS BAJA es
     la ventana, que es lo que hacía que en un móvil se viera bien y en el PC no:

         1512×900 → 1,057×      1512×760 → 1,253×
         1512×660 → 1,445×      1160×640 → 1,490×

     Ahora el alto manda y el ancho SE DERIVA de él, que es el único orden que no
     se puede romper: la caja de .stage tiene la proporción del LIENZO corregida
     por --camK (el recorte de cielo va por dentro), así que #cv —que es
     `width:100%` y `height:100%×--camK`— cae exactamente en 960/430. La arena
     queda más estrecha y centrada en vez de ancha y achatada.
     El `min(100%, …)` protege las ventanas estrechas: ahí el ancho manda y el
     alto se reduce solo, sin distorsión tampoco.

     Y --camH deja de ser un 42vh a ciegas. Medido a 1512×760: el botón de jugar
     acababa 30px por debajo del pliegue EN LA FASE DE ELECCIÓN (la puerta del CTA
     solo medía la de RESULTADO, y a 900/1080 de alto, así que pasaba en verde con
     el fallo delante). Encima del botón hay ~436px de interfaz que no depende del
     alto de la ventana —cabecera 41, hud 109, arenaHead 49, controls 170—, de modo
     que el alto disponible para la arena es `100vh − 436px` y no una fracción.
     El suelo de 170px evita que en una ventana muy baja la arena desaparezca. */
  #battle{--camH:max(170px, min(42vh, 380px, calc(100vh - 436px))); --camK:1.075}
  .stage{width:min(100%, calc(var(--camH) * var(--camK) * 960 / 430));
    aspect-ratio:calc(960 * var(--camK) / 430);
    max-height:none;margin-left:auto;margin-right:auto}
  /* ventana BAJA (no estrecha): el registro se recoge en elección igual que en
     móvil. Son 36px que valen más como aire para la arena que como historial que
     en ese momento nadie lee. */
  @media (max-height:820px){
    .ph-pick .log, .ph-wait .log{display:none}
  }
  #cv{position:absolute;left:0;right:0;bottom:0;width:100%;
    height:calc(100% * var(--camK));
    transform-origin:50% 100%;              /* el zoom excepcional crece desde el suelo */
    transition:transform .28s ease}
  .stage.zoomp #cv{transform:scale(1.05)}
  .stage.cinez #cv{transform:scale(1.07)}
  #stageCap{position:absolute;top:9px;left:10px;z-index:2;text-align:left;
    font-size:10px;letter-spacing:.18em;color:var(--muted);pointer-events:none}
  #endStats{display:grid;grid-template-columns:1fr;gap:7px;
    font-size:12px;color:var(--muted)}
  #endStats div{display:flex;justify-content:space-between;align-items:baseline;gap:10px}
  #endStats span{color:var(--dim);font-size:9.5px;letter-spacing:.1em}
  #endStats b{color:var(--ink)}
  #again{flex:1.6;background:linear-gradient(180deg,#17392b,#10281f);
    border-color:var(--you-dim);font-weight:800;letter-spacing:.18em}
  #again:hover{border-color:var(--you)}
  #newTeams,#homeBtn{flex:1;font-size:10.5px;color:var(--muted)}
  .barTag{font-size:10px;letter-spacing:.05em}
  .fighter.enemy .barTag{text-align:right}
  .subrow{display:flex;justify-content:center;align-items:center;gap:8px}
  /* ancho completo + wrap: con RENDIRSE son 5 botones y no caben en una fila
     (antes flex:none tomaba el ancho de contenido y SALIR se salía a la derecha) */
  .auxbtns{display:flex;gap:6px;flex-wrap:wrap;justify-content:center;flex:1 1 100%;min-width:0}
  .auxbtns button{font-size:10px;padding:6px 10px;color:var(--muted);letter-spacing:.1em}
  #surrBtn.warn{color:var(--red);border-color:var(--red)}
  /* aviso de posición perdida (no bloqueante) */
  #lostBanner{margin:8px 0 0;padding:10px 12px;border:1px solid var(--red);border-radius:8px;
    background:rgba(40,12,16,.6);display:flex;align-items:center;gap:10px;flex-wrap:wrap}
  #lostBanner .lb-t{flex:1 1 160px;font-size:11.5px;color:var(--ink);line-height:1.4}
  #lostBanner .lb-t b{color:var(--red)}
  #lostBanner button{font-size:10.5px;padding:7px 12px;letter-spacing:.06em;border-radius:6px}
  #lostBanner #lbSurr{border-color:var(--red);color:var(--red)}
  #lostBanner #lbGo{border-color:var(--line);color:var(--muted)}
  /* el color del ROL vive en la letra y en un filo lateral; la naturaleza es otra
     capa (texto de cuatro letras + su color), y el estado otra (el borde ámbar) */
  .rl-cont{color:var(--rcont)} .rl-cuar{color:var(--rcuar)} .rl-mut{color:var(--rmut)}
  /* EL FILO DEL ROL va en un pseudo-elemento y no en `border-left`: el borde de
     EN LÍNEA (.slot.exp) pone `border-color:amber` en los cuatro lados y borraría
     el filo, que es justo la identidad que hay que conservar. */
  .slots.e .slot::before{content:'';position:absolute;left:0;top:0;bottom:0;width:3px;
    border-radius:5px 0 0 5px;background:var(--line)}
  .slots.e .slot.r-cont::before{background:var(--rcont)}
  .slots.e .slot.r-cuar::before{background:var(--rcuar)}
  .slots.e .slot.r-mut::before{background:var(--rmut)}
  .slots.e .slot{padding-left:10px}
  /* LA NATURALEZA es una segunda capa: su color, y sobre todo su TEXTO de cuatro
     letras, que es lo que se lee sin depender del color. Los mismos valores que
     `.sector.s-*` y `#redOv[data-nat]`. */
  .slot .natx[data-nat="ESTRUCTURA"]{color:#5aa0ff}
  .slot .natx[data-nat="RUIDO"]{color:#ff8c3b}
  .slot .natx[data-nat="SEÑAL"]{color:#ffd84a}
  .slot .natx[data-nat="ECO"]{color:#c07aff}

  /* ── el DETALLE al tocar: el patrón .showprops de la carta, sin capa nueva ── */
  .slot .sdet{display:none}
  .slots.e .slot.showprops{flex:6 1 0}
  .slots.e .slot.showprops .sdet{display:flex;flex-direction:column;gap:1px;min-width:0}
  .slots.e .slot.showprops .sdl1,
  .slots.e .slot.showprops .sdl2{display:flex;align-items:baseline;gap:5px;min-width:0}
  .slots.e .slot.showprops .sdrol{font-size:8.5px;letter-spacing:.14em;font-weight:800;flex:0 0 auto}
  .slots.e .slot.showprops .sdnom{font-size:11.5px;color:var(--ink);font-weight:700;
    overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .slots.e .slot.showprops .sdl2 .natx{font-size:10px}
  .slots.e .slot.showprops .sdef{font-size:9.5px;color:var(--dim);letter-spacing:.02em;
    white-space:nowrap}
  /* con una abierta, las otras se contraen a su letra y la altura no cambia */
  .slots.e:has(.showprops) .slot:not(.showprops){flex:0 0 auto}
  .slots.e:has(.showprops) .slot:not(.showprops) .dat{display:none}
  /* y en la abierta, los datos compactos sueltan la naturaleza y el rango: el
     detalle ya los dice con su nombre entero, y repetirlos robaba el ancho */
  .slots.e .slot.showprops .dat .natx,
  .slots.e .slot.showprops .dat .mlv{display:none}

  /* ── REVELACIÓN: el estirón ya lo hace flex; esto añade el destello ── */
  .slot.recien{animation:slotRev .7s ease-out}
  .slot.recien .dat{animation:slotDat .5s ease-out .12s both}
  @keyframes slotRev{
    0%{background:rgba(255,255,255,.16); box-shadow:0 0 14px rgba(255,255,255,.28)}
    100%{background:rgba(10,13,19,.82); box-shadow:none} }
  @keyframes slotDat{ 0%{opacity:0; transform:translateY(-3px)} 100%{opacity:1; transform:none} }
  @media (prefers-reduced-motion:reduce){
    .slot.recien,.slot.recien .dat{animation:none}
    .slot{transition:none} }

  /* ---------- overlays ---------- */
  .overlay{position:fixed;inset:0;background:rgba(5,7,11,.86);display:none;
    align-items:center;justify-content:center;padding:16px;z-index:10}
  .overlay.on{display:flex}
  .box{background:var(--panel);border:1px solid var(--line);border-radius:10px;
    padding:22px;max-width:560px;width:100%;display:flex;flex-direction:column;gap:12px;
    max-height:88dvh;overflow-y:auto}
  .box h3{font-size:15px;letter-spacing:.14em}
  .box p{font-size:12.5px;line-height:1.6;color:var(--muted)}
  .box p strong{color:var(--ink)}
  .box .btns{display:flex;gap:8px;flex-wrap:wrap}
  .box .btns button{padding:12px 14px;font-size:12px;letter-spacing:.08em;flex:1}
  .box .btns .danger{border-color:var(--foe-dim);background:#241329}
  .box pre{font-size:10.5px;line-height:1.75;color:var(--muted);background:var(--bg);
    border:1px solid var(--line);border-radius:6px;padding:12px;overflow-x:auto}
  .big{font-size:22px;letter-spacing:.3em;font-weight:800}
  .big.win{color:var(--you)} .big.lose{color:var(--foe)}
  /* ── progresión v1 ── */
  #ctaProg{display:flex;flex-direction:column;gap:8px;padding:12px;
    background:var(--bg);border:1px solid var(--line);border-radius:8px}
  .progHead{display:flex;justify-content:space-between;align-items:baseline;
    font-size:11px;letter-spacing:.1em}
  .progHead b{color:var(--you);font-size:13px} .progHead span{color:var(--dim)}
  .progBar{height:8px;background:#0c1017;border:1px solid var(--line);
    border-radius:5px;overflow:hidden}
  .progBar i{display:block;height:100%;border-radius:5px;
    background:linear-gradient(90deg,var(--you-dim),var(--you));transition:width .5s ease}
  .progNext{font-size:11.5px;color:var(--muted);margin:0}
  .progNext b{color:var(--ink)}
  .pronto{color:var(--dim);font-size:9.5px;letter-spacing:.08em;text-transform:uppercase}
  #progVerMas{align-self:flex-start;padding:4px 0;background:none;border:none;
    color:var(--amber);font-size:10.5px;letter-spacing:.06em;cursor:pointer}
  .progLista{list-style:none;margin:2px 0 0;padding:0;display:flex;flex-direction:column;gap:5px}
  .progLista li{font-size:11px;color:var(--dim);display:flex;gap:8px;align-items:baseline}
  .progLista li.hecho{color:var(--muted)}
  .progLista .pl-n{color:var(--you-dim);width:16px;flex:none;text-align:center;
    font-variant-numeric:tabular-nums}
  .progLista li.hecho .pl-n{color:var(--you)}
  .nivelBox{align-items:center;text-align:center;max-width:420px;
    border-color:var(--you-dim);box-shadow:0 0 40px rgba(63,224,160,.25)}
  .nivelSpark{font-size:48px;color:var(--you);animation:nivelPop .6s ease}
  @keyframes nivelPop{0%{transform:scale(0) rotate(-40deg);opacity:0}
    60%{transform:scale(1.3) rotate(10deg)}100%{transform:scale(1) rotate(0);opacity:1}}
  .nivelUp{font-size:11px;letter-spacing:.3em;color:var(--muted);margin:0}
  .nivelBox h2{font-size:30px;letter-spacing:.16em;color:var(--you);margin:0}
  @media (prefers-reduced-motion:reduce){ .nivelSpark{animation:none} .progBar i{transition:none} }
  /* ── expediciones y anillos de entrenamiento ── */
  .pips{color:var(--you);letter-spacing:1px;font-size:10px}
  .pips .pip-off{color:var(--you-dim);opacity:.5}
  .expLink{display:block;word-break:break-all;background:var(--bg);border:1px solid var(--line);
    border-radius:6px;padding:10px 12px;color:var(--blue);font-size:12px;text-decoration:none}
  .expLink:hover{border-color:var(--blue)}
  #expCuerpo{display:flex;flex-direction:column;gap:10px}
  #expResp{margin:0}
  .expWin{font-size:44px;color:var(--you);text-align:center;animation:nivelPop .6s ease}
  .expAnillos{text-align:center;font-size:22px;letter-spacing:3px}
  .expAnillos span{font-size:12px;color:var(--dim);letter-spacing:.1em;margin-left:8px}
  /* ── pestañas de redes guardadas (N2) ── */
  #redesTabs{display:flex;gap:6px;flex-wrap:wrap;margin-bottom:2px}
  .redTab{padding:7px 14px;font-size:11px;letter-spacing:.06em;border:1px solid var(--line);
    background:var(--panel);color:var(--muted);border-radius:7px 7px 0 0;cursor:pointer}
  .redTab.on{border-color:var(--you-dim);border-bottom-color:var(--you);
    background:var(--panel2);color:var(--you)}
  .redTab.vacia{color:var(--dim);border-style:dashed}
  .redTab i{font-style:normal;opacity:.6;font-size:9.5px}
  /* ── taller de personajes (dev) ── */
  #taller{max-width:720px;margin:0 auto}
  #tallerLista{display:flex;flex-direction:column;gap:8px;margin:12px 0}
  .botCard{display:flex;gap:12px;align-items:center;background:var(--panel);
    border:1px solid var(--line);border-radius:9px;padding:10px 12px}
  .botAv{width:48px;height:48px;flex:none;background:var(--bg);border:1px solid var(--line);
    border-radius:6px;display:flex;align-items:center;justify-content:center;overflow:hidden}
  .botAvCv{width:100%;height:100%;image-rendering:pixelated}
  .botAvVacio{font-size:8px;color:var(--dim);text-align:center;line-height:1.2;letter-spacing:.05em}
  .botInfo{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
  .botInfo b{font-size:14px}
  .botTags{font-size:10px;color:var(--amber);letter-spacing:.05em}
  .botCartas{font-size:10.5px;color:var(--muted)}
  .botAcc{display:flex;gap:5px;flex-wrap:wrap;justify-content:flex-end}
  .botAcc .danger{border-color:var(--foe-dim);color:var(--foe)}
  #tallerEditor{background:var(--panel);border:1px solid var(--you-dim);border-radius:10px;
    padding:14px;margin-top:10px;display:flex;flex-direction:column;gap:10px}
  #tbCartas{display:flex;flex-direction:column;gap:8px}
  .tbCarta{background:var(--bg);border:1px solid var(--line);border-radius:7px;padding:9px 10px;
    display:flex;flex-direction:column;gap:6px}
  .tbRol{font-size:10px;letter-spacing:.14em;color:var(--dim)}
  .tbCarta .ctain{margin:0}
  .tbNats{display:flex;gap:5px;flex-wrap:wrap}
  .tbNat{padding:5px 9px;font-size:10px;letter-spacing:.05em;border:1px solid var(--line);
    background:var(--panel);color:var(--muted);border-radius:6px;cursor:pointer;
    display:inline-flex;align-items:center;gap:4px}
  .tbNat.on{border-color:var(--you);color:var(--you);background:var(--panel2)}
  .tbStats{display:flex;gap:14px;flex-wrap:wrap}
  .tbStats label{font-size:10.5px;color:var(--dim);letter-spacing:.05em;display:flex;
    align-items:center;gap:6px}
  .tbNum{width:52px;padding:5px 6px;background:var(--bg);border:1px solid var(--line);
    border-radius:5px;color:var(--ink);font-size:14px;text-align:center}
  .tbSeed{display:flex;gap:6px}
  .tbSeed .ctain{flex:1}
  .tbSeed .mini{flex:none}
  .tbCarOut{font-size:11px;color:var(--muted);min-height:1em}
  .tbAvatarRow{display:flex;gap:12px;align-items:center}
  .tbAvPrev{width:56px;height:56px;flex:none;background:var(--bg);border:1px solid var(--line);
    border-radius:6px;display:flex;align-items:center;justify-content:center;overflow:hidden}
  #tallerTelePanel{background:var(--panel);border:1px solid var(--you-dim);border-radius:10px;
    padding:14px;margin:10px 0}
  .teleGrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(130px,1fr));gap:10px}
  .teleCard{background:var(--bg);border:1px solid var(--line);border-radius:8px;padding:12px;text-align:center}
  .teleCard b{display:block;font-size:24px;color:var(--you);font-variant-numeric:tabular-nums}
  .teleCard span{font-size:10px;letter-spacing:.08em;color:var(--dim);text-transform:uppercase}
  /* CÓDIGO MEZCLADO: aviso de que algún js se quedó en una build anterior */
  #mixWarn{position:fixed;left:8px;right:8px;bottom:calc(8px + env(safe-area-inset-bottom));
    z-index:99;background:#2a1206;border:1px solid var(--amber,#ffc65c);border-radius:8px;
    padding:10px 12px;display:flex;flex-direction:column;gap:6px;font-family:var(--mono)}
  #mixWarn b{font-size:11px;letter-spacing:.16em;color:var(--amber,#ffc65c)}
  #mixWarn span{font-size:10.5px;line-height:1.45;color:#e8dcc6;overflow-wrap:anywhere}
  #mixWarn button{align-self:flex-start;padding:9px 14px;min-height:40px;font-size:10px;
    letter-spacing:.14em;border:1px solid var(--amber,#ffc65c);background:transparent;
    color:var(--amber,#ffc65c)}
  /* ⏱ MARCA DE HISTORIA (dev): una fila por episodio, legible en el móvil */
  .hdRow{display:flex;align-items:center;gap:9px;padding:6px 8px;border:1px solid var(--line);
    border-radius:6px;margin:3px 0;background:var(--bg)}
  .hdRow>b{color:var(--dim);width:12px;flex:none;text-align:center}
  .hdRow>span{flex:1;font-size:11px;letter-spacing:.04em;color:var(--muted);min-width:0}
  .hdRow.ok{border-color:var(--you-dim,#2f6f4a)}
  .hdRow.ok>b{color:var(--you)}
  .hdRow.ok>span{color:var(--ink)}
  .hdRow>button{padding:7px 9px;font-size:9.5px;letter-spacing:.1em;flex:none;min-height:34px}
  #endHist{font-size:10.5px;line-height:1.8;color:var(--muted);background:var(--bg);
    border:1px solid var(--line);border-radius:6px;padding:10px 12px;overflow-x:auto}
  #endHist b.you{color:var(--you)} #endHist b.foe{color:var(--foe)}
  #endHist .lbl{color:var(--dim);font-size:9px;letter-spacing:.12em;display:block;margin-bottom:4px}

  /* ---------- HOME (menú principal, mobile-first) ---------- */
  #title{display:flex;flex-direction:column;align-items:stretch;gap:14px;
    padding:2dvh 0 4dvh;text-align:left;max-width:460px;margin:0 auto;width:100%}
  /* escritorio: la home no debe quedar diminuta en el centro de una pantalla ancha */
  @media (min-width:720px){
    #title{max-width:640px;gap:18px;padding-top:4dvh}
    .spiritCard{padding:20px;gap:22px}
    .spiritCv{width:140px;height:176px}
    .spiritLbl{font-size:11px}
    .spiritWebs li{font-size:13px}
    .playCta{font-size:25px;padding:26px;letter-spacing:.28em}
    .homePillars{gap:14px}
    .pillar{min-height:92px;padding:18px}
    .pillar b{font-size:16px}
    .pillarSub{font-size:11px}
  }
  .homeTop{display:flex;justify-content:flex-end}
  .profilePill{display:inline-flex;align-items:center;gap:8px;font-size:11px;letter-spacing:.08em;
    color:var(--muted);background:var(--panel2);border:1px solid var(--line);border-radius:999px;
    padding:6px 12px;cursor:pointer;font-family:var(--mono)}
  .profilePill:hover{border-color:var(--you);color:var(--ink)}
  .profilePill .frag{color:var(--amber)}
  /* ciberspírit protagonista */
  .spiritCard{display:flex;gap:14px;align-items:center;background:
      radial-gradient(120% 90% at 20% 0%, rgba(63,224,160,.06), transparent 60%),
      linear-gradient(180deg,var(--panel2),var(--bg));
    border:1px solid var(--line);border-radius:12px;padding:14px}
  .spiritCv{width:104px;height:130px;flex:none;image-rendering:pixelated;
    filter:drop-shadow(0 0 10px rgba(63,224,160,.35));animation:spiritBreath 3.4s ease-in-out infinite}
  @keyframes spiritBreath{0%,100%{opacity:.86}50%{opacity:1}}
  @media (prefers-reduced-motion:reduce){ .spiritCv{animation:none} }
  .spiritInfo{flex:1;min-width:0;display:flex;flex-direction:column;gap:6px}
  .spiritLbl{font-size:10px;letter-spacing:.22em;color:var(--dim)}
  .spiritWebs{list-style:none;display:flex;flex-direction:column;gap:3px;margin:0;padding:0}
  .spiritWebs li{font-family:var(--mono);font-size:11.5px;color:var(--ink);letter-spacing:.02em;
    overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:flex;align-items:center;gap:6px}
  .spiritWebs li::before{content:'';width:6px;height:6px;flex:none;border-radius:1px;background:var(--dim)}
  .spiritWebs li.c-cont::before{background:var(--rcont)}
  .spiritWebs li.c-cuar::before{background:var(--rcuar)}
  .spiritWebs li.c-mut::before{background:var(--rmut)}
  .spiritWebs li.empty{color:var(--dim);font-style:italic}
  .spiritEdit{align-self:flex-start;margin-top:2px}
  /* CTA principal: lenguaje de los CTA del combate */
  .playCta{font-size:20px;font-weight:800;letter-spacing:.24em;padding:20px;border-radius:12px;
    color:var(--ink);border:1px solid var(--you);background:
      radial-gradient(120% 140% at 50% 0%, rgba(63,224,160,.22), transparent 70%),var(--panel2);
    box-shadow:0 0 22px rgba(63,224,160,.28), inset 0 0 0 1px rgba(63,224,160,.35);
    animation:goPulse 2s ease-in-out infinite;cursor:pointer}
  .playCta:hover{background:radial-gradient(120% 140% at 50% 0%, rgba(63,224,160,.34), transparent 70%),var(--panel2)}
  .playCta .pc-a{color:var(--you)}
  @media (prefers-reduced-motion:reduce){ .playCta{animation:none} }
  /* duelos en curso (contextual) */
  .homeDuels[hidden]{display:none}   /* gana a display:flex: si no hay duelos, NO ocupa */
  .homeDuels{display:flex;flex-direction:column;gap:8px;border:1px solid var(--amber);
    border-radius:10px;padding:12px;background:rgba(40,32,8,.35)}
  .homeDuels .hdHead{font-size:10px;letter-spacing:.16em;color:var(--amber)}
  .homeDuels .hdRow{display:flex;align-items:center;gap:10px;justify-content:space-between;
    background:var(--panel2);border:1px solid var(--line);border-radius:8px;padding:9px 11px;
    cursor:pointer;text-align:left}
  .homeDuels .hdRow:hover{border-color:var(--you)}
  .homeDuels .hdRow.mine{border-color:var(--you)}
  .homeDuels .hd-t{display:flex;flex-direction:column;gap:2px;min-width:0}
  .homeDuels .hd-s{font-size:9.5px;letter-spacing:.1em}
  .homeDuels .hd-s.turno{color:var(--you)} .homeDuels .hd-s.espera{color:var(--dim)}
  .homeDuels .hd-cta{font-size:11px;color:var(--you);white-space:nowrap}
  /* pilares LA RED / APRENDER */
  .homePillars{display:grid;grid-template-columns:1fr 1fr;gap:10px}
  .pillar{position:relative;display:flex;flex-direction:column;gap:5px;align-items:flex-start;text-align:left;
    padding:14px;border-radius:10px;background:linear-gradient(180deg,var(--panel2),var(--bg));
    border:1px solid var(--line);cursor:pointer;min-height:74px}
  /* señal contextual en LA RED: algo nuevo/asequible que capturar (sin ruido) */
  .pillDot{position:absolute;top:9px;right:9px;display:none;align-items:center;justify-content:center}
  .pillDot.on{display:flex}
  .pillDot.dot{width:8px;height:8px;border-radius:50%;background:var(--you);
    box-shadow:0 0 8px var(--you);animation:redDotPulse 1.7s ease-in-out infinite}
  .pillDot.count{min-width:17px;height:17px;padding:0 4px;border-radius:9px;background:var(--amber);
    color:#1a1305;font-size:9px;font-weight:800;font-family:var(--mono);
    box-shadow:0 0 8px rgba(255,198,92,.5)}
  @keyframes redDotPulse{0%,100%{opacity:.45}50%{opacity:1}}
  @media (prefers-reduced-motion:reduce){ .pillDot.dot{animation:none} }
  .pillar:hover{border-color:var(--you)}
  .pillar b{font-size:14px;letter-spacing:.12em}
  .pillar .pi{color:var(--amber)}
  .pillarSub{font-size:10px;color:var(--muted);letter-spacing:.04em;line-height:1.35}
  @media (max-width:360px){ .homePillars{grid-template-columns:1fr} }
  /* terciario */
  .homeTiny{display:flex;gap:6px;flex-wrap:wrap;justify-content:center;margin-top:2px}
  /* panel de modos */
  .modesList{display:flex;flex-direction:column;gap:10px;margin:6px 0 12px}
  .modesList button{padding:16px 18px;font-size:14px;font-weight:800;letter-spacing:.14em;text-align:left}
  .modesList button small{display:block;font-weight:400;color:var(--muted);font-size:9.5px;
    letter-spacing:.05em;margin-top:4px}
  .homeLegacy{display:none}
  #setup2p{display:none;flex-direction:column;gap:16px;padding-top:4dvh}
  #select{display:none}
  .glitch{position:relative;font-size:clamp(52px,15vw,100px);font-weight:800;
    letter-spacing:.3em;line-height:1;color:var(--ink);text-indent:.3em}
  .glitch::before,.glitch::after{content:attr(data-t);position:absolute;inset:0;text-indent:.3em}
  .glitch::before{color:var(--foe);z-index:-1;animation:gl1 2.7s infinite steps(1)}
  .glitch::after{color:var(--you);z-index:-2;animation:gl2 3.1s infinite steps(1)}
  @keyframes gl1{0%,88%{clip-path:inset(0 0 100% 0);transform:none}
    89%{clip-path:inset(12% 0 52% 0);transform:translate(-4px,1px)}
    93%{clip-path:inset(58% 0 12% 0);transform:translate(4px,-1px)}
    96%{clip-path:inset(30% 0 40% 0);transform:translate(-3px,0)}
    99%{clip-path:inset(0 0 100% 0)}}
  @keyframes gl2{0%,90%{clip-path:inset(100% 0 0 0);transform:none}
    91%{clip-path:inset(45% 0 30% 0);transform:translate(4px,2px)}
    95%{clip-path:inset(5% 0 75% 0);transform:translate(-4px,-1px)}
    98%{clip-path:inset(100% 0 0 0)}}
  @media (prefers-reduced-motion: reduce){
    .glitch::before,.glitch::after{animation:none;display:none}}
  .tsub{color:var(--muted);font-size:12px;letter-spacing:.12em;line-height:1.7}
  .tbtns{display:flex;gap:10px;flex-wrap:wrap;justify-content:center;align-items:center}
  .tbtns button{padding:16px 22px;font-size:14px;font-weight:800;letter-spacing:.16em}
  .tbtns button small{display:block;font-weight:400;color:var(--muted);font-size:9.5px;
    letter-spacing:.06em;margin-top:4px}
  .mini{font-size:10px;padding:6px 10px;color:var(--muted);letter-spacing:.1em}
  .scorebox{display:flex;gap:10px;align-items:center;color:var(--muted);font-size:11px;
    flex-wrap:wrap;justify-content:center}
  .scorebox .lbl{color:var(--dim);font-size:9px;letter-spacing:.14em}
  .scorebox b{color:var(--amber)}
  /* ── EL CIERRE DE LA CALIBRACIÓN, EN EL RESULTADO ───────────────────────────
     Mismo carril ámbar que la caja del PROTOCOLO en la mesa: es la misma voz, y quien
     la ha estado leyendo cinco minutos tiene que reconocerla aquí. Solo aparece cuando
     el duelo se acabó antes de que el guion llegara a su final (combate.js::showEnd). */
  #endCal{margin:2px 0 4px;padding:9px 12px 9px 11px;text-align:left;
    border-left:3px solid var(--amber);background:rgba(255,198,92,.06);
    font-size:12.5px;line-height:1.55;color:var(--ink)}
  #endCal .lbl{display:block;color:var(--dim);font-size:8.5px;letter-spacing:.16em;
    margin-bottom:5px}
  #endCal p{margin:0 0 4px;overflow-wrap:anywhere}
  #endCal p:last-child{margin:0}
  /* el cierre, separado de las lecciones pendientes que viajan con él */
  #endCal p.cal-fin{margin:0;padding-top:7px;border-top:1px solid var(--line)}
  #endCal p.cal-fin:first-of-type{padding-top:0;border-top:0}
  .names{display:flex;gap:10px;flex-wrap:wrap}
  .nameIn{background:var(--panel2);border:1px solid var(--line);border-radius:6px;
    color:var(--ink);font-family:var(--mono);padding:12px;font-size:14px;
    letter-spacing:.1em;text-transform:uppercase;width:170px}
  .nameIn:focus-visible{outline:2px solid var(--amber);outline-offset:2px}
  .rivalrow{display:none;gap:8px;flex-wrap:wrap;margin-top:12px}
  .rivalrow.on{display:flex}
  .rivalrow button{padding:10px 14px;font-size:11px;letter-spacing:.1em}
  .rivalrow .lbl{width:100%;color:var(--dim);font-size:10px;letter-spacing:.14em}
  #editor{display:none;flex-direction:column;gap:12px;padding-top:3dvh}
  /* 84vw y no 92: pedido por Andreu el 2-sep, «solo un poco más pequeña», para dejar
     sitio a la previsualización del Tejido sin que haya que hacer scroll para verla. */
  #pixgrid{display:grid;grid-template-columns:repeat(16,1fr);gap:1px;
    width:min(84vw,360px);touch-action:none;border:1px solid var(--line);
    border-radius:6px;padding:4px;background:var(--panel);cursor:crosshair}
  /* la rejilla del NÚCLEO (7×7): menos celdas y más grandes, y no necesita todo el ancho */
  #pixgrid.glifo{width:min(72vw,300px);gap:2px;padding:6px}
  #pixgrid.glifo .px{border-radius:2px}
  #pixgrid .px{aspect-ratio:1;border-radius:1px;background:#161d29}
  #pixgrid .px.bm{background:#131a2b}
  #pixgrid .px.bc{background:#152230}
  #pixgrid .px.bq{background:#182b28}
  #pixgrid .px.on{background:var(--you)}
  .hint2{color:var(--dim);font-size:9.5px;letter-spacing:.1em;min-height:12px}
  #gBody b{color:var(--ink)}
  .slots.l{display:none}
  .stage::after{content:'';position:absolute;inset:0;pointer-events:none;
    border-radius:8px;box-shadow:inset 0 0 90px rgba(0,0,0,.5)}
  @keyframes goPulse{0%,100%{box-shadow:0 0 0 0 rgba(63,224,160,0)}
    50%{box-shadow:0 0 14px 2px rgba(63,224,160,.35)}}
  #go:not(:disabled){animation:goPulse 1.8s ease-in-out infinite}
  @media (prefers-reduced-motion: reduce){#go{animation:none}}
  #vsOv{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
    gap:18px;pointer-events:none;opacity:0;transition:opacity .3s;z-index:4}
  #vsOv.on{opacity:1}
  #vsOv b{font-size:clamp(20px,4vw,34px);font-weight:800;letter-spacing:.2em;
    text-shadow:0 2px 14px rgba(0,0,0,.9)}
  #vsOv b:first-child{color:var(--you)} #vsOv b:last-child{color:var(--foe)}
  #vsOv i{color:var(--amber);font-size:16px;letter-spacing:.2em;font-style:normal}

  footer{color:var(--dim);font-size:9.5px;letter-spacing:.1em;text-align:center;line-height:1.8}
  @media (max-width:560px){
    .card{padding:9px 8px 18px;min-height:94px}
    .card .cname{font-size:10.5px}
    .card .num{font-size:16px;right:7px;top:11px}
    .card .role{font-size:8px}
    .card .note b{font-size:7.5px;padding:1px 4px}
    .hud{grid-template-columns:1fr 1fr}
    .turno{display:none}
    /* móvil: las dos cartas en fila (se ven desde el primer momento);
       el veredicto debajo, a todo el ancho */
    .clash{flex-wrap:wrap;gap:8px}
    #verdict{order:3;flex:1 1 100%;max-width:none;min-width:0;padding-top:0}
    .ccard{width:auto;flex:1 1 0;min-width:0;padding:7px 9px}
    .ccard .v{font-size:16px}
    .ccard .n{font-size:11px}
    .verdict b{font-size:13px}
    .verdict span{font-size:9.5px}
    .capPh{display:none}   /* la fase ya la dice el botón grande */
    /* arena a sangre: el campo de batalla manda en vertical (la altura la fija
       --camH; ver «CÁMARA ESTABLE») */
    .stage{margin-left:-12px;margin-right:-12px;border-radius:0}
  }

  /* ═══════════ PASADA DE MADUREZ · coherencia entre pantallas ═══════════ */
  /* párrafo introductorio unificado en todas las pantallas (no solo #select) */
  .lead{color:var(--muted);font-size:12.5px;line-height:1.6;max-width:72ch}
  #lared h2,#mired h2{font-size:16px;letter-spacing:.08em;margin:6px 0 2px}

  /* ── CONFIGURACIÓN ── */
  #cfgBtn{font-size:14px;line-height:1}
  .cfgBox{max-width:520px}
  .cfgList{display:flex;flex-direction:column;gap:0}
  .cfgGrp{font-size:9px;letter-spacing:.2em;color:var(--dim);margin:14px 0 2px;
    padding-bottom:4px;border-bottom:1px solid var(--line)}
  .cfgGrp:first-child{margin-top:0}
  .cfgRow{display:flex;align-items:center;gap:12px;padding:10px 2px}
  .cfgRow+.cfgRow{border-top:1px solid rgba(35,44,59,.5)}
  .cfgT{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
  .cfgT b{font-size:13px;font-weight:700;letter-spacing:.02em;color:var(--ink)}
  .cfgT span{font-size:10px;color:var(--dim);line-height:1.4}
  .cfgTog{flex:none;min-width:104px;text-align:center;font-family:var(--mono);font-size:11px;
    letter-spacing:.08em;padding:10px 12px;border:1px solid var(--you-dim);border-radius:8px;
    background:var(--panel2);color:var(--you);cursor:pointer}
  .cfgTog.off{border-color:var(--line);color:var(--dim)}
  .cfgTog:hover:not(:disabled){border-color:var(--you)}
  .cfgTog:disabled{opacity:.55;cursor:default;border-color:var(--line);color:var(--dim)}
  .cfgRange{flex:none;width:130px;accent-color:var(--you);cursor:pointer}
  /* selector de idioma */
  .langSel{display:flex;gap:6px;width:100%}
  .langBtn{flex:1;font-family:var(--mono);font-size:11.5px;letter-spacing:.03em;padding:10px 8px;
    border:1px solid var(--line);border-radius:8px;background:var(--panel2);color:var(--muted);cursor:pointer}
  .langBtn:hover{border-color:var(--you);color:var(--ink)}
  .langBtn.on{border-color:var(--you);color:var(--you);background:var(--panel);
    box-shadow:inset 0 0 0 1px var(--you-dim)}

  /* ── MI RED: presupuesto de 24 bytes como barra ── */
  /* El bloque de .budgetBox / .miredCompose / .mslot vivía aquí: barra de
     progreso, panel de la criatura y tres tarjetas redondeadas. Lo sustituye el
     compositor de más abajo. La barra de progreso en concreto era el widget que
     la ficha ya había descartado a propósito en favor de celdas discretas. */

  /* ── MI RED: sugerencia como AYUDA secundaria, no acción principal ── */
  .capsHead{display:flex;justify-content:space-between;align-items:center;gap:10px;
    margin-top:8px;flex-wrap:wrap}
  .capsHead .lead{flex:1;min-width:140px}
  .ghostBtn{flex:none;font-family:var(--mono);font-size:10px;letter-spacing:.06em;color:var(--dim);
    background:none;border:1px solid var(--line);border-radius:999px;padding:6px 13px;cursor:pointer}
  .ghostBtn:hover{color:var(--muted);border-color:var(--muted)}

  /* MI RED: JUGAR es la acción primaria (mismo lenguaje que #again / #go) */
  #miredPlay{flex:1.6;background:linear-gradient(180deg,#17392b,#10281f);
    border-color:var(--you-dim);font-weight:800;letter-spacing:.16em}
  #miredPlay:not(:disabled):hover{border-color:var(--you)}

  /* ── LA RED: legibilidad de las capturas en pantallas grandes ── */
  @media (min-width:760px){
    .wnode .nn{font-size:12px}
    .wnode .nd{font-size:9.5px}
    .wnode .ns{font-size:10px}
    .sector .sname{font-size:14px}
  }

  /* ── accesibilidad: "reducir animaciones" apaga los bucles decorativos,
        igual que prefers-reduced-motion (las transiciones puntuales siguen) ── */
  body.reduce-fx *,body.reduce-fx *::before,body.reduce-fx *::after{
    animation-duration:.001ms!important;animation-iteration-count:1!important}

  /* ── TEJIDOS DE HISTORIA (taller dev): diseñador de personajes de campaña ── */
  #tejidosPanel{display:flex;flex-direction:column;gap:10px;margin:10px 0}
  #tejidosPanel textarea,#tejidosPanel input,
  #tjed textarea,#tjed input[type=text],#tjed input:not([type]),#tjed input[type=number]{
    background:var(--panel);border:1px solid var(--line);
    border-radius:7px;color:var(--ink);font-family:var(--mono);font-size:12px;padding:7px 9px;width:100%}
  #tejidosPanel textarea,#tjed textarea{color:var(--dim);resize:vertical;line-height:1.5}
  #tejidosPanel textarea:focus,#tejidosPanel input:focus,
  #tjed textarea:focus,#tjed input:focus{outline:1px solid var(--you);color:var(--ink)}

  /* ── ÍNDICE: los seis Tejidos con la figura que va a la historia ── */
  /* ═══ COMPONER MI RED ═══════════════════════════════════════════════════════
     Habla el idioma del índice: VT323 a su escala, filetes finos, sin tarjetas.
     El dictamen con las medidas: docs/componer-mi-red-dictamen.md.
     Las clases del listado (.sector, .shead, .sgrid, .wls) NO se duplican aquí:
     sus selectores están compartidos con #lared más arriba, para que las dos
     pantallas no se separen. */
  #mired h2, #mired #redResumen{font-family:'VT323',var(--mono)}
  #mired .tbtns button{font-family:'VT323',var(--mono);letter-spacing:.08em;
    background:transparent;border:1px solid #1e8f45;color:#3aff6e;
    text-shadow:0 0 6px rgba(58,255,110,.45)}
  #mired .tbtns #miredPlay{border-color:#3aff6e;font-size:19px}
  #mired .tbtns #miredPlay:disabled{border-color:#143d22;color:#1e8f45;
    text-shadow:none;opacity:.75}

  /* ── COMPOSITOR · fijo arriba, una sola altura, ~185px ──
     Antes eran 326px de 740 y no era sticky: al bajar a la colección
     desaparecía, y con ella el contexto del rol activo. */
  .mrComp{position:sticky;top:0;z-index:6;margin:8px 0 6px;padding:8px 10px 9px;
    border:1px solid var(--line);border-top:2px solid #1e8f45;border-radius:10px;
    background:linear-gradient(180deg,rgba(8,16,12,.97),rgba(6,10,14,.97));
    backdrop-filter:blur(3px);display:flex;flex-direction:column;gap:7px}
  /* MEMORIA · celdas discretas, nunca una barra de relleno */
  .mrMemTop{display:flex;align-items:baseline;gap:8px;
    font-family:'VT323',var(--mono);font-size:17px}
  .mrMemTop .mrLbl{color:#1e8f45;letter-spacing:.1em}
  .mrMemTop .mrMemN{color:#3aff6e;font-weight:400;font-variant-numeric:tabular-nums}
  .mrMemTop .mrMemN b{color:#eaffef}
  .mrMemTop .mrMemFree{margin-left:auto;color:var(--faint);font-size:15px;letter-spacing:.04em}
  /* las 24 celdas van en su PROPIA línea: compartiendo línea con rótulo y cifra
     medirían 357px y el ancho útil a 360 es 324 (medido) */
  .mrCel{display:flex;gap:2px;align-items:stretch;height:9px}
  .mrCel i{flex:1;min-width:0;background:rgba(255,255,255,.07)}
  .mrCel i.on{background:#3aff6e;box-shadow:0 0 5px rgba(58,255,110,.5)}
  .mrCel i.ex{background:var(--red,#ff5c5c);box-shadow:0 0 5px rgba(255,92,92,.55)}
  .mrMem.over .mrMemN b{color:var(--red,#ff5c5c)}
  .mrMem.over .mrMemFree{color:var(--red,#ff5c5c)}

  .mrBody{display:flex;gap:9px;align-items:stretch}
  .mrSpirit{flex:0 0 auto;display:flex;align-items:center;justify-content:center;
    border:1px solid var(--line);border-radius:8px;padding:3px;
    background:radial-gradient(circle at 50% 45%,rgba(63,224,160,.07),transparent 70%)}
  .mrSpirit canvas{display:block;width:72px;height:96px;image-rendering:pixelated}
  .mrRoles{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
  /* cada rol es una FILA, y el activo se marca con cursor «>»: eso sustituye a la
     línea «eligiendo tu…», que gastaba altura repitiendo el mismo estado */
  .mrRole{flex:1;min-height:30px;display:flex;align-items:baseline;gap:6px;
    background:transparent;border:0;border-left:2px solid transparent;
    padding:2px 5px;text-align:left;cursor:pointer;color:var(--ink);
    font-family:'VT323',var(--mono);font-size:17px;letter-spacing:.02em}
  .mrRole .mrCur{flex:0 0 9px;color:var(--amber);white-space:pre}
  .mrRole .mrRol{flex:0 0 auto;letter-spacing:.07em;font-size:15px}
  .mrRole.rc-cont .mrRol{color:var(--rcont)} .mrRole.rc-cuar .mrRol{color:var(--rcuar)}
  .mrRole.rc-mut .mrRol{color:var(--rmut)}
  .mrRole .mrDom{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;
    white-space:nowrap;color:#e8eef7}
  /* una sola línea: partido en dos descuadraba la altura de esa fila y el «↓»
     se quedaba solo abajo, que parecía un error de maquetación */
  .mrRole .mrVac{flex:1;min-width:0;color:var(--faint);font-size:15px;
    overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .mrRole .mrStx{color:var(--faint);font-size:15px}
  .mrRole.act{background:rgba(58,255,110,.07);border-left-color:#3aff6e}
  /* el color de la naturaleza tiñe el dominio, como en el índice */
  [data-nat="ESTRUCTURA"]{--sc:#5aa0ff} [data-nat="RUIDO"]{--sc:#ff8c3b}
  [data-nat="SEÑAL"]{--sc:#ffd84a} [data-nat="ECO"]{--sc:#c07aff}
  .mrRole .mrDom[data-nat]{color:var(--sc)}

  .mrTools{display:flex;margin:2px 0 8px}
  .mrTools #msAuto{flex:1;font-family:'VT323',var(--mono);font-size:16px;
    letter-spacing:.08em;background:transparent;border:1px solid var(--line);
    border-radius:8px;color:var(--amber);padding:7px 10px;cursor:pointer}

  /* ── LA COLECCIÓN · carpetas por naturaleza, como el índice ── */
  /* minmax(0,1fr) y no 1fr: `1fr` es `minmax(auto,1fr)` y la pista NO baja del
     contenido mínimo, así que la segunda línea de la fila (nowrap) empujaba la
     rejilla y el documento desbordaba 78px a 360. No se veía en la medición
     porque la emulación móvil «reduce para encajar»: ensanchaba el viewport de
     360 a 438 en vez de desbordar. */
  #capsGrid{display:grid;grid-template-columns:minmax(0,1fr);gap:14px;margin:0 0 14px}
  @media (min-width:760px){ #capsGrid{grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:18px} }
  #mired .sector, #mired .sgrid, #mired .wls{min-width:0}
  /* la descripción en UNA línea: «comodín · encaja en cualquier rol» partía en
     dos y empujaba el nombre de la carpeta hacia abajo, desalineando la cabecera */
  #mired .sector .shead{align-items:center}
  /* el nombre de la carpeta NO se encoge ni parte: con la descripción larga de ECO
     el flex lo estrujaba y «▸» se quedaba solo en una línea sobre «ECO/» */
  #mired .sector .shead .sname{flex:0 0 auto;white-space:nowrap}
  #mired .sector .shead .sdesc{font-family:'VT323',var(--mono);font-size:15px;
    min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  #mired .sector .shead .scount{flex:0 0 auto}
  /* la fila: línea 1 igual que en el índice; línea 2 lo que hace falta para
     ELEGIR (asignación, encaje, habilidad, si cabe) */
  #mired .wls{flex-direction:column;align-items:stretch;gap:0;padding:4px 8px 5px}
  #mired .wls .l1{display:flex;align-items:baseline;gap:8px;min-width:0}
  #mired .wls .l2{display:flex;align-items:baseline;gap:5px;flex-wrap:nowrap;
    min-width:0;overflow:hidden;padding-left:30px;font-size:14px;
    color:var(--faint);letter-spacing:.03em;white-space:nowrap}
  #mired .wls .l2 > *{flex:0 0 auto}
  #mired .wls .l2ab{flex:0 1 auto;overflow:hidden;text-overflow:ellipsis}
  /* en pantalla estrecha, la fila sugerida lleva el texto más largo de todos
     («★ MEJOR ENCAJE LIBRE PARA MUTACIÓN») y el recorte partía la naturaleza a
     media palabra («SEÑA…»). Ahí se cede la habilidad, que además está en el
     `title` y en la ficha. */
  @media (max-width:420px){ #mired .wls.sugerida .l2ab{display:none} }
  #mired .wls .l2s{color:var(--line)}
  #mired .wls .l2nat[data-nat]{color:var(--sc)}
  #mired .wls .l2ab{color:var(--dim)}
  #mired .wls .l2rol{color:#3aff6e;letter-spacing:.06em;font-weight:400}
  #mired .wls .l2sug{color:var(--amber);letter-spacing:.05em;font-weight:400}
  #mired .wls .l2no{color:var(--red,#ff5c5c);letter-spacing:.05em;font-weight:400}
  /* los BYTES no son las stats: van con su unidad, en ámbar apagado y separados,
     porque «5·⛨5  5 B» seguidos y del mismo color se leían como un solo dato */
  #mired .wls .mrB, .mrRole .mrB{color:#a8842e;font-size:15px;
    font-variant-numeric:tabular-nums;flex:0 0 auto;padding-left:3px}
  #mired .wls .st .sug{color:var(--amber)}
  #mired .wls .st .pt{color:var(--line)}
  /* PUESTA: la web no se mueve de su carpeta; solo cambia su marca. Eso es lo que
     permitió quitar el reordenado, que movía 9 de cada 10 filas. */
  #mired .wls.puesta{border-left-color:#3aff6e;background:rgba(58,255,110,.05)}
  #mired .wls.sugerida{border-left-color:var(--amber)}
  /* NO CABE: se atenúa, pero se puede tocar igual — cambiar de web libera bytes */
  #mired .wls.nocabe .dom, #mired .wls.nocabe .stx{opacity:.5}
  /* objetivo táctil de 44px aunque la fila se vea fina */
  #mired .wls, .mrRole{min-height:44px}
  @media (min-width:760px){ #mired .wls, .mrRole{min-height:0} }

  /* ═══ DEMO PROCEDURAL (taller dev) ════════════════════════════════════════
     Rejilla de figuras para juzgar el generador. Mobile-first: en un móvil de
     360px caben dos columnas de 132px de canvas sin que nada se salga, y crece
     con el ancho por auto-fill en vez de por breakpoints. */
  #lecOv .lec-donde{font-size:15px;color:#1e8f45;letter-spacing:.04em;margin-top:2px}
  /* LLEVA A OTRA WEB · ámbar, porque no es un fallo: es una bifurcación */
  #lecOv .lec-salto{font-size:22px;letter-spacing:.14em;color:var(--amber);
    text-shadow:0 0 10px rgba(255,216,74,.4)}
  #lecOv .lec-out .lec-x{margin:12px auto 0}
  .lec-retry{margin-top:7px;font-family:'VT323',var(--mono);font-size:16px;
    color:var(--amber);letter-spacing:.03em;text-align:center;opacity:.9}
  .dmCtl{display:flex;flex-wrap:wrap;gap:5px;align-items:center;margin:8px 0 10px}
  .dmCtl .dmL{font:600 9.5px/1 var(--mono);letter-spacing:.09em;text-transform:uppercase;
    color:var(--dim);margin-left:6px}
  .dmCtl .dmL:first-child{margin-left:0}
  .dmSel.on{border-color:var(--you);color:var(--you);background:rgba(63,224,160,.12)}
  .dmGrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(158px,1fr));gap:8px}
  .dmCard{display:flex;flex-direction:column;gap:3px;align-items:stretch;
    background:var(--panel);border:1px solid var(--line);border-radius:9px;padding:6px;
    cursor:pointer;text-align:left;color:inherit;font:inherit}
  .dmCard:hover{border-color:var(--you)}
  .dmCard canvas{width:100%;height:auto;display:block;border-radius:6px;background:#070a10}
  .dmCard .dmT{font:600 10px/1.25 var(--mono);letter-spacing:.05em;color:var(--dim)}
  .dmCard .dmT b{color:var(--ink);margin-left:4px;letter-spacing:.03em}
  .dmCard .dmS{font:500 9.5px/1.3 var(--mono);color:var(--dim);display:flex;
    align-items:center;gap:3px;flex-wrap:wrap}
  .dmN{width:8px;height:8px;border-radius:2px;display:inline-block;flex:0 0 auto}
  /* la grande: a escala de arena, que es donde se juzga de verdad */
  #dmOv{position:fixed;inset:0;z-index:90;background:rgba(4,7,12,.86);
    display:none;align-items:center;justify-content:center;padding:14px}
  .dmOvBox{background:var(--panel);border:1px solid var(--line);border-radius:12px;
    padding:12px;max-width:min(94vw,340px);width:100%}
  .dmOvH{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:8px}
  .dmOvH b{font:700 12px/1 var(--mono);letter-spacing:.05em}
  .dmOvH span{font:500 10px/1 var(--mono);color:var(--dim);flex:1}
  #dmOvCv{width:100%;height:auto;display:block;border-radius:8px;background:#070a10}
  .dmOvF{display:flex;flex-direction:column;gap:3px;margin-top:9px;
    font:500 10px/1.4 var(--mono);color:var(--dim)}
  .dmOvF span{display:flex;align-items:center;gap:5px}
  .tjIdx{display:flex;flex-direction:column;gap:9px}
  .tjCard{background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:9px}
  .tjCardH{display:flex;align-items:center;gap:8px;margin-bottom:8px}
  .tjCardH b{font-size:13px;letter-spacing:.1em}
  .tjCardH span{font-size:9px;letter-spacing:.12em;color:var(--dim);margin-left:auto;text-transform:uppercase}
  .tjVers{display:flex;gap:7px;overflow-x:auto;padding-bottom:3px}
  .tjVer{flex:0 0 auto;width:112px;display:flex;flex-direction:column;align-items:center;gap:3px;
    background:radial-gradient(120% 90% at 50% 36%, #0c111b, #060911);
    border:1px solid var(--line);border-radius:9px;padding:6px 5px;cursor:pointer}
  .tjVer canvas{image-rendering:pixelated;width:64px;height:76px}
  .tjVerT{font-size:9px;line-height:1.3;color:var(--ink);text-align:center;overflow-wrap:anywhere}
  .tjVerN{font-size:8px;letter-spacing:.06em;color:var(--dim)}

  /* ── PANTALLA DE EDICIÓN ── */
  #tjed{max-width:720px;margin:0 auto;display:flex;flex-direction:column;gap:10px;
    padding-bottom:calc(74px + env(safe-area-inset-bottom))}   /* hueco para la barra de acciones */
  .tjTop{display:flex;align-items:center;gap:8px;flex-wrap:wrap;
    border-bottom:1px solid var(--line);padding-bottom:9px}
  .tjTop>button{flex:0 0 auto}
  /* los dos desplegables piden toda una línea: apretados junto al botón, el
     nombre del Tejido se recortaba a tres letras («CAR…») */
  .tjWho{display:flex;align-items:center;gap:6px;flex:1 0 100%;order:2;min-width:0}
  .tjWho select{flex:1 1 0;min-width:0;background:var(--panel);border:1px solid var(--line);
    border-radius:7px;color:var(--ink);font-family:var(--mono);font-size:11.5px;
    letter-spacing:.06em;padding:8px 7px;min-height:42px}
  .tjWho #tjSelV{flex:1.5 1 0}
  .tjSave{flex:1 1 auto;font-size:9px;letter-spacing:.12em;color:var(--dim);text-align:right}
  #tjed input[type=color]{flex:0 0 auto;width:46px;height:38px;padding:2px;
    background:var(--panel);border:1px solid var(--line);border-radius:7px}
  .tjStripWrap{display:flex;flex-direction:column;gap:4px}
  .tjStrip{display:flex;gap:8px;overflow-x:auto;padding:2px 0 6px}
  .tjTabs{display:flex;border:1px solid var(--line);border-radius:8px;overflow:hidden}
  .tjTabs button{flex:1;border:0;border-radius:0;padding:12px 6px;font-size:11px;font-weight:700;
    letter-spacing:.16em;background:transparent;color:var(--dim);min-height:44px}
  .tjTabs button+button{border-left:1px solid var(--line)}
  .tjTabs button.on{color:var(--you);background:rgba(63,224,160,.08);box-shadow:inset 0 -2px 0 var(--you)}
  #tjTabBody{display:flex;flex-direction:column;gap:9px}
  .tjFig{background:radial-gradient(120% 90% at 50% 34%, #0c111b, #060911);
    border:1px solid var(--line);border-radius:10px;padding:8px;
    display:flex;flex-direction:column;gap:7px;align-items:center}
  .tjFig canvas{width:100%;max-width:300px;height:auto;image-rendering:pixelated}
  .tjSeg{display:flex;border:1px solid var(--line);border-radius:8px;overflow:hidden}
  .tjSeg button{flex:1;border:0;border-radius:0;background:transparent;color:var(--dim);
    font-size:10.5px;letter-spacing:.1em;padding:11px 6px;min-height:42px}
  .tjSeg button+button{border-left:1px solid var(--line)}
  .tjSeg button.on{color:var(--you);background:rgba(63,224,160,.08)}
  .tjBig{width:100%;padding:12px;font-size:11px;letter-spacing:.14em;color:var(--you);
    border-color:var(--you);min-height:46px}
  .tjZona{border:1px dashed var(--red,#ff5c5c);border-radius:9px;padding:9px;margin-top:6px;
    display:flex;flex-direction:column;gap:7px}
  .tjZona .tjLbl{color:var(--red,#ff5c5c)}
  .tjActs{position:fixed;left:0;right:0;bottom:0;z-index:40;display:flex;gap:8px;
    padding:9px 12px calc(9px + env(safe-area-inset-bottom));
    background:linear-gradient(180deg, transparent, var(--bg) 34%);
    border-top:1px solid var(--line)}
  .tjActs button{flex:1;min-height:46px;font-size:11px;letter-spacing:.12em;font-weight:700}
  #tjElegir{color:var(--gold,#ffc65c);border-color:var(--gold,#ffc65c)}
  #tjElegir.on{color:var(--dim);border-color:var(--line);font-weight:400}
  body.scr-battle .tjActs{display:none}
  .tjLbl{font-size:9px;letter-spacing:.18em;color:var(--dim);text-transform:uppercase}
  .tjChips{display:flex;flex-wrap:wrap;gap:5px}
  .tjChip{display:flex;align-items:center;gap:6px;font-size:11px;padding:6px 9px}
  .tjChip.mini{font-size:10px;padding:4px 8px}
  .tjChip.on{color:var(--you);box-shadow:inset 0 0 0 1px var(--you)}
  .tjDot{width:8px;height:8px;border-radius:50%;flex:0 0 auto}
  .tjVerRow{display:flex;gap:6px;align-items:center}
  .tjCands{display:flex;gap:8px;overflow-x:auto;padding:2px 0 6px}
  .tjCand{flex:0 0 auto;width:112px;background:radial-gradient(120% 90% at 50% 40%, #0c111b, #060911);
    border:1px solid var(--line);border-radius:9px;padding:4px;cursor:pointer;text-align:center}
  .tjCand canvas{width:104px;height:122px;image-rendering:pixelated;display:block}
  .tjCand.sel{border-color:var(--you)}
  .tjCand.win{box-shadow:0 0 0 1px var(--gold,#ffc65c) inset}
  .tjCandTag{font-size:8.5px;color:var(--dim);display:block;margin-top:2px;letter-spacing:.03em;
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .tjCand.tjMas{display:flex;flex-direction:column;align-items:center;justify-content:center;
    gap:1px;width:88px;color:var(--dim);font-size:10.5px;line-height:1.35;min-height:120px;
    font-family:var(--mono)}
  .tjCand.tjMas i{font-style:normal;font-size:8.5px;letter-spacing:.06em;opacity:.72}
  .tjRead{font-size:10px;color:var(--dim);text-align:center;letter-spacing:.04em}
  .tjRead b{color:var(--ink)}
  .tjNuc{display:flex;flex-direction:column;gap:6px;align-items:center}
  #tjGrid{border:1px solid var(--line);border-radius:8px;background:#080b11;cursor:crosshair;
    width:288px;max-width:100%;image-rendering:pixelated}
  .tjTools{display:flex;gap:4px;flex-wrap:wrap;justify-content:center}
  .tjWebs{display:flex;flex-direction:column;gap:8px}
  .tjWeb{background:var(--panel);border:1px solid var(--line);border-radius:9px;padding:8px;
    display:flex;flex-direction:column;gap:6px}
  .tjNats{display:flex;gap:4px;flex-wrap:wrap}
  .tjNats .on{box-shadow:inset 0 0 0 1px currentColor}
  .tjStats{display:flex;gap:12px;font-size:10px;color:var(--dim);flex-wrap:wrap}
  .tjStats label{display:flex;align-items:center;gap:5px;flex:0 0 auto}
  #tejidosPanel .tjStats input,#tjed .tjStats input{width:58px;flex:0 0 auto;text-align:center}
  /* dibujo directo de Tejidos (pixel art 27×36) */
  .tjInks{display:flex;gap:4px;flex-wrap:wrap;justify-content:center}
  .tjInks .on{box-shadow:inset 0 0 0 1px currentColor}
  #tjGridD{border:1px solid var(--line);border-radius:8px;background:#080b11;cursor:crosshair;
    width:100%;max-width:351px;image-rendering:pixelated}
  /* modo edición ampliado de Tejidos */
  #tjOv{position:fixed;inset:0;z-index:340;background:rgba(4,6,10,.96);display:none;
    align-items:center;justify-content:center;padding:12px}
  .tjOvIn{display:flex;gap:16px;align-items:flex-start;max-height:100%;overflow:auto}
  .tjOvIzq canvas{image-rendering:pixelated;border:1px solid var(--line);border-radius:10px;
    background:#080b11;cursor:crosshair;display:block;max-width:100%;height:auto}
  .tjOvDer{display:flex;flex-direction:column;gap:10px;width:170px;flex:0 0 auto}
  .tjOvReal{background:radial-gradient(120% 90% at 50% 40%, #0c111b, #060911);
    border:1px solid var(--line);border-radius:10px;padding:8px;display:flex;justify-content:center}
  .tjOvReal canvas{image-rendering:pixelated;width:108px;height:144px}
  .tjInksV{flex-direction:column;align-items:stretch}
  .tjInksV .mini{text-align:left}
  #tjGuardarB{margin-top:auto;color:var(--you);border-color:var(--you);padding:9px 10px;font-weight:700}
  @media (max-width:700px){ .tjOvIn{flex-direction:column;align-items:center} 
    .tjOvDer{width:100%;flex-direction:row;flex-wrap:wrap;align-items:center}
    .tjInksV{flex-direction:row} #tjGuardarB{margin:0 0 0 auto} }

  /* ── MODO HISTORIA (F1): CANAL DIRECTO · REGISTROS · EL ARCHIVO ── */
  #histBadge{display:block;margin:10px auto 2px;padding:10px 14px;max-width:420px;width:calc(100% - 24px);
    background:#03120a;border:1px solid #0c3a1d;border-radius:9px;cursor:pointer;text-align:left;
    font-family:'VT323',var(--mono,monospace);font-size:17px;letter-spacing:.06em;color:#1e8f45}
  #histBadge b{color:#3aff6e;text-shadow:0 0 7px rgba(58,255,110,.55)}
  #histBadge.pend{border-color:#1e8f45;box-shadow:0 0 16px rgba(58,255,110,.14), inset 0 0 14px rgba(58,255,110,.05)}
  #histBadge .hb-cur{display:inline-block;width:.55em;height:1em;background:#3aff6e;vertical-align:-2px;
    margin-left:6px;animation:trmcur .9s steps(1) infinite}
  body.reduce-fx #histBadge .hb-cur{animation:none}
  #histOv{position:fixed;inset:0;z-index:75;display:none;align-items:center;justify-content:center;
    background:rgba(1,5,2,.92);font-family:'VT323',var(--mono,monospace)}
  #histOv.on{display:flex}
  #histOv .ho-in{width:min(94vw,560px);max-height:88dvh;overflow-y:auto;background:#010502;
    border:1px solid #0c3a1d;border-radius:12px;padding:16px 18px;color:#3aff6e;
    text-shadow:0 0 6px rgba(58,255,110,.5);display:flex;flex-direction:column;gap:10px}
  #histOv .ho-top{display:flex;justify-content:space-between;align-items:center}
  #histOv .ho-t{font-size:15px;letter-spacing:.28em;color:#1e8f45}
  #histOv .ho-tx{font-size:20px;line-height:1.5}
  #histOv .ho-tx b{color:#b8ffce}
  #histOv .ho-cond{display:block;font-size:15px;color:#1e8f45;margin-top:4px}
  #histOv #hoPlay{padding:13px;background:transparent;border:1px solid #3aff6e;color:#3aff6e;
    font-family:inherit;font-size:19px;letter-spacing:.16em;cursor:pointer;border-radius:6px;
    text-shadow:0 0 7px rgba(58,255,110,.55);box-shadow:0 0 14px rgba(58,255,110,.16)}
  /* la puerta a EL ARCHIVO: presente pero claramente subordinada al botón de
     la transmisión (borde punteado y apagado, no el verde brillante del CTA) */
  #histOv .ho-door{display:flex;align-items:center;gap:10px;text-align:left;
    background:transparent;border:1px dashed #0c3a1d;border-radius:8px;padding:11px 12px;
    color:#1e8f45;font-family:inherit;font-size:15px;cursor:pointer;margin-top:2px}
  #histOv .ho-door b{color:#3aff6e;letter-spacing:.16em;flex:0 0 auto}
  #histOv .ho-door span{flex:1;font-size:14px;letter-spacing:.03em;line-height:1.3}
  #histOv .ho-door i{font-style:normal;color:#3aff6e;flex:0 0 auto}
  #histOv .ho-door:hover{border-color:#1e8f45}
  #histOv .ho-back{align-self:flex-start;background:transparent;border:1px solid #0c3a1d;
    border-radius:6px;color:#1e8f45;font-family:inherit;font-size:14px;letter-spacing:.14em;
    padding:8px 11px;cursor:pointer;min-height:40px}
  #histOv .ho-tabs{display:flex;border:1px solid #0c3a1d;border-radius:8px;overflow:hidden}
  #histOv .ho-tabs button{flex:1;background:transparent;border:0;border-radius:0;
    color:#1e8f45;font-family:inherit;font-size:13px;letter-spacing:.1em;padding:11px 4px;
    cursor:pointer;min-height:44px;display:flex;flex-direction:column;align-items:center;gap:1px}
  #histOv .ho-tabs button+button{border-left:1px solid #0c3a1d}
  #histOv .ho-tabs button i{font-style:normal;font-size:12px;opacity:.65}
  #histOv .ho-tabs button.on{color:#3aff6e;background:rgba(58,255,110,.07);
    box-shadow:inset 0 -2px 0 #3aff6e}
  #histOv .ho-sec{font-size:13px;letter-spacing:.24em;color:#1e8f45;border-top:1px solid #0c3a1d;padding-top:9px}
  #histOv .ho-sec span{letter-spacing:.04em}
  #histOv .ho-list{display:flex;flex-direction:column;gap:5px}
  #histOv .ho-reg{text-align:left;background:transparent;border:1px solid #0c3a1d;border-radius:6px;
    color:#3aff6e;font-family:inherit;font-size:16px;padding:7px 10px;cursor:pointer;letter-spacing:.04em}
  #histOv .ho-reg:hover{border-color:#1e8f45}
  #histOv .ho-frag{border:1px dashed #0c3a1d;border-radius:6px;padding:7px 10px;font-size:15px;line-height:1.45}
  #histOv .ho-frag b{display:block;color:#b8ffce}
  #histOv .ho-frag span{color:#1e8f45}
  #histOv .ho-vacio{color:#1e8f45;font-size:14px}
  #histOv .mini{background:transparent;border:1px solid #0c3a1d;color:#1e8f45;font-family:inherit;
    padding:4px 9px;cursor:pointer;border-radius:5px}
  /* el EVENTO (A1·E6): glitch sin magenta — tearing/desfase breve */
  @keyframes histGlitch{
    0%{transform:translate(0)}8%{transform:translate(-7px,2px) skewX(-2deg)}16%{transform:translate(5px,-1px)}
    24%{transform:translate(-3px,0) skewX(1.4deg)}36%{transform:translate(6px,2px)}
    48%{transform:translate(-5px,-2px) skewX(-1deg)}62%{transform:translate(2px,1px)}100%{transform:translate(0)}}
  body.hist-glitch #battle{animation:histGlitch .7s steps(2,end);filter:contrast(1.35) saturate(.6)}
  body.reduce-fx.hist-glitch #battle{animation:none;filter:none}
  #histBanner{position:fixed;left:50%;top:34%;transform:translate(-50%,-50%);z-index:85;display:none;
    font-family:'VT323',var(--mono,monospace);text-align:center;pointer-events:none}
  #histBanner.on{display:block;animation:mlin .25s ease-out}
  #histBanner .hb-a{display:block;font-size:22px;color:#5f6f86;text-decoration:line-through;letter-spacing:.2em}
  #histBanner .hb-b{display:block;font-size:56px;color:#e8eef7;letter-spacing:.3em;
    text-shadow:0 0 18px rgba(232,238,247,.6)}
  /* historia: web retenida (E6→E7) y ficha con campo nuevo */
  .wls.ret{border-color:var(--red,#ff5c5c);opacity:.85}
  .wls .retx{color:var(--red,#ff5c5c)}
  .wls .anx{color:#c58bff;margin-left:4px}

  /* ── SKINS de fósforo (recompensa de historia). El CANAL DIRECTO y el terminal
        de LA RED (trmOv) NO se re-colorean jamás: la voz es verde (plan §2). ── */
  body.skin-ambar #lared, body.skin-ambar #mired,
  body.skin-ambar #histOv .ho-sec, body.skin-ambar #histOv .ho-list{
    filter:hue-rotate(-96deg) saturate(1.25) brightness(1.04)}
  body.skin-p4 #lared, body.skin-p4 #mired,
  body.skin-p4 #histOv .ho-sec, body.skin-p4 #histOv .ho-list{
    filter:saturate(.1) brightness(1.18)}
  /* trazas e insignias en el canal */
  #histOv .ho-reg.done{border-color:#1e8f45;opacity:.72}
  #histOv .ho-ins{font-size:12px;letter-spacing:.14em;color:#1e8f45;margin-left:auto;margin-right:10px}
  #histOv .ho-ins b{color:#b8ffce;font-weight:400}
  #cfgSkins{display:flex;gap:6px;flex-wrap:wrap}
  #cfgSkins button{font-family:var(--mono);font-size:10px;padding:5px 9px;border:1px solid var(--line);
    border-radius:6px;background:var(--panel2);color:var(--muted);cursor:pointer}
  #cfgSkins button.on{color:var(--you);box-shadow:inset 0 0 0 1px var(--you)}
  #cfgSkins button:disabled{opacity:.4;cursor:default}

  /* ── LECTURA EN VIVO (LA RED analizando una web real) ── */
  #lecOv{position:fixed;inset:0;z-index:78;display:none;align-items:center;justify-content:center;
    padding:14px;background:rgba(1,5,2,.94);font-family:'VT323',var(--mono,monospace)}
  #lecOv.on{display:flex}
  #lecOv .lec-in{width:min(94vw,470px);background:#010502;border:1px solid #0c3a1d;border-radius:12px;
    padding:16px 18px;color:#3aff6e;text-shadow:0 0 6px rgba(58,255,110,.5);position:relative;overflow:hidden}
  #lecOv .lec-in::before{content:'';position:absolute;inset:0;pointer-events:none;
    background:repeating-linear-gradient(0deg, rgba(0,0,0,.36) 0 2px, transparent 2px 4px)}
  #lecOv .lec-hd{font-size:14px;letter-spacing:.26em;color:#1e8f45}
  #lecOv .lec-dom{font-size:22px;color:#b8ffce;margin:2px 0 8px;word-break:break-all}
  #lecOv .lec-cv{width:100%;height:70px;display:block;background:#020a04;border:1px solid #0c3a1d;border-radius:4px}
  #lecOv .lec-fases{margin:10px 0 8px;font-size:16px;line-height:1.5}
  #lecOv .lec-f{opacity:.35;letter-spacing:.04em}
  #lecOv .lec-f.on{opacity:1}
  #lecOv .lec-f .ok{color:#3aff6e}
  #lecOv .lec-f .run{color:#b8ffce;animation:trmcur .7s steps(1) infinite}
  #lecOv .lec-f .wait{color:#1e8f45}
  #lecOv .lec-bar{height:6px;background:#0c3a1d;border-radius:3px;overflow:hidden}
  #lecOv .lec-bar i{display:block;height:100%;width:0;background:#3aff6e;
    box-shadow:0 0 10px rgba(58,255,110,.8);transition:width .5s ease}
  #lecOv .lec-out{min-height:26px;margin-top:10px;font-size:17px;color:#1e8f45;text-align:center}
  #lecOv .lec-nat{font-size:30px;letter-spacing:.16em}
  #lecOv .lec-st{font-size:16px;color:#b8ffce}
  #lecOv .lec-st b{color:#fff}
  #lecOv .lec-ok{font-size:13px;letter-spacing:.16em;color:#1e8f45;margin-top:4px}
  #lecOv .lec-fail{font-size:24px;letter-spacing:.14em;color:#ff5c5c;text-shadow:0 0 10px rgba(255,92,92,.5)}
  #lecOv .lec-x{margin:12px auto 0;display:block;background:transparent;border:1px solid #3aff6e;
    color:#3aff6e;font-family:inherit;font-size:17px;letter-spacing:.16em;padding:8px 20px;
    cursor:pointer;border-radius:5px;position:relative}
  body.reduce-fx #lecOv .lec-in::before{display:none}

  /* ── guía sobre pantalla: misma voz que el terminal (LA RED en verde) ── */
  #guiaOv .guia-card{background:#010502;border-color:#0c3a1d;font-family:'VT323',var(--mono,monospace)}
  #guiaOv .guia-card .wizeye{color:#1e8f45;letter-spacing:.26em;font-size:13px}
  #guiaOv .guia-card .guia-txt{color:#3aff6e;font-size:20px;line-height:1.5;
    text-shadow:0 0 6px rgba(58,255,110,.5)}
  #guiaOv .guia-card .guia-txt b{color:#b8ffce;font-weight:400}
  #guiaOv .guia-card .guia-cta{background:transparent;border:1px solid #3aff6e;color:#3aff6e;
    font-family:inherit;font-size:17px;letter-spacing:.14em;text-shadow:0 0 7px rgba(58,255,110,.5)}
  #guiaOv .guia-card .guia-x{color:#1e8f45;border-color:#0c3a1d;font-family:inherit}

  /* ── HOME · fase de acompañamiento: el CANAL es el CTA, JUGAR espera turno ── */
  #histBadge{display:flex;flex-direction:column;gap:1px}
  #histBadge i{font-style:normal;font-size:15px;color:#1e8f45;letter-spacing:.02em}
  #histBadge.cta{padding:16px 18px;border-color:#3aff6e;border-radius:12px;
    box-shadow:0 0 22px rgba(58,255,110,.18), inset 0 0 18px rgba(58,255,110,.06);
    background:linear-gradient(180deg, #04170c, #010502)}
  #histBadge.cta b{font-size:23px;letter-spacing:.04em;line-height:1.15}
  #histBadge.cta i{font-size:16px}
  body.hist-first #playBtn{font-size:15px;padding:11px 14px;letter-spacing:.12em;
    background:var(--panel,#131a28);border-color:var(--line,#233043);color:var(--muted,#8b96a8);
    box-shadow:none;animation:none;display:flex;flex-direction:column;gap:2px}
  body.hist-first #playBtn .pc-s{font-size:11px;letter-spacing:.04em;color:var(--dim,#5f6f86);
    font-weight:400;text-transform:none}

  /* panel de reinicio del taller (dev) */
  #resetPanel .danger{border-color:var(--red);color:var(--red)}
  #resetPanel .nameIn{margin:6px 0}
  #resetPanel #rsWho{flex-wrap:wrap}

  /* ══════════════════════════════════════════════════════════════════════════
     JERARQUÍA POR FASE (UX1) · cada momento del turno tiene UN foco
     ─────────────────────────────────────────────────────────────────────────
     pick      · decides   → mandan tus Formas y la decisión actual
     wait      · esperas   → nada es interactivo; el rival tiene la palabra
     resolving · choca     → manda la arena; la UI deja de parecer pulsable
     result    · entiendes → manda el choque: qué pasó, por qué, cuánto
     Regla: se atenúa y se sustituye, NO se mueve el layout (14 turnos × 3
     transiciones = la interfaz no puede bailar). Solo en móvil se colapsa
     lo que hace falta para ganar espacio real.
     ══════════════════════════════════════════════════════════════════════════ */
  #battle .cardbay, #battle #stepPanel, #battle .subrow, #battle .log,
  #battle .clash, #battle .hud, #battle .stage{
    transition:opacity .18s ease, filter .18s ease, transform .18s ease}

  /* ── pick: la decisión manda; el resto baja un paso (no desaparece) ── */
  .ph-pick .log{opacity:.62}
  .ph-pick .subrow{opacity:.55}
  .ph-pick .subrow:hover,.ph-pick .subrow:focus-within{opacity:1}

  /* ── wait: nada es tuyo ahora mismo ── */
  .ph-wait .cardbay{opacity:.34;pointer-events:none;filter:saturate(.55)}
  .ph-wait #stepPanel{opacity:0;pointer-events:none}
  .ph-wait #go{opacity:.5}
  .ph-wait .subrow{opacity:.8}

  /* ── resolving: la arena se come la atención ── */
  .ph-resolving .cardbay{opacity:.14;pointer-events:none;filter:saturate(.35) blur(.6px)}
  .ph-resolving #stepPanel{opacity:0;pointer-events:none;visibility:hidden}
  .ph-resolving .log{opacity:.35}
  .ph-resolving .subrow{opacity:.3;pointer-events:none}
  .ph-resolving .stage{box-shadow:0 0 0 1px var(--line2), 0 0 32px rgba(0,0,0,.55)}

  /* ── result: manda el choque; las cartas quedan de contexto ── */
  .ph-result .cardbay{opacity:.28;pointer-events:none;filter:saturate(.5)}
  .ph-result #stepPanel{opacity:0;pointer-events:none;visibility:hidden}
  .ph-result .log{opacity:.5}
  .ph-result .clash{filter:none}
  /* el veredicto es el protagonista: un poco más de aire y jerarquía */
  .ph-result #verdict b{letter-spacing:.06em}

  /* ══════════ MÓVIL: DISEÑO PROPIO (UX2), no desktop comprimido ══════════ */
  @media (max-width:560px){
    /* 1 · la cabecera de la app no aporta nada dentro del combate: ~60px libres.
       Doble vía a propósito: la clase del body (que en un móvil real llegó a
       faltar) y el propio #battle visible, que es la verdad del DOM. */
    body.scr-battle > .wrap > header{display:none}
    .wrap:has(> #battle[style*="flex"]) > header{display:none}
    body.scr-battle{padding-top:6px}

    /* 2 · legibilidad mínima: nada por debajo de 11px (antes 7.5-8px) */
    .card .cname{font-size:12px}
    .card .role{font-size:9.5px;letter-spacing:.12em}
    .card .note b{font-size:9.5px;padding:2px 5px}
    .card .num{font-size:19px}
    .modeQ{font-size:12px}
    .modes button{font-size:12px;padding:13px 4px;min-height:52px}
    .modes button small{font-size:9.5px}
    .auxbtns button{font-size:11px;padding:9px 11px;min-height:40px}
    .log p{font-size:11.5px}
    /* móvil: la causa se lee, el desglose respira, y nada permanente nuevo */
    .causa{font-size:11.5px}
    .pasos{font-size:11.5px;gap:2px 10px}
    /* la naturaleza de la banda ya NO se encoge en móvil: esta regla la dejaba en
       9px justo donde el problema era la legibilidad (reporte 28-ago). El ancho lo
       da ahora la fila propia, no recortar la letra. */
    .slots.l .natx{font-size:9px}

    /* 3 · UNA cámara móvil, la misma en las tres fases (ver «CÁMARA ESTABLE»).
           #cv se estira en vertical (la arena es 960×430 y el móvil es
           estrecho) y la ventana recorta el cielo: los Tejidos entran enteros
           y ~11% más grandes que antes, y además más cerca (CAM_OX en
           render.js). El tope inferior evita que en pantallas cortas la
           decisión se salga por debajo. */
    /* --camK recorta cielo, y el recorte se mide en FILAS del lienzo (430), no
       en píxeles de pantalla: 1.102 se comía 39,8 filas. Con CELL=10 la figura
       empieza en la fila 55 (oy = 415 − 36·CELL) y su marco 14 filas más arriba,
       con un vaivén de ±2,2 — o sea que a 1.102 el marco quedaba justo fuera y
       las antenas tocaban el borde. A 1.05 el recorte baja a 20 filas: quedan
       10px de aire sobre el marco, la figura solo pierde un 5% de alto y el
       estiramiento mejora de 1,27× a 1,21×.
       OJO: subir --camH NO arregla esto — el recorte es proporcional y se lleva
       las mismas filas. La palanca es esta. */
    #battle{--camH:clamp(160px, 51.7vw, 226px); --camK:1.05}
    /* ══ EL ZOOM EXCEPCIONAL, SOLO CON LA LENTE AMPLIADA (6-sep-2026) ════════
       `.zoomp` (rotura) y `.cinez` (FURIA, núcleo, cinemáticas) escalan #cv desde
       el suelo. Con el mundo entero sobra sitio y siguen en 1,05/1,07 para todo el
       mundo. Con la cámara ampliada de 744×402 la cuenta cambia: esa lente solo
       tolera ×1,027 antes de que el glifo del ancla más alto salga de cuadro, y un
       zoom que recorta una capa semántica recorta información aunque dure 280ms.

       Desde el 7-sep la lente ampliada es la de TODOS, así que el empujón baja a
       1,02 en móvil sin condición. Con la lente clásica del interruptor de
       desarrollo sobra sitio y 1,02 solo se ve más sutil, que es preferible a
       tener dos efectos distintos según una bandera de comparación.
       `tactil.js::ENCUADRE.zoomExc` lleva el mismo número para que la puerta pueda
       comprobar que no se separan. */
    .stage.zoomp #cv{transform:scale(1.02)}
    .stage.cinez #cv{transform:scale(1.02)}
    /* el `width` se devuelve a AUTO a propósito: el escritorio ahora deriva el
       ancho del alto con un min(), y el móvil no debe heredarlo. Y `auto` en vez
       de `100%` porque la arena móvil va A SANGRE con márgenes negativos de −12px
       (regla `.stage{margin-left:-12px…}` de más arriba): con `100%` los márgenes
       dejan de ensanchar y la arena perdía 24px de ancho — medido, 428 → 404.
       El estiramiento vertical de aquí (1,21×) es deliberado: ver arriba. */
    /* ══ LA ARENA NO ES EL AMORTIGUADOR (2-sep-2026) ══════════════════════════
       Medido: `height` es una PREFERENCIA, y en un flex todo hijo nace con
       `flex-shrink:1`. El resto de bloques del combate tienen alturas mínimas
       intrínsecas (texto, cartas con min-height), así que la arena era lo único que
       podía ceder — y cedía hasta 2px cuando el panel del tutorial llegaba a 279.
       `flex:0 0 var(--camH)` la fija: si algo no cabe, cede lo de abajo o la página
       hace scroll, que es lo que decidió Andreu. */
    .stage{aspect-ratio:auto;flex:0 0 var(--camH);height:var(--camH);max-height:none;width:auto}

    /* 4 · al elegir, las cartas y la decisión son lo primero: el log se recoge */
    .ph-pick .log,.ph-wait .log{display:none}
    .ph-pick #coach,.ph-wait #coach{margin-top:4px}
    /* y en resolución/resultado el hueco de las cartas se cede al choque */
    .ph-resolving .cardbay,.ph-result .cardbay{max-height:0;margin:0;opacity:0;overflow:hidden}
    .ph-resolving #stepPanel,.ph-result #stepPanel{display:none}

    /* 5 · objetivos: chips con diana real, no una lista que pasa desapercibida */
    #stepPanel{padding:9px;gap:7px}
    .targets{display:flex;flex-wrap:wrap;gap:6px}
    .targets button{min-height:44px;font-size:11.5px;flex:1 1 46%}

    /* 6 · la acción principal, siempre a mano y sin competencia */
    #go{padding:16px 10px;font-size:14.5px;letter-spacing:.16em;min-height:56px}
    .subrow{gap:6px}
    /* secundarios: se pliegan tras «⋯» (RENDIRSE y SALIR dejan de competir) */
    .subrow.plegada .auxbtns > button:not(#chuBtn):not(#masBtn){display:none}
    #masBtn{font-size:11px;padding:9px 12px;color:var(--dim)}
  }
  /* en pantallas grandes el plegado no aplica: hay sitio para todo */
  @media (min-width:561px){ #masBtn{display:none} }

  /* ── RESULT: el veredicto es el foco, así que se LEE (contraste, no gris) ── */
  .ph-result #verdict b{color:var(--ink)}
  .ph-result #verdict span{color:var(--muted);font-size:12px;line-height:1.55}
  .ph-result #vMatch{color:var(--dim);font-size:10.5px}
  .ph-result #vChips b{opacity:1}
  @media (max-width:560px){
    /* móvil: el veredicto y su explicación por encima del mínimo legible */
    .ph-result .verdict b{font-size:15px;line-height:1.25}
    .ph-result .verdict span{font-size:11.5px;color:var(--muted)}
    .ph-result #vMatch{font-size:10.5px}
    .ph-result #vDelta{margin-top:5px}
    /* nombre de la Forma: el recorte va en el TEXTO (.nm), no en el flex que
       lo contiene — así parte por palabras y usa dos líneas de verdad */
    .card .cname{letter-spacing:0;line-height:1.2;align-items:flex-start;padding-right:30px}
    .card .cname .nm{overflow-wrap:break-word;word-break:normal;hyphens:none;
      display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
    .ccard .n{letter-spacing:0;word-break:normal}
  }


  /* ══════════════ AJUSTES UX2.1 (feedback de partida real) ══════════════ */

  /* 1 · barras de colonización ALINEADAS: el rival lleva una línea más
        ("sin ESTRUCTURA"), así que el nombre reserva sitio para dos en ambos */
  .fname{display:flex;flex-direction:column;justify-content:flex-end}
  .fighter.enemy .fname{align-items:flex-end}

  /* 2 · los cables carta↔Tejido se esconden cuando las cartas no mandan
        (antes quedaban colgando de la nada al resolver y al leer el resultado) */
  #battle.ph-resolving #linkfx, #battle.ph-result #linkfx{display:none!important}

  /* 5 · segunda decisión (¿a dónde?): un bloque con título propio, la opción
        principal a ancho completo y las alternativas en dos columnas */
  .targets.on{display:grid;grid-template-columns:1fr 1fr;gap:7px;padding-top:22px;position:relative}
  .targets.on::before{content:'◈ ¿a dónde?';position:absolute;top:2px;left:2px;
    font-family:var(--mono);font-size:9.5px;letter-spacing:.2em;color:var(--dim);text-transform:uppercase}
  .targets button{width:100%}
  .targets button[data-t="rival"]{grid-column:1 / -1}
  .targets button[data-t="self"]{grid-column:1 / -1}
  /* si la última alternativa queda huérfana (número impar de opciones para
     romper), ocupa la fila entera en vez de dejar medio hueco muerto */
  .targets button:last-child:nth-child(even){grid-column:1 / -1}
  /* la Forma que no tiene nada que elegir dice a dónde va, y se ve que NO se
     pulsa: misma caja, sin relieve, texto atenuado y sin cursor de botón */
  .targets .tgtfix{grid-column:1 / -1;text-align:center;padding:11px 9px;
    border:1px dashed var(--line);border-radius:6px;color:var(--muted);
    font-size:11.5px;line-height:1.3;background:rgba(255,255,255,.015)}

  @media (max-width:560px){
    /* 1b · en móvil el nombre del rival también reserva sus dos líneas */

    /* 4 · las Formas más grandes: se leen y se tocan mejor, y hay sitio de sobra */
    .card{min-height:156px;padding:10px 10px 13px;display:flex;flex-direction:column;gap:5px}
    /* el VALOR se alinea con el rol (arriba) y así el nombre dispone de todo
       el ancho: antes competían por la misma línea y el nombre se partía */
    .card .role{order:1;font-size:10.5px;padding-right:32px}
    .card .cname{order:2;font-size:15px;padding-right:2px;gap:5px}
    .card .cifra{order:1}   /* bajo el rol: aquí cada hijo lleva su order */
    .card .cdom{order:3;font-size:9.5px}
    .card .num{font-size:26px;top:8px;right:9px;line-height:1}
    /* la explicación (ⓘ / sello) se cuela bajo el dominio, no ANTES del rol:
       sin `order` caía en 0 y empujaba la cabecera de la carta hacia abajo */
    .card .props{order:4}
    .card .note{order:8;margin-top:auto;display:flex;flex-wrap:wrap;gap:4px;align-items:flex-end}
    .card .note b{font-size:10px;padding:3px 6px}
    /* acciones al fondo, separadas de la información */
    .card .repl-btn,.card .conc-btn,.card .asc-btn{order:9;align-self:stretch;
      text-align:center;padding:8px 6px;font-size:10.5px;min-height:36px}
    .card .propbtn{top:auto;bottom:8px;right:8px}

    /* 5b · objetivos con diana grande y texto que respira */
    .targets.on{gap:8px;padding-top:24px}
    .targets button{min-height:48px;font-size:12px;padding:11px 9px;line-height:1.25}
    #stepPanel{padding:11px 10px}
  }

  /* RECONSTRUIR ocupa todo el ancho: al elegirlo no puede ESCALAR (se salía de
     la pantalla por los dos lados). Sube un poco y basta. */
  .card.rebbtn[aria-pressed="true"]{transform:translateY(-4px) scale(1)}
  .cards .card.rebbtn{max-width:100%}

  /* ══════════════════════════════════════════════════════════════════════════
     UX3 · MENOS RUIDO, MISMA CÁMARA (2ª pasada con partidas reales encima)
     ─────────────────────────────────────────────────────────────────────────
     Principio: la profundidad del combate no desaparece, se PLIEGA. En cada
     momento se ve solo lo que hace falta para ese momento; el resto está a un
     toque (elegir la Forma, «detalles», «⋯ MÁS»). El encuadre de la arena no
     se toca nunca (ver «CÁMARA ESTABLE»).
     ══════════════════════════════════════════════════════════════════════════ */

  /* ── HUD · la COLONIZACIÓN es la condición de victoria: manda ella ──────── */
  .crow{display:flex;align-items:baseline;gap:11px}
  .fighter.enemy .crow{flex-direction:row-reverse}
  .colo{display:flex;align-items:baseline;gap:2px;line-height:1;
    font-variant-numeric:tabular-nums}
  .fighter.enemy .colo{justify-content:flex-end}
  .colo b{font-size:25px;font-weight:800;color:var(--ink)}
  .colo i{font-size:12.5px;font-style:normal;color:var(--dim);letter-spacing:.04em}
  .colo.hot b{color:var(--you)}                 /* el rival cayendo: buena noticia */
  .colo.warn b{color:var(--red)}                /* tu red al borde: mala */
  .colo.warn{animation:coloWarn 1.05s ease-in-out infinite}
  @keyframes coloWarn{0%,100%{text-shadow:none}
    50%{text-shadow:0 0 13px rgba(255,80,80,.75)}}
  @media (prefers-reduced-motion:reduce){ .colo.warn{animation:none} }
  /* y todo lo demás del marcador baja un escalón: nombre, autoría del avance,
     y el turno (que además vive dentro de la arena, en #stageCap) */
  .fname{font-size:11.5px}
  .barTag{font-size:9.5px;opacity:.92}
  .turno{font-size:9px;opacity:.7}
  .turno b{font-size:13px}

  /* ── FORMAS · dos niveles de estado (los reparte renderCards: n1/n2) ────── */
  /* el chip dice la ACCIÓN, y su color es el del estado AL QUE lleva:
     ámbar si va a ocultar, verde si va a abrir */
  .card .note .mode-b{letter-spacing:.08em;cursor:pointer}
  .card .note .mode-b.acc-abrir{color:var(--you);border-color:var(--you-dim);
    background:rgba(63,224,160,.09)}
  .card .note .mode-b.acc-ocultar{color:var(--amber);border-color:#5c4d22;
    background:rgba(255,198,92,.09)}
  .card .note .mode-b .fl{font-style:normal;opacity:.75;margin-left:2px}
  /* la vieja pista flotante «↻ VOLTEAR» se solapaba con el chip de modo (y
     decía lo mismo dos veces): ahora la ↻ va dentro del chip */
  .cards .card:not(.rebbtn)[aria-pressed="true"]::before{content:none}

  /* ── DECISIÓN EN DOS PASOS · si falta el objetivo, el foco va ahí ───────── */
  #battle.paso-obj #stepPanel{border-color:var(--amber);
    box-shadow:0 0 0 1px rgba(255,198,92,.22), 0 0 20px rgba(255,198,92,.10)}
  #battle.paso-obj .targets.on::before{color:var(--amber)}

  /* ── RESOLVIENDO · el jugador ya no decide: que no parezca que puede ────── */
  .ph-resolving .hud{opacity:.5}
  .ph-resolving #coach{opacity:0}
  .ph-resolving .subrow{opacity:0;pointer-events:none}
  .ph-resolving #go{opacity:.35}

  /* ── RESULTADO · el titular recupera su color (verde=bien, rojo=mal, ámbar=
        a medias): es la lectura instantánea de «qué ha pasado» ────────────── */
  .ph-result #verdict.good>b{color:var(--you)}
  .ph-result #verdict.bad>b{color:var(--foe)}
  .ph-result #verdict.mix>b{color:var(--amber)}

  /* ── RESULTADO · orden de lectura: titular → cuánto → por qué → detalles ── */
  .ph-result #vHead{animation:vSeq .18s ease both}
  .ph-result #vDelta{animation:vSeq .18s ease .12s both}
  .ph-result #vSub{animation:vSeq .18s ease .18s both}
  .ph-result #vChips{animation:vSeq .18s ease .26s both}
  @keyframes vSeq{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}
  @media (prefers-reduced-motion:reduce){
    .ph-result #vHead,.ph-result #vDelta,.ph-result #vSub,
    .ph-result #vChips{animation:none} }
  /* el botón NO se anima: un CTA con animación de entrada y fill puede quedarse
     invisible si el navegador no ejecuta la animación, y ese botón es la salida
     del turno. Aparece cuando la fase cambia y basta. */

  /* al elegir no hay choque que mostrar: el bloque vacío no debe cobrar su
     hueco (10px de gap fantasma entre la arena y las cartas) */
  .ph-pick .clash,.ph-wait .clash{display:none}

  @media (max-width:560px){
    /* móvil: primero PLEGAR, y solo después apretar tamaños. Aquí se recupera
       el alto que necesita el segundo paso de la decisión (objetivos) sin
       tocar la cámara: marcador más compacto, cartas más justas y dianas algo
       menos altas — todo por encima del mínimo táctil (44px). */
    #battle{gap:8px}
    .fighter{gap:4px}
    .colo b{font-size:24px}
    .card{min-height:138px}
    .targets.on{gap:6px;padding-top:19px}
    .targets button{min-height:44px}
    .modeQ{font-size:10.5px;line-height:1.35;opacity:.85}
    #go{min-height:52px;padding:14px 10px}
    .auxbtns button{min-height:36px;padding:7px 11px}

    /* la Forma sin elegir responde «¿quiero jugar esto?»: rol, dominio, valor
       y su estado principal. El detalle (integridad, rango, crecimiento) se
       abre al elegirla — «¿cómo quiero jugarlo?» */
    .card:not([aria-pressed="true"]) .note .n2{display:none}
    /* el ⓘ no cabe junto al chip de modo en 110px de carta, y en móvil su sitio
       lo ocupa un control de verdad: las propiedades siguen a un long-press
       (peek) sobre la carta, que es el gesto nativo del móvil */
    .card .propbtn{display:none!important}
    /* las acciones libres de la carta (replegar/ascender) siguen ahí, pero sin gritar */
    .card .repl-btn,.card .asc-btn{opacity:.75;font-size:10px}

    /* el resultado se lee de un vistazo: usa el hueco que dejan las cartas */
    .ph-result .verdict b{font-size:19px;line-height:1.2;letter-spacing:.04em}
    .ph-result .verdict span{font-size:12px;line-height:1.5}
    .ph-result #vMatch{font-size:9.5px;opacity:.8}
    .ph-result #vDelta{margin:9px 0 4px;gap:7px}
    .ph-result #vDelta b{font-size:17px;padding:5px 12px}
    .ph-result .fxsum{font-size:11px}
    .ph-result .ccard{padding:6px 9px}
    .ph-result .ccard .n{font-size:10.5px}
    .ph-result .ccard .v{font-size:15px}
    /* al resolver, los secundarios desaparecen del todo (no compiten con el choque) */
    .ph-resolving .subrow{visibility:hidden}
  }

  /* ══════════════════════════════════════════════════════════════════════════
     UX3.1 · PASADA QUIRÚRGICA (legibilidad, ritmo, ruido) — sin rediseño
     ══════════════════════════════════════════════════════════════════════════ */

  /* ── 1 · PULSO: una decisión dentro del combate, no otra pantalla ───────── */
  /* el fondo deja ver el duelo (antes lo tapaba al 86%) y la caja no se estira */
  #pulOv{background:rgba(5,7,11,.62);backdrop-filter:blur(1.5px)}
  .pulBox{max-width:420px}
  .pulBox h3{display:flex;align-items:baseline;gap:8px}
  /* versión aprendida: título, una frase, dos botones. Nada más. */
  .pulBox.min{padding:14px 16px;gap:9px}
  .pulBox.min p{font-size:12.5px;line-height:1.45;color:var(--ink)}
  .pulBox.min .btns button{padding:13px 12px}
  .pulBox .btns button{display:flex;flex-direction:column;align-items:center;gap:2px;line-height:1.2}
  .pulBox .btns button small{font-size:9px;letter-spacing:.08em;color:var(--dim);font-weight:400}
  @media (max-width:560px){
    /* hoja inferior: aparece donde está el pulgar y no reencuadra nada */
    #pulOv{align-items:flex-end;padding:0}
    .pulBox{max-width:none;border-radius:14px 14px 0 0;border-bottom:0;
      animation:pulUp .16s ease-out}
    @keyframes pulUp{from{transform:translateY(14px);opacity:.6}to{transform:none;opacity:1}}
    .pulBox.min{padding:14px 14px 18px}
    .pulBox h3{font-size:14px}
  }
  @media (prefers-reduced-motion:reduce){ .pulBox{animation:none} }

  /* ── 2 · OBJETIVOS: la etiqueta es una etiqueta, no una franja ──────────── */
  /* antes: 19-24px de padding reservados para dos palabras. Ahora la etiqueta
     es la primera fila de la propia rejilla y ocupa lo que mide su texto. */
  .targets.on{padding-top:0}
  .targets.on::before{content:'objetivo';position:static;grid-column:1 / -1;
    font-size:9px;letter-spacing:.22em;line-height:1;margin-bottom:-1px}

  /* ── 3 · FORMA SIN ELEGIR: UN estado, el que decide si la juego ─────────── */
  /* solo colapsa la familia .n1 —los estados que BLOQUEAN (rota · ya jugada ·
     sin ⚡)—, de la que basta el primero. Los .n1c (precio de la mutación,
     combo disponible, REPLICAR ×2) se quedan: son raros o fijos, y esconderlos
     era la razón de que nadie entendiera lo que la carta ofrecía. */
  @media (max-width:560px){
    .card:not([aria-pressed="true"]) .note .n1 ~ .n1{display:none}
  }

  /* ── 4 · RESOLVIENDO: solo el combate ──────────────────────────────────── */
  .ph-resolving .hud{opacity:.38}
  .ph-resolving .log{opacity:0}
  .ph-resolving .subrow{visibility:hidden}      /* también en escritorio */
  .ph-resolving #go{pointer-events:none}

  /* ── 5 · RESULTADO: el titular pesa, y una Forma ROTA pesa más ──────────── */
  #vDelta b.rot{font-size:17px;padding:5px 12px;color:var(--amber);
    border-color:var(--amber);background:rgba(255,198,92,.14);letter-spacing:.05em}
  #vDelta b.rot.mia{color:var(--foe);border-color:var(--foe);background:rgba(255,90,120,.13)}
  @media (max-width:560px){
    .ph-result .verdict b{font-size:21px;line-height:1.18}
    .ph-result #vDelta b.rot{font-size:19px;padding:6px 13px}
    .ph-result .verdict span{font-size:12.5px}
  }

  /* ── 7 · HUD: el número de colonización es lo primero que se encuentra ─── */
  @media (max-width:560px){
    .crow{gap:9px}
    .colo b{font-size:30px;letter-spacing:-.01em}
    .colo i{font-size:13px}
    .colo{margin-bottom:1px}                   /* pegado a su barra: son lo mismo */
    .bar{height:16px}
    .fighter{gap:3px}
    .fname{font-size:10.5px;color:var(--muted)}
    .meta{font-size:10.5px}
  }
  .turno{opacity:.55}                          /* el turno, el último de la fila */

  /* ══════════════════════════════════════════════════════════════════════════
     UX3.2 · ZONA DE DECISIÓN ELÁSTICA (solo móvil, solo el eje vertical)
     ─────────────────────────────────────────────────────────────────────────
     El problema no era «hay negro», era que la interfaz parecía terminar antes
     de tiempo y luego sobraba media pantalla. Ahora la pantalla de combate
     ocupa el viewport y la zona de decisión (.controls) es la que se estira:
       FORMAS  → arriba del dock, quietas
       OBJETIVO → crece hacia abajo según cuántas opciones haya
       ESPACIO FLEXIBLE → se consume al aparecer más objetivos
       CTA + REGLAS/MÁS → anclados abajo, con safe-area de Android
     Nada por encima de las Formas se mueve: la elasticidad vive debajo.
     ══════════════════════════════════════════════════════════════════════════ */
  @media (max-width:560px){
    /* OJO: nada de esto cuelga de body.scr-battle. Esa clase falló en un móvil
       real (cabecera visible y CTA sin anclar) y el layout no puede depender de
       una clase que se pone por JS: #battle solo existe visible en combate, y
       que .wrap crezca no mueve nada en las demás pantallas (sus hijos no
       tienen margen automático). */
    .wrap{flex:1;padding-bottom:calc(8px + env(safe-area-inset-bottom))}
    #battle{flex:1}
    #battle .controls{flex:1}             /* el dock se queda todo el sobrante */
    /* EL AIRE VA JUSTO ENCIMA DEL BOTÓN (UX3.5). OBJETIVO no es un panel
       independiente: es la segunda mitad de la decisión sobre LA Forma que
       acabas de elegir («¿a dónde apunta ESTA web?»), así que va pegado a ella.
       El hueco cae entonces entre la lista de objetivos y el botón, que sigue
       anclado abajo — los dos extremos quedan fijos y el aire absorbe la
       diferencia entre 1, 2 y 4 objetivos.
       (En UX3.3 el aire estaba arriba, emparejando OBJETIVO con el botón: el
       vínculo carta↔objetivo es semántico y pesa más que el procedimental.)
       Si hay reloj de turno, arrastra consigo al botón: el par baja junto. */
    #battle.ph-pick #reloj, #battle.ph-wait #reloj,
    #battle.ph-pick #go,    #battle.ph-wait #go{margin-top:auto}

    /* TOPE DE LA COMPOSICIÓN (UX3.4) · el combate deja de estirarse sin límite.
       La arena se dimensiona por el ANCHO (51.7vw), así que en un móvil alto
       toda la altura extra caía en el hueco: 84px en una pantalla de 852 pero
       164 en una de 932. Con el tope, el hueco crece hasta ~120 y el resto se
       queda como margen bajo el pie (52px en 932), que se lee como margen de
       página y no como «la interfaz se acabó antes de tiempo».
       Es inerte en pantallas cortas (una de 852 usa 838) y no puede esconder
       nada: si el contenido pasa del tope, la página conserva su scroll. */
    #battle{max-height:860px}

    /* LAS FORMAS SE QUEDAN EL SOBRANTE (UX3.6) · el hueco molestaba estuviera
       arriba o abajo, así que el problema no era su posición sino su tamaño.
       Los píxeles tienen que pertenecer a algo y solo hay tres destinos:
         · la arena → NO: al crecer no agranda los Tejidos, los ESTIRA (el
           canvas es 960×430 sobre 393 de ancho; a 245 de alto ya se ven finos
           y a 285 deformados). Eso es trabajo de cámara, no de esta pantalla.
         · negro al final → es lo que se quería evitar.
         · las Formas → sí: su interior no es vacío, es el chasis con su trama,
           así que se lee como carta y no como agujero.
       Ligado SOLO a la altura de la pantalla (constante por dispositivo): no
       depende de qué Forma elijas ni de cuántos objetivos haya, así que nada
       crece ni decrece durante el turno. Inerte por debajo de ~860 de alto,
       donde no hay sobrante que repartir. */
    .card{min-height:clamp(138px, calc(138px + (100dvh - 800px) * .77), 240px)}
    /* ══ LA PARADOJA DEL MÓVIL ALTO (2-sep-2026) ══════════════════════════════
       La regla de arriba (UX3.6) reparte el SOBRANTE de altura a las Formas para que no
       quede un agujero. Está bien… en un combate sin panel de tutorial. Durante la
       calibración no hay sobrante —el panel se lo lleva— y las cartas lo reclamaban igual:
       a 915 de alto pedían 227px en vez de 138, y con `#battle{max-height:860px}` el
       contenedor daba menos que la ventana. Resultado medido: un móvil de 915 dejaba
       MENOS arena que uno de 640 (2px contra 6px).
       Durante la calibración, las Formas se quedan en su suelo. UX3.6 sigue intacto en el
       combate normal, que es donde el sobrante existe de verdad. */
    #battle.tut .card{min-height:138px}
    /* RESULTADO: el veredicto es el protagonista del hueco disponible, así que
       se centra entre el final de la arena y el botón (dos márgenes automáticos
       = el sobrante se reparte a medias arriba y abajo del bloque). La arena,
       el HUD y el CTA no se mueven. */
    #battle.ph-result .clash{margin-top:auto}
    #battle.ph-result .controls{flex:0 0 auto;margin-top:auto}

    /* muchos destinos (4+: colonizar + las tres webs del rival a la vista):
       rejilla 2×2 en vez de tres filas — la clase la pone renderTargets */
    /* al perder la fila entera, la opción principal se distingue por el borde
       (si no, COLONIZAR quedaría como una celda más entre cuatro) */
    .targets.on.many button[data-t="rival"]{grid-column:auto;border-color:var(--you-dim)}
    .targets.on.many button{font-size:11.5px}
    /* y en 2×2 la última tampoco se estira: la regla del «huérfano» sobra aquí */
    .targets.on.many button:last-child:nth-child(even){grid-column:auto}
    /* red de seguridad del caso extremo (núcleo abierto = dos cartas jugadas,
       hasta 6 destinos): el bloque hace scroll interno antes de empujar el CTA
       fuera de la pantalla */
    #stepPanel{max-height:42vh;overflow-y:auto}
  }

  /* ── 8 · RECONSTRUIR vive en la carta rota, no en una fila permanente ───── */
  /* el chip es la vía de vuelta: se ve siempre en la carta rota (no se plega
     con el resto de estados) y elegir la carta abre el detalle debajo */
  /* NO SE SALE DE LA CARTA. Bisecado con humo-calibracion: a 320px el documento
     desbordaba 21px (8px a 360, 3px a 375) y NINGÚN elemento excedía su caja —el
     desborde lo hacía el NODO DE TEXTO de este chip, que ningún barrido de rects ve.
     Causa: `.card .note b` lleva `white-space:nowrap` porque los sellos de estado son
     chips de una palabra; pero «↻ RECONSTRUIR ⚡4» es una FRASE (112px medidos) dentro
     de una caja de 68px, y con nowrap el texto sale del botón sin ensancharlo.
     `overflow-wrap:anywhere` no bastaba: bajo nowrap no parte nada. El arreglo está
     arriba, en `.card .note b`, porque el fallo era de toda la familia de sellos y no de
     este chip. No es decorativo: pasa en cualquier combate con una Forma reconstruible a
     ese ancho, no solo en la calibración. */
  .card .note .reb-b{max-width:100%;
    color:var(--you);border-color:var(--you-dim);
    background:rgba(63,224,160,.1);letter-spacing:.04em;font-size:9.5px}
  .card .note .reb-b.off{color:var(--dim);border-color:var(--line);background:transparent}
  /* una carta rota que SÍ puede volver no está del todo apagada (el botón sin
     energía sigue deshabilitado, y ese sí se apaga) */
  .card.rota:not([disabled]){filter:saturate(.5) brightness(.9)}
  .card.rota[aria-pressed="true"]{filter:none;border-style:solid;border-color:var(--you-dim)}
  .card.rota[aria-pressed="true"] .cname{color:var(--ink);text-decoration:none}
  .card.rebbtn{min-height:0;padding:11px 12px;gap:4px}       /* sin hueco muerto */
  .card.rebbtn .cname{font-size:12px;font-weight:400;line-height:1.45;color:var(--muted)}
  @media (max-width:560px){
    .card.rebbtn{min-height:0}
    .card.rebbtn .role{padding-right:0}
    .card.rebbtn .cname{font-size:11.5px}
  }

  /* ══ RÓTULO DEL ROL vs NÚMERO GRANDE en cartas estrechas ══════════════════
     Reporte 27-ago: a ~390px se leía «CUARENTEN[6]», con el número montado
     encima del rol. Medido con viewport real (protocolo DevTools), el hueco
     útil del rótulo es carta − 20 (padding) − padding-right − (punto + gap):

        ancho   carta   hueco   CONTAGIO/MUTACIÓN (61px)   CUARENTENA (76px)
         360     106      41     desborda 20 · solapa 3     desborda 35 · solapa 18
         390     116      51     desborda 10                desborda 25 · solapa 8
         430     129      64     cabe                       desborda 12

     Es decir: los TRES rótulos desbordan a 360px, no solo CUARENTENA. Dos
     medidas, en el orden de preferencia acordado:

     1) reservar el ancho EXACTO del número en vez de 32px a ojo. El .num mide
        26px de fuente (≈15.6px de glifo) y vive a right:9px, así que con 27px
        de padding-right queda holgura y se recuperan 5px de rótulo.
     2) y solo donde sigue sin caber, el rótulo cede tamaño y espaciado. Nada
        de recortes ni de «CUARENT…»: el rótulo siempre se lee entero.

     Los cortes salen de la medida, no de anchos redondos: son el punto donde el
     rótulo más largo deja de caber. El escritorio (>560px) no se toca. */
  @media (max-width:560px){
    .card .role{padding-right:28px;letter-spacing:.04em;gap:4px}
  }
  @media (max-width:424px){
    .card .role{font-size:9px;letter-spacing:.02em}
  }
  @media (max-width:386px){
    .card .role{font-size:7.5px;letter-spacing:0;gap:3px}
  }
  /* Un valor de DOS CIFRAS mide ~1,19× el ancho de una y se metía en el hueco
     del rótulo (CUARENTENA solapaba 2px a 390 y 1px a 430). Se compacta solo
     ese caso: una cifra sigue a 26px. El escritorio no entra aquí. */
  @media (max-width:560px){
    .card .num.dos-cifras{font-size:22px}
  }

  /* ═══ P0 · EL TEJIDO COMO TABLERO (dev-only) ═══════════════════════════════
     Prototipo del comité del 6-sep-2026. Con `body.p0on` las tres cartas grandes
     se esconden —siguen en el DOM porque siguen siendo la lógica— y en su sitio
     quedan tres controles compactos y una banda contextual.

     Lo que se busca NO es campo más grande: las mediciones dicen que la arena está
     limitada por el ANCHO, no por el alto. Lo que se busca es acercar la decisión
     al cuerpo y dejar permanente solo lo comparable. */
  body.p0on #cards{ display:none }
  .p0ctl{ display:none }
  body.p0on .p0ctl{ display:grid; grid-template-columns:repeat(3,minmax(0,1fr));
    gap:8px; margin:0 0 6px }
  .p0b{ display:flex; align-items:center; justify-content:center; gap:7px;
    min-height:44px;                     /* la diana del DOM sí es un botón de 44 */
    padding:6px 8px; border-radius:9px; background:var(--panel,#10151f);
    border:1px solid var(--line,#243044); color:var(--ink,#dfe6f2) }
  .p0b .p0g{ font:700 15px/1 ui-monospace,monospace }
  .p0b .p0n{ font:600 13px/1 ui-monospace,monospace; opacity:.9; text-decoration:none }
  .p0b .p0e{ font-style:normal; opacity:.8 }
  /* el rol NO depende solo del color: el glifo va delante y el borde lo repite */
  .p0-cont{ border-left:3px solid var(--rcont) }
  .p0-cuar{ border-left:3px double var(--rcuar); border-left-width:4px }
  .p0-mut { border-left:3px dashed var(--rmut) }
  .p0b.on{ outline:2px solid var(--good,#5fe0a8); outline-offset:1px }
  .p0b:focus-visible{ outline:3px solid var(--acc,#46d6ec); outline-offset:2px }
  .p0b[disabled]{ opacity:.45 }
  .p0b.rota .p0n{ text-decoration:line-through }
  .p0b.oculta{ border-style:dashed }

  .p0banda{ display:none }
  body.p0on .p0banda.on{ display:flex; flex-wrap:wrap; align-items:center; gap:6px 10px;
    margin:0 0 6px; padding:6px 9px; border-radius:8px;
    background:var(--panel2,#0b1017); border:1px solid var(--line,#243044) }
  .p0banda .p0bn{ font:700 12px/1.2 ui-monospace,monospace }
  .p0banda .p0bd{ font:12px/1.2 ui-monospace,monospace; opacity:.82 }
  .p0banda .p0ba{ display:flex; gap:6px; margin-left:auto }
  .p0banda .p0ba button{ min-height:32px; padding:4px 9px; border-radius:7px;
    font:600 11px/1 ui-monospace,monospace }
  .visually-hidden{ position:absolute; width:1px; height:1px; margin:-1px;
    padding:0; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0 }
  @media (max-width:560px){
    .p0b{ gap:5px; padding:5px 6px }
    .p0b .p0g{ font-size:14px } .p0b .p0n{ font-size:12px }
    .p0banda .p0bd{ font-size:11px }
  }

  /* ═══ P0.1 · la intención, comprimida ══════════════════════════════════════
     El bloque OBJETIVO original se esconde y en su sitio va un espejo de chips
     cortos. Se esconde por CSS y NO durante la calibración: ahí el guion apunta a
     `#targets` con su resplandor, y taparlo dejaría la lección señalando al vacío
     (`p0-tablero.js::pintaObjetivo` lo respeta, y esta regla también: la calibración
     pone la clase `tut` en `#battle`, no en el body). */
  body.p0on #battle:not(.tut) #targets{ display:none }
  .p0obj{ display:none }
  body.p0on .p0obj.on{ display:flex; flex-wrap:wrap; gap:6px; margin:0 0 6px }
  .p0obj button{ min-height:40px; padding:6px 12px; border-radius:8px;
    font:600 12px/1 ui-monospace,monospace }
  .p0obj button[aria-pressed="true"]{ outline:2px solid var(--good,#5fe0a8);
    outline-offset:1px }
  .p0obj button:focus-visible{ outline:3px solid var(--acc,#46d6ec); outline-offset:2px }
  /* la línea de intención: es la respuesta a «qué juego si pulso FIJAR» */
  .p0banda .p0bi{ font:700 13px/1.25 ui-monospace,monospace; letter-spacing:.02em }
  .p0banda .p0bi b{ font-weight:800 }
  .p0banda .p0sep{ font-style:normal; opacity:.55; margin:0 6px }

  /* ═══ P0.2 · el CTA junto a la decisión, y el rival sin dibujarse dos veces ══
     `#battle.ph-pick #go{margin-top:auto}` ancla el botón abajo (UX3.5) para que el
     aire absorba una lista de objetivos de altura variable. Con los chips de P0.1 esa
     lista ya no varía, y en móvil el ancla dejaba la intención pegada al Tejido y el
     FIJAR casi al fondo. Bajo p0on se suelta. */
  body.p0on #battle.ph-pick #go, body.p0on #battle.ph-wait #go{ margin-top:0 }
  /* la caja vacía que quedaba entre la banda y el botón: solo se esconde cuando
     `p0-tablero.js::ajustaPanel` confirma que no lleva nada dentro */
  #stepPanel.p0vacio{ display:none }

  /* la ranura rival que ES destino válido. La banda ya marcaba `exp` (ámbar) y
     `broken`; esto añade el «se puede elegir», en el verde de la selección para que
     se lea como lo mismo que el anillo de los controles. NO añade ningún dato: el
     conjunto de destinos válidos ya lo publica `#targets`. */
  body.p0on .slot.p0tgt{ cursor:pointer; border-color:var(--good,#5fe0a8);
    box-shadow:0 0 0 1px rgba(95,224,168,.35) inset }
  body.p0on .slot.p0tgt-on{ outline:2px solid var(--good,#5fe0a8); outline-offset:1px }
  body.p0on .slot.p0tgt::after{ content:'◈'; margin-left:4px;
    color:var(--good,#5fe0a8); font-size:9px; line-height:1 }
  body.p0on .slot.p0tgt-on::after{ content:'◆' }

  /* ══ P1 · EL COMBATE Y SUS ACCIONES, UN SOLO BLOQUE ═══════════════════════════
     Andreu, 7-sep-2026: «las acciones tienen que quedar DENTRO del área de combate».

     Acordado con Codex que «dentro» no significa rasterizado sobre la anatomía —
     cuerpos de 130×125 px no aguantan seis controles— sino DENTRO DEL MARCO. Los
     controles siguen siendo botones DOM de verdad, con su foco, su teclado y su
     lector; lo que cambia es que la banda del rival, la arena y la zona de decisión
     dejan de ser tres cajas sueltas y se leen como una sola superficie de combate.

     Se hace SIN TOCAR EL DOM a propósito: `.clash`, `.log` y `#coach` viven entre
     la arena y los controles, y moverlos para poder envolver el grupo cambiaría
     dónde aparece el desglose del choque en la fase de resultado. En la fase de
     ELECCIÓN esos tres están vacíos, así que el marco sale continuo sin reordenar
     nada — y en resultado vuelve a abrirse solo, que es cuando el desglose manda.

     Y el `gap:10px` de `#battle` se anula solo entre estas tres piezas: como el
     hueco es del contenedor, se compensa con margen negativo en las dos costuras.  */
  body.p0on #battle.ph-pick .arenaHead,
  body.p0on #battle.ph-wait .arenaHead{
    background:var(--panel2, #0e1310); border:1px solid var(--line);
    border-bottom:0; border-radius:8px 8px 0 0; padding:6px 8px 4px; margin-bottom:-10px }
  body.p0on #battle.ph-pick .stage,
  body.p0on #battle.ph-wait .stage{ border-radius:0; border-top:0; border-bottom:0;
    margin-bottom:-10px }
  body.p0on #battle.ph-pick .controls,
  body.p0on #battle.ph-wait .controls{
    background:var(--panel2, #0e1310); border:1px solid var(--line); border-top:0;
    border-radius:0 0 8px 8px; padding:8px }
  /* la arena va a sangre en móvil (márgenes de −12px): el marco tiene que ir con
     ella o el bloque saldría escalonado */
  @media (max-width:560px){
    body.p0on #battle.ph-pick .arenaHead,
    body.p0on #battle.ph-wait .arenaHead,
    body.p0on #battle.ph-pick .controls,
    body.p0on #battle.ph-wait .controls{
      margin-left:-12px; margin-right:-12px; border-left:0; border-right:0;
      border-radius:0 }
  }
  /* en la fase de elección esas tres piezas están vacías: se recogen del todo para
     que la costura no quede rota por un hueco de 10px que no dice nada */
  body.p0on #battle.ph-pick .clash, body.p0on #battle.ph-wait .clash,
  body.p0on #battle.ph-pick .log:empty, body.p0on #battle.ph-wait .log:empty{
    display:none }

  /* ══ P1 · PASO 5 · LA LECTURA, DENTRO DEL MARCO Y SIN REPETIRSE ═══════════════
     Andreu abrió P1 con esto: «cargarnos el máximo posible de la información que
     estamos mostrando fuera del área de combate». Los pasos 2-4 metieron las
     ACCIONES dentro; este mete la LECTURA y quita lo repetido.

     Lo que se conserva porque hace falta para DECIDIR:
       · X/24 de cada lado — es la condición de victoria;
       · ⚡ de cada lado — condiciona mutación y reconstruir;
       · el turno — es el reloj de la partida;
       · los chips de ECO y de núcleo — cambian lo que se puede jugar.

     Lo que se retira porque es el mismo dato dos veces:
       · las dos BARRAS de progreso — son el `X/24` dibujado otra vez, y desde que
         la marea colorea las células colonizadas EN EL CUERPO, tres veces;
       · los nombres — se leen al empezar el duelo y en el registro, no en cada
         turno de una partida de catorce.

     Lo que NO se toca, y es el motivo de que este paso sea solo CSS: `renderHud`
     sigue escribiendo en los mismos nodos. Cero lógica nueva, cero segunda fuente.

     ══ EL RÓTULO QUE SÍ SE QUEDA ══════════════════════════════════════════════
     `colonizados por AVISPERO` parece redundante y NO lo es: dice la DIRECCIÓN del
     número. El `X/24` de la izquierda no es tu puntuación, es cuánto te ha
     colonizado el rival. Sin rótulo, el número más importante de la pantalla se
     puede leer del revés. Se conserva, en pequeño y en una sola línea.       */
  @media (max-width:560px){
    body.p0on #battle.ph-pick .hud,
    body.p0on #battle.ph-wait .hud{
      background:var(--panel2, #0e1310); border:1px solid var(--line);
      border-bottom:0; border-radius:0; margin:0 -12px -10px;
      padding:6px 10px 2px; gap:8px; align-items:center }
    /* la fila se aprieta: número, energía y chips en línea */
    body.p0on #battle.ph-pick .hud .fname,
    body.p0on #battle.ph-wait .hud .fname,
    body.p0on #battle.ph-pick .hud .bar,
    body.p0on #battle.ph-wait .hud .bar{ display:none }
    body.p0on #battle.ph-pick .hud .fighter,
    body.p0on #battle.ph-wait .hud .fighter{ gap:1px }
    body.p0on #battle.ph-pick .colo b,
    body.p0on #battle.ph-wait .colo b{ font-size:19px }
    /* el rótulo de dirección: pequeño, en una línea, y sin desaparecer */
    body.p0on #battle.ph-pick .barTag,
    body.p0on #battle.ph-wait .barTag{
      font-size:8.5px; letter-spacing:.04em; line-height:1.15;
      white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width:100% }
    /* y la arenaHead deja de llevar el borde superior: ahora el marco lo abre el HUD */
    body.p0on #battle.ph-pick .arenaHead,
    body.p0on #battle.ph-wait .arenaHead{ border-top:0; border-radius:0 }
    /* ── EL MARCO CIERRA DEBAJO DEL BOTÓN ──────────────────────────────────────
       `#battle .controls{flex:1}` le da a la zona de decisión todo el sobrante, y
       eso era lo correcto cuando ahí vivían las cartas: crecían con el contenido.
       Ahora el contenido es fijo —tres controles, la banda y el botón—, así que el
       sobrante se convertía en un vacío de 380px DENTRO del marco, y el bloque
       parecía sin terminar. Al soltar el `flex`, el marco acaba justo bajo el botón
       y el aire que sobra queda FUERA, en la página, donde no dice nada raro.
       Los 70px que se recuperan del HUD no se los queda el vacío: se los queda
       la pantalla. */
    body.p0on #battle.ph-pick .controls,
    body.p0on #battle.ph-wait .controls{ flex:0 0 auto }
  }
