  /* ---------- FX (2026-09-29): estilos de la capa de efectos, ver src/ui/fx.js ----------
     Todo lo de este fichero es decorativo. Cada bloque va numerado como en la página de
     propuestas ("Efectos para Alignment Drift") para poder localizarlo o quitarlo entero. */
  #fxLayer{ position:fixed; inset:0; width:100%; height:100%; pointer-events:none; z-index:90; }

  /* 06 · botones con rebote */
  .fx-host{ position:relative; overflow:hidden; }
  .fx-rip{ position:absolute; width:14px; height:14px; margin:-7px 0 0 -7px; border-radius:50%; background:currentColor; opacity:.3; pointer-events:none; animation:fxRip .52s ease-out forwards; }
  .fx-sq{ animation:fxSq .4s cubic-bezier(.2,1.5,.4,1); }
  .row .icon.fx-bo{ animation:fxBo .5s cubic-bezier(.2,1.6,.4,1); }
  .cnt.fx-pop{ display:inline-block; animation:fxPop .4s cubic-bezier(.2,1.8,.4,1); }
  .fx-slot{ display:inline-block; animation:fxSlot .32s cubic-bezier(.2,1.2,.3,1); }
  .row{ position:relative; transition:border-color .45s, box-shadow .45s; }
  .row.fx-hit{ border-color:var(--compute); box-shadow:0 0 0 3px color-mix(in srgb, var(--compute) 22%, transparent); transition:none; }
  .fx-cost{ position:absolute; right:14px; top:0; font-family:"IBM Plex Mono"; font-size:.8rem; font-weight:600; color:var(--risk); pointer-events:none; animation:fxCost .9s ease-out forwards; z-index:2; }
  @keyframes fxRip{ to{ transform:scale(16); opacity:0; } }
  @keyframes fxSq{ 0%{ transform:scale(1); } 25%{ transform:scale(.92,.86); } 60%{ transform:scale(1.05,1.07); } 100%{ transform:scale(1); } }
  @keyframes fxBo{ 0%{ transform:none; } 35%{ transform:translateY(-8px) rotate(-8deg); } 70%{ transform:translateY(2px) rotate(3deg); } 100%{ transform:none; } }
  @keyframes fxPop{ 0%{ transform:scale(1); } 40%{ transform:scale(1.6); } 100%{ transform:scale(1); } }
  @keyframes fxSlot{ from{ transform:translateY(9px); opacity:0; } to{ transform:none; opacity:1; } }
  @keyframes fxCost{ 0%{ opacity:0; transform:translateY(8px); } 20%{ opacity:1; } 100%{ opacity:0; transform:translateY(-26px); } }

  /* 03 · recursos que vuelan: el marcador de destino da un pequeño salto con cada llegada */
  .fx-bump{ animation:fxBump .2s cubic-bezier(.2,1.6,.4,1); }
  @keyframes fxBump{ 0%{ transform:scale(1); } 50%{ transform:scale(1.07); } 100%{ transform:scale(1); } }

  /* 08 · celebración de hito */
  #fxSlam{ position:fixed; inset:0; z-index:95; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:4px; padding:0 20px 16vh; text-align:center; pointer-events:none; opacity:0; visibility:hidden; }
  #fxSlam.on{ visibility:visible; animation:fxSlam 1.7s cubic-bezier(.2,1.3,.3,1) forwards; }
  #fxSlam small{ font-family:"IBM Plex Mono"; font-size:.75rem; letter-spacing:.2em; text-transform:uppercase; color:var(--energy); }
  #fxSlam b{ font-family:"IBM Plex Mono"; font-size:1.9rem; font-weight:700; letter-spacing:.05em; line-height:1.15; text-transform:uppercase; color:var(--text); text-shadow:0 0 26px var(--fc, var(--research)), 0 2px 0 #000; }
  #fxSlam span{ font-size:.9rem; color:var(--muted); text-shadow:0 1px 0 #000; }
  #fxFlash{ position:fixed; inset:0; z-index:94; background:#fff; opacity:0; pointer-events:none; visibility:hidden; }
  #fxFlash.on{ visibility:visible; animation:fxFlash .5s ease-out; }
  .app.fx-shake{ animation:fxShake .45s linear; }
  @keyframes fxSlam{ 0%{ opacity:0; transform:scale(2.3); } 13%{ opacity:1; transform:scale(.96); } 21%{ transform:scale(1); } 82%{ opacity:1; transform:scale(1); } 100%{ opacity:0; transform:scale(1.04); } }
  @keyframes fxFlash{ 0%{ opacity:.8; } 100%{ opacity:0; } }
  @keyframes fxShake{ 0%,100%{ transform:none; } 15%{ transform:translate(-5px,3px); } 30%{ transform:translate(4px,-4px); } 45%{ transform:translate(-3px,2px); } 60%{ transform:translate(3px,1px); } 80%{ transform:translate(-1px,-1px); } }

  /* 10 · transiciones entre pantallas */
  /* Las ventanas ya no aparecen ni desaparecen de golpe. El juego las abre y cierra con el atributo
     hidden desde muchos sitios; en vez de tocarlos todos, aquí hidden pasa a significar "invisible
     y sin eventos" y la transición hace el resto, también al cerrar. */
  .overlay{ transition:opacity .2s ease, visibility 0s; }
  .overlay[hidden]{ display:flex !important; opacity:0; visibility:hidden; pointer-events:none; transition:opacity .18s ease, visibility 0s linear .18s; }
  .overlay > .card{ transition:transform .28s cubic-bezier(.2,1.1,.3,1); }
  .overlay[hidden] > .card{ transform:translateY(16px) scale(.97); }
  main[data-dir="r"] > section.active{ animation:fxTabR .24s cubic-bezier(.2,.9,.3,1); }
  main[data-dir="l"] > section.active{ animation:fxTabL .24s cubic-bezier(.2,.9,.3,1); }
  @keyframes fxTabR{ from{ opacity:0; transform:translateX(26px); } to{ opacity:1; transform:none; } }
  @keyframes fxTabL{ from{ opacity:0; transform:translateX(-26px); } to{ opacity:1; transform:none; } }
  .fx-ghost{ position:fixed; z-index:45; margin:0; overflow:hidden; pointer-events:none; background:var(--bg); display:flex; flex-direction:column; gap:12px; }

  /* ---------- Juegos dentro del juego (src/ui/fx-games.js) ---------- */
  /* G1 · anomalía: un rombo que deriva y se apaga en 8 s; el anillo se cierra con el tiempo */
  #fxAnomaly{ position:fixed; z-index:45; width:52px; height:52px; margin:-26px 0 0 -26px; padding:0; border:0; background:none; cursor:pointer; animation:fxAnDrift 5s ease-in-out forwards, fxAnIn .3s cubic-bezier(.2,1.6,.4,1); touch-action:manipulation; }
  #fxAnomaly .gem{ position:absolute; left:50%; top:50%; width:22px; height:22px; margin:-11px 0 0 -11px; transform:rotate(45deg); border:2px solid var(--ac, var(--energy)); background:color-mix(in srgb, var(--ac, var(--energy)) 30%, transparent); box-shadow:0 0 18px var(--ac, var(--energy)), inset 0 0 8px rgba(255,255,255,.4); border-radius:4px; animation:fxAnSpin 1.6s linear infinite; }
  #fxAnomaly .ring{ position:absolute; inset:6px; border-radius:50%; border:2px solid rgba(255,255,255,.65); animation:fxAnRing 5s linear forwards; }
  #fxAnomaly.gone{ opacity:0; transform:scale(.4); transition:opacity .3s, transform .3s; }
  @keyframes fxAnDrift{ 0%{ transform:none; } 33%{ transform:translate(var(--x1,0), var(--y1,0)); } 66%{ transform:translate(var(--x2,0), var(--y2,0)); } 100%{ transform:translate(var(--x3,0), var(--y3,0)); } }
  @keyframes fxAnIn{ from{ opacity:0; scale:.3; } to{ opacity:1; scale:1; } }
  @keyframes fxAnSpin{ to{ transform:rotate(405deg); } }
  @keyframes fxAnRing{ from{ transform:scale(1); opacity:.9; } to{ transform:scale(.35); opacity:.2; } }
  .meter{ position:relative; }
  .fx-x7{ position:absolute; right:4px; top:3px; font-family:"IBM Plex Mono"; font-size:.75rem; font-weight:700; color:#1a1206; background:var(--energy); border-radius:999px; padding:0 6px; line-height:1.5; white-space:nowrap; }
  body.fx-frenzy #mC{ color:var(--energy); text-shadow:0 0 12px rgba(232,163,61,.7); }
  body.fx-frenzy #rC{ color:var(--energy) !important; }
  body.fx-frenzy .corebox{ box-shadow:0 0 0 2px color-mix(in srgb, var(--energy) 40%, transparent); }
  /* G2 · tercera habilidad */
  .ability.wide{ grid-column:1/-1; }
  .ability.wide .an svg{ stroke:var(--compute); }
  /* G2 y G8 · pantalla de minijuego */
  #fxGame{ position:fixed; inset:0; z-index:97; background:rgba(4,6,8,.94); backdrop-filter:blur(3px); display:flex; flex-direction:column; align-items:center; padding:max(22px, env(safe-area-inset-top,0px)) 16px max(18px, env(safe-area-inset-bottom,0px)); gap:4px; animation:fxCapIn .2s ease-out; touch-action:manipulation; user-select:none; -webkit-user-select:none; }
  #fxGame.out{ opacity:0; transition:opacity .22s; pointer-events:none; }
  #fxGame .gt{ font-family:"IBM Plex Mono"; font-weight:700; font-size:1.05rem; letter-spacing:.04em; }
  #fxGame .gs{ font-family:"IBM Plex Mono"; font-size:.84rem; color:var(--muted); min-height:1.4em; }
  #fxGame canvas{ flex:1; width:100%; max-width:520px; min-height:0; display:block; }
  #fxGame .gh{ font-family:"IBM Plex Mono"; font-size:.78rem; letter-spacing:.06em; text-transform:uppercase; color:var(--muted); min-height:1.4em; text-align:center; }
  #fxGame .gend{ position:absolute; left:16px; right:16px; top:50%; transform:translateY(-50%); max-width:420px; margin:0 auto; background:var(--surface); border:1px solid var(--border); border-radius:14px; padding:18px 16px; display:flex; flex-direction:column; gap:10px; text-align:center; box-shadow:0 20px 50px rgba(0,0,0,.6); animation:fxCapIn .25s ease-out; }
  #fxGame .gend b{ font-family:"IBM Plex Mono"; font-size:1.15rem; }
  #fxGame .gend p{ margin:0; font-size:.92rem; line-height:1.45; color:var(--muted); }
  #fxGame .gend .dm{ color:var(--risk); font-family:"IBM Plex Mono"; font-size:.84rem; }
  #fxGame .gend .btn-s{ appearance:none; align-self:center; border:1px solid var(--border); border-radius:9px; padding:10px 22px; font-family:"IBM Plex Mono"; font-size:.9rem; cursor:pointer; }
  #fxGame.fx-shake{ animation:fxShake .3s linear; }

  /* ---------- Expedición (G5) y Contratos (G6): src/ui/fx-quests.js ---------- */
  #fxQuest{ position:fixed; inset:0; z-index:97; background:rgba(4,6,8,.92); backdrop-filter:blur(3px); display:flex; align-items:center; justify-content:center; padding:max(16px, env(safe-area-inset-top,0px)) 16px max(16px, env(safe-area-inset-bottom,0px)); animation:fxCapIn .2s ease-out; }
  #fxQuest.out{ opacity:0; transition:opacity .22s; pointer-events:none; }
  #fxQuest .qcard{ position:relative; width:100%; max-width:400px; max-height:100%; overflow-y:auto; overflow-x:hidden; background:var(--surface); border:1px solid var(--border); border-radius:14px; padding:18px 16px 16px; display:flex; flex-direction:column; gap:12px; }
  #fxQuest .qx{ position:absolute; top:8px; right:8px; width:34px; height:34px; border-radius:50%; appearance:none; border:1px solid var(--border); background:var(--surface-2); color:var(--muted); font-size:1.2rem; line-height:1; cursor:pointer; padding:0; }
  #fxQuest .eyebrow{ color:var(--energy); font-family:"IBM Plex Mono"; font-size:.75rem; letter-spacing:.14em; text-transform:uppercase; padding-right:40px; display:flex; align-items:center; gap:6px; flex-wrap:wrap; }
  #fxQuest.con .eyebrow{ color:var(--research); }
  #fxQuest .eyebrow .matc{ letter-spacing:0; text-transform:none; font-size:.8rem; }
  #fxQuest h3{ margin:-6px 0 0; font-family:"IBM Plex Mono"; font-size:1.05rem; line-height:1.3; padding-right:30px; }
  #fxQuest p{ margin:0; font-size:.9rem; line-height:1.45; color:var(--muted); }
  #fxQuest .qlead{ color:var(--text); } #fxQuest .qlead b{ color:var(--energy); font-weight:600; }
  #fxQuest .qfoot{ font-size:.82rem; text-align:center; color:var(--muted); margin-top:-4px; min-height:1.4em; }
  #fxQuest .qfoot.wait{ color:var(--energy); font-family:"IBM Plex Mono"; animation:fxBlink 1s steps(2) infinite; }
  @keyframes fxBlink{ 50%{ opacity:.35; } }
  .qsteps{ margin:0; padding-left:1.1em; display:flex; flex-direction:column; gap:6px; font-size:.9rem; line-height:1.4; color:var(--muted); }
  .qsteps b{ color:var(--text); font-weight:600; }
  .qex{ font-size:.84rem; line-height:1.45; color:var(--muted); background:var(--surface-2); border:1px dashed var(--border); border-radius:10px; padding:8px 10px; }
  .qex b{ color:var(--energy); font-weight:600; }
  /* botones: altura normal, contorno en vez de relleno, nunca pegados */
  .qbtn{ appearance:none; min-height:44px; padding:10px 14px; border-radius:10px; border:1px solid var(--border); background:var(--surface-2); color:var(--text); font-family:"IBM Plex Mono"; font-size:.88rem; font-weight:600; cursor:pointer; }
  .qbtn.go{ border-color:var(--energy); color:var(--energy); background:color-mix(in srgb, var(--energy) 10%, var(--surface-2)); }
  #fxQuest.con .qbtn.go{ border-color:var(--research); color:var(--research); background:color-mix(in srgb, var(--research) 10%, var(--surface-2)); }
  .qbtn:disabled{ opacity:.45; cursor:not-allowed; }
  .qrow2{ display:grid; grid-template-columns:1fr 1fr; gap:10px; }
  .qlink{ appearance:none; align-self:center; background:none; border:0; padding:8px 10px; color:var(--muted); font-family:"IBM Plex Sans", sans-serif; font-size:.86rem; text-decoration:underline; text-underline-offset:3px; cursor:pointer; }
  /* expedición: los seis niveles en una fila */
  .qstp{ display:grid; grid-template-columns:repeat(6,1fr); gap:5px; }
  .qstp span{ display:flex; flex-direction:column; align-items:center; gap:1px; padding:6px 0 5px; border-radius:8px; border:1px solid var(--border); background:var(--surface-2); font-family:"IBM Plex Mono"; color:var(--muted-2); }
  .qstp b{ font-size:.92rem; font-weight:700; } .qstp small{ font-size:.75rem; }
  .qstp .ok{ color:var(--compute); border-color:var(--compute-dim); }
  .qstp .now{ color:var(--text); border-color:var(--energy); background:color-mix(in srgb, var(--energy) 14%, var(--surface-2)); }
  .qstp .now small{ color:var(--energy); }
  .qstp .lost{ color:var(--risk); border-color:var(--risk); }
  .qstpl{ display:flex; justify-content:space-between; font-size:.75rem; color:var(--muted-2); margin-top:-8px; }
  /* contratos: tres tarjetas compactas; el detalle solo se abre en la elegida */
  .qlist{ display:flex; flex-direction:column; gap:8px; }
  .qct{ appearance:none; text-align:left; color:var(--text); font:inherit; border-radius:11px; border:1px solid var(--border); border-left:3px solid var(--qc); background:var(--surface-2); padding:9px 11px; cursor:pointer; display:grid; grid-template-columns:1fr auto; gap:3px 10px; align-items:center; }
  .qct.easy{ --qc:var(--compute); } .qct.medium{ --qc:var(--energy); } .qct.hard{ --qc:var(--research); }
  .qct .qd{ font-family:"IBM Plex Mono"; font-size:.75rem; letter-spacing:.08em; text-transform:uppercase; color:var(--qc); }
  .qct .qrw{ font-family:"IBM Plex Mono"; font-size:.78rem; display:flex; gap:8px; justify-content:flex-end; flex-wrap:wrap; }
  .qct b{ grid-column:1/-1; font-family:"IBM Plex Mono"; font-size:.9rem; font-weight:600; line-height:1.3; }
  .qct .qwhy{ grid-column:1/-1; font-size:.84rem; line-height:1.4; color:var(--muted); display:none; }
  .qct[aria-pressed="true"]{ border-color:var(--qc); background:color-mix(in srgb, var(--qc) 10%, var(--surface-2)); }
  .qct[aria-pressed="true"] .qwhy{ display:block; }
  .qr{ font-weight:600; white-space:nowrap; } .qr.an{ color:var(--energy); } .qr .ri{ width:12px; height:12px; }
  .note.pity{ color:var(--compute); border-left:2px solid var(--compute-dim); padding-left:8px; }
  /* G1: la anomalía solo existe en el Núcleo */
  body:not([data-tab="core"]) #fxAnomaly{ display:none; }
  /* filas de la sonda y de los contratos */
  #probeRow.armed, #contractRow.armed{ border-color:var(--energy-dim); }
  #contractRow{ margin-top:2px; }
  #contractRow .bar{ height:5px; border-radius:3px; background:var(--bg); overflow:hidden; margin:5px 0 3px; }
  #contractBar, #contractStripBar, #contractCoreBar{ height:100%; width:0; background:var(--research); transition:width .3s linear; }
  #contractRow .name .st{ font-family:"IBM Plex Mono"; font-size:.75rem; color:var(--research); font-weight:400; margin-left:4px; }
  .cstrip{ margin:6px 16px 0; padding:6px 10px; border-radius:9px; border:1px solid var(--research-dim); background:color-mix(in srgb, var(--research) 8%, var(--surface)); display:flex; flex-direction:column; gap:4px; }
  .cstrip .l{ display:flex; align-items:baseline; gap:8px; font-size:.8rem; min-width:0; }
  .cstrip .l b{ font-family:"IBM Plex Mono"; font-size:.75rem; letter-spacing:.06em; text-transform:uppercase; color:var(--research); flex:none; }
  .cstrip .l span{ white-space:nowrap; overflow:hidden; text-overflow:ellipsis; min-width:0; }
  .cstrip .l .p{ margin-left:auto; color:var(--muted); font-size:.76rem; flex:none; }
  .cstrip .bar{ height:4px; border-radius:2px; background:var(--bg); overflow:hidden; }
  body[data-tab="core"] .cstrip{ display:none; } /* en el Núcleo va sobre el arte (#contractCore) */
  /* lo que cuenta para el contrato en curso lleva una marca */
  body[data-contract="buy"] #buildings .row button[data-f="buy"], body[data-contract="tech"] #techs .row button, body[data-contract="clicks"] .corebox, body[data-contract="models"] .modelcard.next, body[data-contract="colony"] #shipRow{ outline:1px dashed var(--research); outline-offset:2px; }
  /* H5 · aviso del pulso */
  #pulseHint{ display:flex; flex-direction:column; gap:6px; }
  #pulseHint[hidden]{ display:none; }
  #pulseHint .btn-s{ align-self:flex-start; appearance:none; border:1px solid var(--border); border-radius:8px; padding:7px 12px; font-family:"IBM Plex Mono"; font-size:.82rem; cursor:pointer; }

  /* 13 · riesgo que se siente */
  #fxVig{ position:fixed; inset:0; z-index:40; pointer-events:none; opacity:0; box-shadow:inset 0 0 70px 24px rgba(224,82,90,.85); }

  /* 18 · voz del modelo */
  .toast.voice.fx-voice{ align-items:flex-start; border-radius:4px 14px 14px 14px; box-shadow:0 6px 24px rgba(0,0,0,.5), 0 0 18px rgba(154,134,230,.25); }
  .toast.voice.fx-voice .toast-avatar{ box-shadow:0 0 0 2px var(--research), 0 0 12px rgba(154,134,230,.6); }
  .fx-wave{ display:flex; align-items:center; gap:2px; height:30px; flex:none; }
  .fx-wave i{ display:block; width:3px; height:4px; border-radius:2px; background:var(--research); opacity:.55; }
  .speaking .fx-wave i{ animation:fxWave .5s ease-in-out infinite alternate; opacity:1; }
  .speaking .fx-wave i:nth-child(2){ animation-delay:-.32s; } .speaking .fx-wave i:nth-child(3){ animation-delay:-.12s; } .speaking .fx-wave i:nth-child(4){ animation-delay:-.4s; } .speaking .fx-wave i:nth-child(5){ animation-delay:-.2s; }
  @keyframes fxWave{ from{ height:4px; } to{ height:22px; } }
  .fx-vtxt{ font-family:"IBM Plex Sans", system-ui, sans-serif; font-size:.92rem; line-height:1.4; color:var(--text); min-width:0; }
  .fx-vsc{ font-family:"IBM Plex Mono"; color:var(--research); }

  /* 19 · cápsula de recompensa */
  #fxCapsule{ position:fixed; inset:0; z-index:96; background:rgba(4,6,8,.86); backdrop-filter:blur(3px); cursor:pointer; animation:fxCapIn .2s ease-out; }
  #fxCapsule.out{ opacity:0; transition:opacity .24s; pointer-events:none; }
  #fxCapsule canvas{ position:absolute; inset:0; width:100%; height:100%; }
  #fxCapsule .t{ position:absolute; left:0; right:0; top:16%; text-align:center; font-family:"IBM Plex Mono"; font-weight:600; font-size:1.05rem; color:var(--text); padding:0 20px; }
  #fxCapsule .h{ position:absolute; left:0; right:0; bottom:16%; text-align:center; font-family:"IBM Plex Mono"; font-size:.78rem; letter-spacing:.1em; text-transform:uppercase; color:var(--muted); }
  @keyframes fxCapIn{ from{ opacity:0; } to{ opacity:1; } }

  /* 19b · tres cartas boca abajo y 19d · paquete cifrado: comparten el fondo a pantalla completa */
  #fxCards, #fxDecrypt{ position:fixed; inset:0; z-index:96; background:rgba(4,6,8,.9); backdrop-filter:blur(3px); display:flex; flex-direction:column; align-items:center; justify-content:center; gap:10px; padding:20px 16px; text-align:center; animation:fxCapIn .2s ease-out; }
  #fxCards.out, #fxDecrypt.out{ opacity:0; transition:opacity .24s; pointer-events:none; }
  #fxCards .t, #fxDecrypt .t{ font-family:"IBM Plex Mono"; font-weight:600; font-size:1.05rem; color:var(--text); }
  #fxCards .st{ font-size:.88rem; color:var(--muted); max-width:30ch; margin-bottom:10px; }
  #fxCards .h, #fxDecrypt .h{ font-family:"IBM Plex Mono"; font-size:.78rem; letter-spacing:.1em; text-transform:uppercase; color:var(--muted); min-height:1.4em; margin-top:12px; }
  .fxc3{ display:flex; gap:12px; perspective:900px; }
  .fxc{ appearance:none; border:0; background:none; padding:0; width:min(98px, 27vw); height:150px; position:relative; transform-style:preserve-3d; transition:transform .6s cubic-bezier(.2,1.1,.3,1), opacity .4s; cursor:pointer; color:inherit; }
  .fxc span{ position:absolute; inset:0; border-radius:12px; backface-visibility:hidden; -webkit-backface-visibility:hidden; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:6px; font-family:"IBM Plex Mono"; padding:6px; }
  .fxc .bk{ background:repeating-linear-gradient(45deg, #15222a 0 8px, #1b2a33 8px 16px); border:1px solid var(--energy-dim); box-shadow:inset 0 0 0 4px #0e1418, inset 0 0 0 5px var(--energy-dim); }
  .fxc .bk::after{ content:""; width:26px; height:26px; border:2px solid var(--energy); transform:rotate(45deg); border-radius:4px; }
  .fxc .ft{ transform:rotateY(180deg); background:var(--surface-2); border:1px solid var(--fcol); box-shadow:0 0 22px color-mix(in srgb, var(--fcol) 45%, transparent); }
  .fxc .ft b{ font-size:1.15rem; font-weight:700; color:var(--fcol); line-height:1.1; }
  .fxc .ft small{ font-size:.75rem; color:var(--muted); line-height:1.25; }
  .fxc.up{ transform:rotateY(180deg); } .fxc.dim{ opacity:.45; }
  .fxc.win{ transform:rotateY(180deg) translateY(10px) scale(1.08); }
  .fxc:not(.win):not(.up):active{ transform:scale(.95); }
  #fxDecrypt{ cursor:pointer; touch-action:none; user-select:none; -webkit-user-select:none; }
  #fxDecrypt pre{ margin:6px 0 0; font-family:"IBM Plex Mono"; font-size:.92rem; line-height:1.6; color:var(--compute-dim); white-space:pre; max-width:100%; overflow:hidden; }
  #fxDecrypt pre b{ color:var(--text); font-weight:600; }
  #fxDecrypt pre i{ font-style:normal; font-weight:700; color:var(--energy); text-shadow:0 0 12px rgba(232,163,61,.7); }
  #fxDecrypt .bar{ width:200px; height:4px; border-radius:2px; background:var(--surface-3); overflow:hidden; margin-top:8px; }
  #fxDecrypt .bar i{ display:block; height:100%; width:0; background:var(--compute); }
  #fxDecrypt.ok .bar i{ background:var(--energy); }

  /* 16 · planeta de la colonia (src/ui/fx-planet.js) */
  .colhead.has-planet{ padding-right:112px; min-height:112px; }
  .fx-planet{ position:absolute; right:8px; top:50%; width:100px; height:100px; margin-top:-50px; touch-action:pan-y; cursor:grab; }

  /* 24 · árbol de Anclas con energía (src/ui/fx-tree.js) */
  #anclasTreeCv{ display:block; width:100%; height:300px; margin-bottom:12px; border-radius:14px; border:1px solid var(--border); background:radial-gradient(circle at 50% 100%, rgba(232,163,61,.10), transparent 60%), #0d1216; cursor:pointer; touch-action:manipulation; }

  /* 17 · barra de pestañas líquida */
  nav.tabs{ position:relative; }
  .fx-tabind{ position:absolute; border-radius:10px; background:var(--surface-2); box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--compute) 35%, transparent); pointer-events:none; z-index:0; }
  body.fx-tabs nav.tabs button{ z-index:1; }
  body.fx-tabs nav.tabs button.active{ background:transparent; }
  nav.tabs button svg.fx-bo{ animation:fxBo .5s cubic-bezier(.2,1.6,.4,1); }
  body.doc-militar .fx-tabind{ box-shadow:inset 0 0 0 1px var(--risk-dim); } body.doc-cientifica .fx-tabind{ box-shadow:inset 0 0 0 1px var(--research-dim); } body.doc-social .fx-tabind{ box-shadow:inset 0 0 0 1px var(--compute-dim); }
  body.fx-tabs.doc-militar nav.tabs button.active, body.fx-tabs.doc-cientifica nav.tabs button.active, body.fx-tabs.doc-social nav.tabs button.active{ box-shadow:none; }

  /* 25 · vuelta tras ausencia */
  .wb-rows{ display:flex; flex-direction:column; gap:6px; background:var(--surface-2); border:1px solid var(--border); border-radius:10px; padding:10px 12px; }
  .wb-row{ display:flex; justify-content:space-between; align-items:baseline; gap:10px; font-family:"IBM Plex Mono"; font-size:.86rem; animation:fxRowIn .45s cubic-bezier(.2,1.2,.3,1) backwards; }
  .wb-row span{ color:var(--muted); display:flex; align-items:center; gap:6px; }
  .wb-row span .ri{ color:var(--mc); width:13px; height:13px; margin:0; }
  .wb-row b{ color:var(--mc); font-size:1rem; font-weight:600; font-variant-numeric:tabular-nums; }
  @keyframes fxRowIn{ from{ opacity:0; transform:translateX(-14px); } to{ opacity:1; transform:none; } }

  /* 11 · barras con energía (entrenamiento y fabricación de nave) */
  .traincard .bar{ height:9px; border-radius:5px; overflow:visible; }
  #trainBar, #shipBar{ position:relative; border-radius:5px; min-width:9px; }
  #trainBar{ background:linear-gradient(90deg, #4a3596, #d5c6ff); box-shadow:0 0 10px rgba(154,134,230,.55); }
  #shipBar{ background:linear-gradient(90deg, #1f5a4f, #a8f5e4); }
  #trainBar::before, #shipBar::before{ content:""; position:absolute; inset:0; border-radius:inherit; background:linear-gradient(115deg, transparent 0 38%, rgba(255,255,255,.28) 38% 62%, transparent 62%) 0 0/24px 100%; animation:fxStripes .6s linear infinite; }
  #trainBar::after{ content:""; position:absolute; right:-5px; top:50%; width:14px; height:14px; margin-top:-7px; border-radius:50%; background:radial-gradient(circle, #fff 0 25%, rgba(214,198,255,.7) 45%, transparent 70%); }
  @keyframes fxStripes{ to{ background-position:24px 0; } }

  /* 21 · Sobrecarga con impacto */
  body.fx-oc .corebox{ border-color:var(--energy); box-shadow:0 0 0 2px color-mix(in srgb, var(--energy) 45%, transparent), inset 0 0 38px rgba(232,163,61,.28); transition:box-shadow .3s, border-color .3s; }
  body.fx-oc #mC{ color:var(--energy); text-shadow:0 0 12px rgba(232,163,61,.7); }
  body.fx-oc #rC{ color:var(--energy) !important; }
  body.fx-oc #abOc{ border-color:var(--energy); box-shadow:inset 0 0 0 1px var(--energy), 0 0 14px rgba(232,163,61,.35); }
  body.fx-oc #abOc .cd{ background:var(--energy); }

  /* 14 · edificios que se levantan: la silueta sube con rebote (la línea de escaneo va en el canvas) */
  .skyhero .pop, .colhero .pop{ animation:fxRise .7s cubic-bezier(.2,1.3,.3,1); }
  @keyframes fxRise{ from{ transform:scaleY(0); } to{ transform:scaleY(1); } }

  /* 01 · núcleo en 3D (src/ui/fx-core3d.js) */
  .corewrap{ position:relative; width:var(--core, 230px); height:var(--core, 230px); max-width:100%; flex:none; }
  .corewrap #core{ position:relative; z-index:1; display:block; width:100%; height:100%; }
  #core3d{ position:absolute; inset:-12%; width:124%; height:124%; pointer-events:none; z-index:0; -webkit-mask-image:radial-gradient(circle closest-side, #000 72%, transparent 98%); mask-image:radial-gradient(circle closest-side, #000 72%, transparent 98%); }
  /* el canvas 2D tampoco deja marca al tocar: sin resalte de toque ni contorno de foco cuadrado */
  #core{ -webkit-tap-highlight-color:transparent; outline:none; }
  #core:focus-visible{ box-shadow:0 0 0 2px var(--compute); }

  /* 07 · mapa orbital vivo (src/ui/fx-map.js) */
  #netMapCv{ display:block; width:100%; height:216px; cursor:pointer; touch-action:manipulation; }
  @media (max-height: 700px){ #netMapCv{ height:190px; } }

  /* 05 · cartas holográficas (src/ui/fx-holo.js) — EFECTO EN PRUEBA: para quitarlo, borrar este
     bloque entero junto con fx-holo.js y su <script>. No hay nada más que dependa de él. */
  .fx-holo{ overflow:hidden; border-radius:14px 14px 0 0; }
  .fx-holo > img{ transform:perspective(700px) rotateY(var(--hx,0deg)) rotateX(var(--hy,0deg)) scale(1.06); will-change:transform; }
  .fx-holo .fx-sheen{ position:absolute; inset:0; pointer-events:none; mix-blend-mode:color-dodge; opacity:.62; z-index:1;
    background:
      radial-gradient(circle at var(--mx,50%) var(--my,50%), rgba(255,255,255,.5), transparent 40%),
      linear-gradient(115deg, transparent 22%, rgba(82,224,196,.42) 38%, rgba(154,134,230,.42) 50%, rgba(232,163,61,.38) 62%, transparent 78%);
    background-size:100% 100%, 220% 220%; background-position:0 0, var(--sx,50%) var(--sy,50%); }
  .fx-holo .fnd-tag, .fx-holo .fnd-scan{ z-index:2; }
  /* fin de 05 */

  @media (prefers-reduced-motion: reduce){
    .overlay, .overlay[hidden], .overlay > .card{ transition:none; }
    main[data-dir] > section.active{ animation:none; }
    .speaking .fx-wave i{ animation:none; }
    #fxAnomaly, #fxAnomaly .gem{ animation:none; }
    .fxc{ transition:none; }
    .wb-row, #trainBar::before, #shipBar::before, nav.tabs button svg.fx-bo, .skyhero .pop, .colhero .pop{ animation:none; }
    .fx-sq, .row .icon.fx-bo, .cnt.fx-pop, .fx-slot, .fx-bump{ animation:none; }
    .fx-rip, .fx-cost{ display:none; }
  }
  /* con pisos, el mapa del árbol crece hacia arriba */
  body.has-floors #anclasTreeCv{ height:440px; }
