/* Caso Abierto — hoja de estilo única.
   Dos materiales: el expediente (papel, serif, cálido) y la consola (pantalla,
   monoespaciada, fría). El contraste entre ambos es toda la dirección de arte;
   todo lo demás es contención. */

:root {
  /* Papel carbón, no azul de pantalla: el negro tira a betún y la tinta a
     marfil, como un expediente bajo un flexo. El acento es manila de carpeta;
     el rojo, de sello de goma. */
  --bg:        #0c0b09;
  --bg-2:      #14120f;
  --panel:     #191612;
  --panel-2:   #211d18;
  --line:      #302a22;
  --line-soft: #26211b;
  --ink:       #ebe3d1;
  --ink-dim:   #a69d8b;
  /* #6f675a daba 3.0–3.5:1 sobre los cuatro fondos del juego: por debajo de
     AA en las 64 reglas que lo usan —contadores, rótulos, pies de foto, el
     aviso de filas recortadas—. Subido a 4.7–5.5:1 sin salir del tono apagado
     que la dirección de arte pide. */
  --ink-faint: #8f8676;
  --amber:     #e2b15a;
  --amber-dim: #8d6d33;
  --jade:      #5fbb96;
  --violet:    #a891d9;
  --red:       #cf4a3c;
  /* El mismo rojo de sello no vale como texto: sobre el bloque de error da
     3.8:1. Éste es para leer; `--red` se queda para sellos y bordes. */
  --red-claro: #e7685a;
  --paper:     #e9e1cf;
  --paper-ink: #201d18;
  --paper-dim: #6b6455;
  --accent:    var(--amber);

  /* Tres voces tipográficas, ninguna de sistema: un titular condensado de
     cartel, una romana de periódico para leer y una máquina de escribir para
     rótulos, datos y SQL. Van empaquetadas (static/fonts, OFL). */
  --display: "Big Shoulders Display", "Oswald", Impact, "Arial Narrow", sans-serif;
  --serif: "Newsreader", "Iowan Old Style", Palatino, Georgia, serif;
  --sans: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono: "Courier Prime", "Courier New", Courier, monospace;

  --r: 4px;
  --safe-b: env(safe-area-inset-bottom, 0px);
}

/* Alto contraste: no es otra piel, es el mismo expediente con más tinta. Se
   suben los tonos que la dirección de arte dejó apagados a propósito —los
   grises de rótulo, los filetes, el papel— y se deja todo lo demás en su
   sitio, para no mantener dos paletas que se desincronizan. */
html.contraste {
  --bg:        #000000;
  --bg-2:      #0a0908;
  --panel:     #141210;
  --panel-2:   #1d1a16;
  --line:      #6a5f52;
  --line-soft: #4e463c;
  --ink:       #ffffff;
  --ink-dim:   #e4dccb;
  --ink-faint: #c3bbaa;
  --amber:     #ffd07d;
  --amber-dim: #cba25a;
  --jade:      #86e6bd;
  --violet:    #c9b6ff;
  --red:       #ff8577;
  --red-claro: #ff9b8e;
  --paper:     #fffdf6;
  --paper-ink: #000000;
  --paper-dim: #3c372f;
}
/* El pliego de hechos lleva su propia paleta local: aquí se le sube la suya. */
html.contraste .accuse {
  --panel: #f2ead6; --panel-2: #e2d8bd; --bg-2: #fffdf6;
  --line: rgba(0,0,0,.45); --line-soft: rgba(0,0,0,.25);
  --ink-dim: #241f18; --ink-faint: #3c372f;
  --amber: #6b4e19; --amber-dim: #8a6b32; --accent: #6b4e19;
  --jade: #1f6347; --red: #8e2f29; --red-claro: #8e2f29;
}
html.contraste .accuse .field label { color: #1a1611; }
html.contraste .accuse .field input { border-bottom-width: 2px; border-bottom-color: rgba(0,0,0,.55); }
/* Los filetes finos desaparecen en pantallas malas: aquí se ven. */
html.contraste .hint, html.contraste .solution, html.contraste .evid,
html.contraste .carpeta, html.contraste .ajuste select, html.contraste .btn { border-width: 2px; }
html.contraste .dossier-stamp { border-width: 2.5px; }

@font-face { font-family: "Big Shoulders Display"; font-style: normal; font-weight: 500 900; font-display: swap; src: url("fonts/BigShouldersDisplay.woff2") format("woff2"); }
@font-face { font-family: "Newsreader"; font-style: normal; font-weight: 400 700; font-display: swap; src: url("fonts/Newsreader.woff2") format("woff2"); }
@font-face { font-family: "Newsreader"; font-style: italic; font-weight: 400 700; font-display: swap; src: url("fonts/Newsreader-Italic.woff2") format("woff2"); }
@font-face { font-family: "Courier Prime"; font-style: normal; font-weight: 400; font-display: swap; src: url("fonts/CourierPrime.woff2") format("woff2"); }
@font-face { font-family: "Courier Prime"; font-style: normal; font-weight: 700; font-display: swap; src: url("fonts/CourierPrime-Bold.woff2") format("woff2"); }
@font-face { font-family: "Courier Prime"; font-style: italic; font-weight: 400; font-display: swap; src: url("fonts/CourierPrime-Italic.woff2") format("woff2"); }

* { box-sizing: border-box; }

/* Un `display` explícito en una clase gana al atributo `hidden`, y entonces el
   modal y la barra de sugerencias aparecen siempre. Esta regla lo zanja para
   todo el documento. */
[hidden] { display: none !important; }

html, body {
  margin: 0; padding: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  -webkit-text-size-adjust: 100%;
  overscroll-behavior-y: none;
}

body {
  min-height: 100dvh;
  background-image:
    radial-gradient(1200px 700px at 50% -14%, rgba(226,177,90,.09), transparent 60%),
    radial-gradient(900px 600px at 100% 110%, rgba(0,0,0,.5), transparent 60%);
  background-attachment: fixed;
}
body.sin-scroll { overflow: hidden; }

/* Grano de película. Un SVG inline: ni una petición de red por una textura. */
.grain {
  position: fixed; inset: 0; pointer-events: none; z-index: 999; opacity: .16;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='140'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/></filter><rect width='140' height='140' filter='url(%23n)' opacity='.5'/></svg>");
  mix-blend-mode: overlay;
}

/* Lluvia: dos capas de gradientes repetidos que se DESPLAZAN POR TRANSFORMACIÓN.
   La versión anterior animaba `background-position`, y eso obliga a repintar
   la pantalla entera sesenta veces por segundo; en un teléfono se ve como
   saltos. Una transformación la mueve el compositor sin tocar un píxel.
   Cada capa se traslada exactamente un periodo de su patrón, así que el bucle
   no tiene costura. */
.rain { position: fixed; inset: 0; pointer-events: none; z-index: 1; opacity: .16; overflow: hidden; }
.rain::before, .rain::after {
  content: ""; position: absolute; left: -12%; right: -12%; top: -720px; bottom: -720px;
  background-image: repeating-linear-gradient(104deg, transparent 0 22px, rgba(190,215,255,.55) 22px 23px, transparent 23px 46px);
  background-size: 460px 460px;
  animation: llueve-a 1.1s linear infinite; will-change: transform;
}
.rain::after {
  background-image: repeating-linear-gradient(99deg, transparent 0 38px, rgba(190,215,255,.35) 38px 39px, transparent 39px 74px);
  background-size: 700px 700px;
  animation: llueve-b 1.7s linear infinite;
}
@keyframes llueve-a { to { transform: translate3d(-110px, 460px, 0); } }
@keyframes llueve-b { to { transform: translate3d(-160px, 700px, 0); } }
@media (prefers-reduced-motion: reduce) {
  .rain::before, .rain::after { animation: none; }
  .rain { opacity: .08; }
}
/* En pantallas táctiles el grano no se mezcla: `mix-blend-mode` sobre toda
   la página obliga a componer cada fotograma otra vez. Se queda como una capa
   translúcida normal, que se ve casi igual y no cuesta nada. */
@media (pointer: coarse) {
  .grain { mix-blend-mode: normal; opacity: .07; }
}

button, input, textarea { font: inherit; color: inherit; }
h1, h2, h3 { margin: 0 0 .4em; line-height: 1.15; }
a { color: var(--accent); }

/* ---------- barra superior ---------- */
.topbar {
  position: sticky; top: 0; z-index: 50;
  display: flex; align-items: center; gap: 12px;
  padding: 10px 16px; padding-top: calc(10px + env(safe-area-inset-top, 0px));
  background: rgba(10,12,15,.86);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line-soft);
}
/* `margin-right:auto` en la marca y no `margin-left:auto` en el botón del
   manual: así TODO lo que va detrás forma un solo grupo a la derecha. Con el
   auto en el ☰, el botón de ahorro se quedaba suelto en mitad de la barra
   —pegado a la marca— mientras los otros dos controles estaban en la esquina. */
.brand { display: flex; align-items: center; gap: 10px; min-width: 0; margin-right: auto; }
.brand-mark {
  display: grid; place-items: center;
  width: 34px; height: 34px; flex: 0 0 34px;
  border: 1px solid var(--amber-dim); border-radius: 3px;
  color: var(--amber); font-family: var(--mono); font-size: 13px; letter-spacing: .06em;
  background: linear-gradient(160deg, rgba(216,162,74,.16), transparent);
}
.brand-text { display: flex; flex-direction: column; min-width: 0; }
.brand-text strong { font-family: var(--serif); font-size: 17px; letter-spacing: .01em; }
.brand-text span {
  font-size: 10.5px; color: var(--ink-faint); text-transform: uppercase; letter-spacing: .13em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.score {
  font-family: var(--mono); font-size: 12px; color: var(--ink-dim);
  border: 1px solid var(--line); border-radius: 999px; padding: 5px 11px; white-space: nowrap;
}
.icon-btn {
  background: none; border: 1px solid var(--line); color: var(--ink-dim);
  width: 34px; height: 34px; flex: 0 0 34px; border-radius: 8px; cursor: pointer; font-size: 15px;
  display: grid; place-items: center; position: relative; transition: color .12s, border-color .12s;
}
.icon-btn:hover { color: var(--ink); border-color: var(--amber-dim); }
.manual-btn { margin-left: 0; }
/* El ☰ solo no decía «manual»: quien buscaba una referencia no lo encontraba.
   Con sitio, lleva la palabra; en pantallas estrechas vuelve a ser el icono. */
.manual-rotulo { display: none; }
@media (min-width: 760px) {
  .manual-btn { width: auto; flex: 0 0 auto; padding: 0 10px; display: inline-flex; align-items: center; gap: 6px; font-size: 13px; }
  .manual-rotulo { display: inline; font-family: var(--mono); letter-spacing: .04em; }
}
.enlace-manual { margin-left: 6px; }
.enlace-manual b { color: var(--ink); font-weight: 600; }
#manual-body .patron.resaltado { outline: 2px solid var(--accent); outline-offset: 4px; border-radius: 6px; transition: outline-color .6s; }
.manual-count {
  position: absolute; top: -6px; right: -6px;
  background: var(--accent); color: #17130a; font-family: var(--mono); font-size: 9.5px;
  min-width: 16px; height: 16px; border-radius: 999px; display: grid; place-items: center;
  padding: 0 4px; font-weight: 700;
}
.manual-count:empty { display: none; }

/* ---------- archivo ---------- */
.view { max-width: 1500px; margin: 0 auto; padding: 26px 16px 90px; position: relative; z-index: 2; }
.hero { max-width: 680px; margin: 22px 0 38px; }
.hero-kicker {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .2em; text-transform: uppercase;
  color: var(--amber-dim); margin: 0 0 10px;
}
.hero h1 {
  font-family: var(--serif); font-size: clamp(32px, 6.5vw, 52px); font-weight: 500;
  letter-spacing: -.015em; margin-bottom: .25em;
}
.hero-lead { color: var(--ink-dim); line-height: 1.68; margin: 0; font-size: 15.5px; }
.hero-stats { display: flex; flex-wrap: wrap; gap: 22px; margin-top: 26px; }
.hero-stat { display: flex; flex-direction: column; gap: 2px; }
.hero-stat b { font-family: var(--mono); font-size: 22px; color: var(--amber); font-weight: 500; }
.hero-stat span {
  font-size: 10.5px; color: var(--ink-faint); text-transform: uppercase; letter-spacing: .12em;
}

/* ---------- el archivo: cajones, carpetas y fotos ----------
 *
 * Una sala de archivo, no una cuadrícula web. Cada temporada es un cajón con
 * su placa; cada caso es una carpeta con una foto de evidencia pegada con
 * cinta —el primer plano de su introducción, pintado— y un sello. Las carpetas
 * cerradas van atadas con cordel y sin foto. Nada aquí es un rectángulo con
 * sombra por defecto: todo tiene una razón de ser dentro del mundo del juego.
 */

.cajon {
  display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; flex-wrap: wrap;
  margin: 44px 0 20px; padding-bottom: 12px; border-bottom: 1px solid var(--line);
  animation: ui-fundir .5s ease-out both;
}
.cajon-placa { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.cajon-num { font-family: var(--mono); font-size: 10px; letter-spacing: .24em; text-transform: uppercase; color: var(--accent); }
.cajon h2 { font-family: var(--serif); font-weight: 500; font-size: clamp(22px, 3vw, 30px); margin: 0; letter-spacing: -.01em; }
.cajon-sub { font-family: var(--serif); font-style: italic; color: var(--ink-faint); font-size: 13.5px; margin: 2px 0 0; max-width: 52ch; }
.cajon-carpetas { display: flex; gap: 5px; align-items: flex-end; padding-bottom: 4px; }
.cajon-carpetas i { display: block; width: 13px; height: 10px; border: 1px solid var(--ink-faint); border-radius: 1px 4px 1px 1px; opacity: .5; }
.cajon-carpetas i.ok { background: var(--accent); border-color: var(--accent); opacity: 1; }
.cajon-carpetas i.medio { border-color: var(--accent); opacity: .9; }

.carpetas { display: grid; gap: 16px; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); }
.carpetas > * { min-width: 0; }
@media (max-width: 400px) { .carpetas { grid-template-columns: 1fr; } }

.carpeta {
  position: relative; display: grid; grid-template-columns: 150px minmax(0, 1fr); gap: 0 16px; align-items: start;
  text-align: left; cursor: pointer; color: inherit;
  padding: 30px 16px 18px 14px;
  background: linear-gradient(170deg, #1a2029 0%, #131820 60%, #10151c 100%);
  border: 1px solid var(--line); border-radius: 3px 10px 10px 10px;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.035), 0 10px 26px rgba(0,0,0,.38);
  transform: rotate(var(--giro, 0deg));
  transition: transform .2s cubic-bezier(.2,.8,.2,1), border-color .2s, box-shadow .2s;
}
/* La textura de la cartulina: líneas casi invisibles. */
.carpeta::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
  background: repeating-linear-gradient(94deg, transparent 0 7px, rgba(255,255,255,.012) 7px 8px);
}
.carpeta:hover:not(.locked), .carpeta:focus-visible:not(.locked) {
  transform: rotate(0deg) translateY(-4px); border-color: var(--amber-dim);
  box-shadow: 0 22px 44px rgba(0,0,0,.55); outline: none;
}
.carpeta:hover:not(.locked) .foto { transform: rotate(0deg) scale(1.02); }
.pestana {
  position: absolute; top: 0; left: 0; padding: 5px 12px 4px 14px;
  font-family: var(--mono); font-size: 10px; letter-spacing: .18em; color: var(--ink-dim);
  background: var(--panel-2); border-right: 1px solid var(--line); border-bottom: 1px solid var(--line);
  border-radius: 3px 0 8px 0;
}
.carpeta.estado-en_curso .pestana { color: var(--amber); }
.carpeta.estado-resuelto .pestana { color: var(--jade); }
.carpeta.estado-rendido  .pestana { color: var(--red); }

.foto {
  position: relative; width: 150px; aspect-ratio: 4 / 3; box-sizing: border-box;
  padding: 5px 5px 16px; background: var(--paper);
  box-shadow: 0 8px 18px rgba(0,0,0,.55), 0 1px 0 rgba(255,255,255,.2) inset;
  transform: rotate(var(--foto-giro, -2deg)); transition: transform .25s cubic-bezier(.2,.8,.2,1);
}
.foto::before {
  /* la cinta que la sujeta */
  content: ""; position: absolute; top: -7px; left: 50%; width: 30px; height: 11px; margin-left: -15px;
  background: rgba(216,162,74,.62); border-radius: 1px; transform: rotate(-4deg);
  box-shadow: 0 1px 2px rgba(0,0,0,.4);
}
.foto .pintado, .foto .escena-viva {
  display: block; width: 100%; height: 100%; object-fit: cover;
  background: var(--bg-2); opacity: 0; transition: opacity .55s ease;
}
.foto .pintado.lista, .foto .escena-viva { opacity: 1; }
.foto .escena-viva svg { width: 100%; height: 100%; display: block; }
.foto-pie { position: absolute; left: 6px; right: 6px; bottom: 2px; font-family: var(--mono); font-size: 8.5px; letter-spacing: .12em; color: #6a6559; text-transform: uppercase; text-align: center; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }

/* Hueco abajo para el sello, que va en absoluto: sin él las etiquetas se le
   metían debajo. */
.carpeta-texto { display: flex; flex-direction: column; gap: 6px; min-width: 0; padding: 2px 0 30px; }
.carpeta h3 { font-family: var(--serif); font-weight: 500; font-size: 17.5px; line-height: 1.2; margin: 0; letter-spacing: -.005em; text-wrap: balance; }
.carpeta .lema { color: var(--ink-dim); font-size: 13px; line-height: 1.5; margin: 0; font-family: var(--serif); font-style: italic; }
.carpeta .dificultad { font-family: var(--mono); font-size: 10px; letter-spacing: .1em; color: var(--amber); }
.carpeta .etiquetas { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 4px; }
.carpeta .etiquetas .chip { font-size: 10px; }

.sello {
  position: absolute; right: 14px; bottom: 12px; padding: 3px 9px;
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .16em; text-transform: uppercase;
  border: 1.5px solid currentColor; border-radius: 3px; transform: rotate(-6deg);
  color: var(--ink-faint); opacity: .9; mix-blend-mode: normal;
}
.carpeta.estado-en_curso .sello { color: var(--amber); }
.carpeta.estado-resuelto .sello { color: var(--jade); }
.carpeta.estado-rendido  .sello { color: var(--red); }
.carpeta .medalla { position: absolute; right: 14px; top: 10px; font-size: 14px; line-height: 1; }
.medalla.med-oro { color: #e2b45e; } .medalla.med-plata { color: #c8d0da; } .medalla.med-bronce { color: #b07a4a; }

/* `opacity` sobre el botón entero dejaba el título a 2.8:1 y las etiquetas
   a 1.8:1: una carpeta bloqueada debe verse apagada, no ilegible. */
.carpeta.locked { cursor: not-allowed; opacity: 1; color: var(--ink-dim); background: linear-gradient(170deg, #15191f 0%, #11151b 100%); }
.carpeta.locked h3 { color: var(--ink-dim); }
.carpeta.locked .lema, .carpeta.locked .dificultad, .carpeta.locked .sello, .carpeta.locked .pestana { color: var(--ink-faint); }
/* Una carpeta bloqueada no es un caso: es un hueco con nombre. Ocupa lo que
   ocupa un nombre —sin foto y, salvo la primera de cada temporada, sin la
   frase de la regla— y se alinea arriba para no estirarse hasta la altura de
   los casos jugables de su fila. */
.carpeta.locked { grid-template-columns: minmax(0, 1fr); align-self: start; padding: 28px 14px 12px; }
.carpeta.locked .foto { display: none; }
.carpeta.locked .carpeta-texto { padding-bottom: 26px; }
.carpeta.locked h3 { font-size: 16px; }
.carpeta.locked .sello { bottom: 10px; }
.carpeta.locked .foto { background: #1b2028; box-shadow: none; }
.carpeta.locked .foto::before { display: none; }
.carpeta.locked .foto .cordel {
  position: absolute; inset: 0;
  background:
    linear-gradient(38deg, transparent 49%, var(--ink-faint) 49% 51%, transparent 51%),
    linear-gradient(-38deg, transparent 49%, var(--ink-faint) 49% 51%, transparent 51%);
  opacity: .6;
}
.carpeta.locked h3 { color: var(--ink-dim); }

@media (max-width: 560px) {
  .carpeta { grid-template-columns: 112px minmax(0, 1fr); gap: 0 12px; padding: 28px 12px 16px 12px; }
  .foto { width: 112px; padding: 4px 4px 13px; }
  .carpetas { grid-template-columns: 1fr; }
}

/* El fondo de la sala: la portada, oscurecida, quieta detrás de todo. */
#archivo-fondo { position: fixed; inset: 0; z-index: 0; pointer-events: none; opacity: .32; }
#archivo-fondo .pintado { width: 100%; height: 100%; object-fit: cover; display: block; opacity: 0; transition: opacity 1s ease; }
#archivo-fondo .pintado.lista { opacity: 1; }
#archivo-fondo::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(to bottom, rgba(10,12,15,.35) 0%, rgba(10,12,15,.9) 55%, rgba(10,12,15,.98) 100%);
}
#view-archivo { position: relative; z-index: 1; }

/* Imágenes pintadas en la portada, el caso activo y las viñetas de la intro. */
#titulo-escena .pintado, .activo .activo-escena .pintado, .plano-capa .pintado {
  width: 100%; height: 100%; object-fit: cover; display: block; opacity: 0; transition: opacity .6s ease;
}
#titulo-escena .pintado.lista, .activo .activo-escena .pintado.lista, .plano-capa .pintado.lista { opacity: 1; }
.plano-capa .pintado { position: absolute; inset: 0; }
.escena-marco .pintado { width: 100%; height: 100%; object-fit: cover; display: block; opacity: 0; transition: opacity .6s ease; }
.escena-marco .pintado.lista { opacity: 1; }

.season { margin-bottom: 44px; }
.chip {
  font-family: var(--mono); font-size: 10px; letter-spacing: .06em;
  border: 1px solid var(--line); border-radius: 4px; padding: 3px 6px; color: var(--ink-faint);
}
.state { font-family: var(--mono); font-size: 10px; letter-spacing: .14em; text-transform: uppercase; margin-left: auto; }
.state.resuelto { color: var(--jade); }
.state.rendido  { color: var(--red-claro); }
.state.en_curso { color: var(--amber); }
.state.bloqueado{ color: var(--ink-faint); }

/* ---------- vista de caso ---------- */
/* La rejilla del caso vive más abajo, en «el puesto de trabajo». */
.pane-title {
  font-family: var(--mono); font-size: 11px; letter-spacing: .16em; text-transform: uppercase;
  color: var(--ink-faint); margin: 0;
}

/* El expediente: papel de verdad, tipografía de máquina de escribir. */
.dossier {
  background: var(--paper); color: var(--paper-ink);
  border-radius: 4px; padding: 22px 22px 18px;
  box-shadow: 0 14px 34px rgba(0,0,0,.5);
  background-image: linear-gradient(180deg, rgba(0,0,0,.03), transparent 120px);
  position: relative;
}
.dossier::after {
  content: ""; position: absolute; inset: 0; border-radius: 4px; pointer-events: none;
  box-shadow: inset 0 0 60px rgba(120,100,60,.14);
}
.dossier-head {
  display: flex; align-items: center; gap: 10px;
  border-bottom: 1px solid rgba(0,0,0,.18); padding-bottom: 8px; margin-bottom: 14px;
}
.dossier-num { font-family: var(--mono); font-size: 11px; letter-spacing: .16em; color: var(--paper-dim); }
.dossier-stamp {
  margin-left: auto; transform: rotate(-6deg);
  font-family: var(--mono); font-size: 11px; letter-spacing: .18em; text-transform: uppercase;
  border: 2px solid currentColor; border-radius: 3px; padding: 2px 7px; opacity: .82;
}
.dossier-stamp:empty { border: 0; }
.dossier-stamp.resuelto { color: #2c7a5a; }
.dossier-stamp.rendido  { color: #a33c36; }
.dossier-stamp.en_curso { color: #8a6c33; }
/* El sello cae de golpe: es el único momento de recompensa del caso. */
.dossier-stamp.sellando { animation: sellar .45s cubic-bezier(.2,1.6,.4,1); }
@keyframes sellar {
  0%   { transform: rotate(-22deg) scale(2.6); opacity: 0; }
  60%  { transform: rotate(-4deg)  scale(.94); opacity: 1; }
  100% { transform: rotate(-6deg)  scale(1); }
}
.dossier h2 { font-family: var(--serif); font-size: 25px; font-weight: 600; letter-spacing: -.01em; }
.dossier-tagline { font-family: var(--serif); font-style: italic; color: var(--paper-dim); margin: 0 0 16px; line-height: 1.45; }
.dossier-body { font-family: var(--serif); font-size: 15.5px; line-height: 1.68; overflow-wrap: anywhere; }
.dossier-body p { margin: 0 0 .85em; }
.dossier-body strong { font-weight: 700; }
.dossier-body code {
  font-family: var(--mono); font-size: .86em; background: rgba(0,0,0,.07);
  padding: 1px 4px; border-radius: 3px;
}
.dossier-body ol, .dossier-body ul { margin: 0 0 .85em; padding-left: 1.3em; }
.dossier-body li { margin-bottom: .3em; }
.dossier-body blockquote {
  margin: 0 0 .85em; padding-left: 12px; border-left: 3px solid rgba(0,0,0,.2);
  font-style: italic; color: var(--paper-dim);
}

.objective {
  margin: 16px 0 12px; padding: 12px 14px;
  background: rgba(0,0,0,.055); border-left: 3px solid var(--amber-dim); border-radius: 0 4px 4px 0;
}
.objective-label {
  font-family: var(--mono); font-size: 10px; letter-spacing: .18em; text-transform: uppercase; color: var(--paper-dim);
}
.objective p { margin: 4px 0 0; font-family: var(--serif); font-size: 16px; font-weight: 600; line-height: 1.45; }
.skills { display: flex; flex-wrap: wrap; gap: 6px; }
.skills span {
  font-family: var(--mono); font-size: 10px; color: var(--paper-dim);
  border: 1px solid rgba(0,0,0,.16); border-radius: 3px; padding: 2px 6px;
}

/* barra de estadísticas del caso */
.statbar {
  display: flex; flex-wrap: wrap; gap: 6px 18px; margin: 12px 2px 0;
  font-family: var(--mono); font-size: 11px; color: var(--ink-faint);
}
.statbar .stat b { color: var(--ink-dim); font-weight: 600; }

/* pistas */
/* `minmax(0, 1fr)` y no el `auto` implícito: un grid item tiene `min-width:
   auto`, así que se estira hasta el contenido más ancho que lleve dentro —una
   línea de SQL sin espacios, por ejemplo— y se sale de su columna. Como la
   consola de al lado está pegada y tiene fondo, el texto desbordado no se ve
   cortado: desaparece debajo. Mismo motivo en el historial y en el manual. */
.hints { margin-top: 14px; display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px; }
.hints > * { min-width: 0; }
.hint {
  background: var(--panel); border: 1px solid var(--line); border-left: 3px solid var(--accent);
  border-radius: 0 var(--r) var(--r) 0; padding: 13px 15px;
  animation: aparece .3s ease;
}
@keyframes aparece { from { opacity: 0; transform: translateY(-6px); } }
.hint h4 {
  margin: 0 0 6px; font-family: var(--mono); font-size: 11px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--accent);
}
.hint-body { font-size: 14px; line-height: 1.62; color: var(--ink); overflow-wrap: anywhere; }
.hint-body p { margin: 0 0 .7em; }
.hint-body p:last-child { margin-bottom: 0; }
.hint-body code, .solution-body code, .patron-nota code {
  font-family: var(--mono); font-size: .88em; background: var(--bg); padding: 1px 4px; border-radius: 3px;
}
/* El SQL de pistas, soluciones y manual ENVUELVE en vez de scrollear: la
   columna del expediente es estrecha y en el móvil lo es más, y una barra de
   scroll horizontal dentro de un bloque de texto que se está leyendo es peor
   que una línea partida. `pre-wrap` conserva la indentación, que es la mitad
   de lo que hace legible una consulta. El `overflow-x` se queda como red por
   si algo no puede partirse. */
.hint-body pre, .solution pre, .patron pre {
  max-width: 100%;
  background: var(--bg); border: 1px solid var(--line); border-radius: 8px;
  padding: 12px; overflow-x: auto; font-family: var(--mono); font-size: 12.5px; line-height: 1.55;
  margin: 0 0 .8em;
  white-space: pre-wrap; overflow-wrap: break-word;
}

/* cuaderno */
.notepad {
  margin-top: 14px; background: var(--panel); border: 1px solid var(--line); border-radius: var(--r);
  overflow: hidden;
}
.notepad summary {
  cursor: pointer; padding: 11px 14px; list-style: none;
  font-family: var(--mono); font-size: 11px; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-dim);
}
.notepad summary::-webkit-details-marker { display: none; }
.notepad summary::before { content: "▸ "; color: var(--ink-faint); }
.notepad[open] summary::before { content: "▾ "; }
.notepad textarea {
  width: 100%; min-height: 130px; resize: vertical; padding: 0 14px 8px;
  background: transparent; border: 0; outline: none; color: var(--ink);
  font-family: var(--serif); font-size: 14.5px; line-height: 1.6;
}
.notepad-state {
  display: block; padding: 0 14px 10px; font-family: var(--mono);
  font-size: 10px; color: var(--ink-faint);
}

/* acusación */
.accuse {
  margin-top: 14px; background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r); padding: 15px;
}
/* El tablero de hechos es un pliego de cargos, no un formulario: el mismo
   papel que el expediente de la izquierda. En vez de repintar cada pieza que
   vive dentro (hechos fijados, prueba, caso cerrado), se cambia la paleta
   local: todo lo de dentro ya lee estas variables. */
.accuse {
  /* Toda la paleta, no media: `--panel-2` se quedó fuera en la primera pasada y
     las etiquetas de las evidencias fijadas salieron con fondo oscuro y letra
     oscura. Si se añade una pieza al pliego, mirar qué variables usa. */
  --panel: #e2d9c4; --panel-2: #d6cbb0; --bg-2: #f1ead9;
  --line: rgba(32,29,24,.22); --line-soft: rgba(32,29,24,.12);
  --ink: var(--paper-ink); --ink-dim: #4a4438; --ink-faint: var(--paper-dim);
  --amber: #7d5f26; --amber-dim: #a58a52; --accent: #7d5f26;
  --jade: #2c7a5a; --red: #a33c36; --red-claro: #a33c36;
  background: var(--paper); color: var(--paper-ink); border: 0;
  background-image: linear-gradient(180deg, rgba(0,0,0,.035), transparent 90px);
  box-shadow: 0 12px 28px rgba(0,0,0,.45), inset 0 0 50px rgba(120,100,60,.13);
  position: relative;
}
/* La grapa: lo que sujeta el pliego a la carpeta. Un trazo, sin imagen. */
.accuse::before {
  content: ""; position: absolute; top: -5px; right: 26px; width: 26px; height: 11px;
  border: 2px solid #8d8778; border-bottom: 0; border-radius: 3px 3px 0 0; opacity: .85;
}
.accuse-head { border-bottom: 1px solid rgba(0,0,0,.18); padding-bottom: 8px; }
/* Los hechos se escriben sobre una línea, como en un impreso, y a máquina. */
.accuse .field label {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .14em; text-transform: uppercase;
  color: #3a342b; margin-bottom: 3px;
}
.accuse .field input {
  background: transparent; border: 0; border-bottom: 1px solid rgba(32,29,24,.35); border-radius: 0;
  padding: 6px 2px 5px; font-family: var(--mono); font-size: 15px; color: var(--paper-ink);
}
.accuse .field input::placeholder { color: rgba(32,29,24,.38); font-style: italic; }
.accuse .field input:focus { border-bottom-color: #7d5f26; box-shadow: 0 1px 0 #7d5f26; }
.accuse .field { position: relative; }
.accuse .field.ok input { border-bottom-color: #2c7a5a; }
.accuse .field.bad input { border-bottom-color: #a33c36; }
/* Hecho establecido: el sello cae sobre la línea, ladeado, como en el expediente.
   Verde si lo estableciste tú; sepia y con la firma de ARCHIVO si lo sacaste
   del expediente, que es una forma de no cerrar el caso del todo solo. */
.accuse .field.revelado[data-sello-archivo]::after,
.accuse .field.ok[data-sello]::after {
  content: attr(data-sello); position: absolute; right: 2px; bottom: 7px; transform: rotate(-5deg);
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .16em; text-transform: uppercase;
  color: #2c7a5a; border: 1.5px solid currentColor; border-radius: 2px; padding: 1px 5px; opacity: .85;
  pointer-events: none; animation: sellar .4s cubic-bezier(.2,1.6,.4,1);
}
.accuse .field.revelado[data-sello-archivo]::after { content: attr(data-sello-archivo); color: #7d5f26; }
/* El botón de cada hecho: discreto hasta que se busca. Ocupa el sitio donde
   luego caerá el sello, así que nunca coinciden. */
.pedir-hecho {
  position: absolute; right: 0; bottom: 5px; width: 22px; height: 22px; padding: 0;
  border: 1px solid rgba(32,29,24,.28); border-radius: 50%; background: transparent;
  font-family: var(--mono); font-size: 12px; line-height: 1; color: rgba(32,29,24,.45);
  cursor: pointer; transition: color .15s ease, border-color .15s ease, background .15s ease;
}
.pedir-hecho:hover, .pedir-hecho:focus-visible { color: #7d5f26; border-color: #7d5f26; background: rgba(125,95,38,.08); }
.field.revelando .pedir-hecho, .field.ok .pedir-hecho { display: none; }
/* Mientras ARCHIVO teclea, el cursor de la máquina parpadea al final de la línea. */
.accuse .field.revelando input { color: var(--paper-ink); border-bottom-color: #7d5f26; }
.accuse .field.revelando::after {
  content: ""; position: absolute; right: 2px; bottom: 8px; width: 9px; height: 2px;
  background: #7d5f26; animation: cursor-archivo .5s steps(2, end) infinite;
}
@keyframes cursor-archivo { 50% { opacity: 0; } }
/* Las evidencias fijadas viven dentro del pliego: sus etiquetas se leen como
   tiras de papel escritas a máquina, no como botones del tema oscuro. */
.accuse .evid .usos button, .accuse .evid .quitar {
  background: var(--panel-2); border-color: rgba(32,29,24,.3); color: #3a342b;
  font-family: var(--mono); letter-spacing: .04em;
}
.accuse .evid .usos button:hover, .accuse .evid .quitar:hover {
  border-color: #7d5f26; color: #201d18; background: #e8dfc8;
}
.accuse .btn-primary { background: #201d18; color: #f1ead9; border-color: #201d18; }
.accuse .btn-primary:hover:not(:disabled) { background: #36312a; }
.accuse .btn-primary:disabled { background: rgba(32,29,24,.28); color: rgba(241,234,217,.8); border-color: transparent; }
html.ahorro .accuse .field.ok[data-sello]::after { animation: none; }
.accuse h3 { font-family: var(--mono); font-size: 11px; letter-spacing: .16em; text-transform: uppercase; color: var(--ink-dim); margin: 0; }
/* El título no se parte: «Tablero de / hechos» en dos líneas con la píldora
   al lado se leía como un descuadre. Si no caben juntos, baja la píldora. */
.accuse-head { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: baseline; gap: 6px 10px; margin-bottom: 12px; }
.accuse-head h3 { white-space: nowrap; }
.hechos-cuenta { font-family: var(--mono); font-size: 11px; color: var(--ink-faint); }
.hechos-cuenta.ok { color: var(--jade); }

/* La prueba: la consulta que sostiene la acusación. Va prellenada con la
   última que corrió, así que en el flujo normal no cuesta ni un clic. */
.prueba { margin: 12px 0 12px; padding-top: 12px; border-top: 1px dashed var(--line); }
.prueba label { display: block; font-family: var(--mono); font-size: 10.5px; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-dim); margin-bottom: 6px; }
.prueba select {
  width: 100%; padding: 9px 10px; border-radius: 8px; font: inherit; font-family: var(--mono); font-size: 12px;
  background: var(--bg-2); border: 1px solid var(--line); color: var(--ink);
}
.prueba select:focus { outline: none; border-color: var(--accent); }
.prueba select:disabled { color: var(--ink-faint); }
.prueba-nota { margin: 6px 0 0; font-size: 12.5px; color: var(--ink-dim); min-height: 1em; }
.prueba.sin .prueba-nota { color: var(--ink-faint); }

/* Evidencias: celdas fijadas de un resultado. Sirven para rellenar los hechos
   sin volver a la consola a copiar. */
.evidencias { margin: 2px 0 12px; display: grid; gap: 6px; }
.evidencias-titulo { font-family: var(--mono); font-size: 10.5px; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-dim); }
.evidencias-vacio { margin: 0; padding: 8px 10px; font-size: 12.5px; line-height: 1.45; color: var(--ink-dim);
  background: var(--bg-2); border: 1px dashed var(--line); border-radius: 8px; }
.evid { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding: 7px 10px; background: var(--bg-2); border: 1px solid var(--line-soft); border-radius: 8px; font-size: 12.5px; }
.evid code { font-family: var(--mono); color: var(--ink); background: none; padding: 0; }
.evid .de { color: var(--ink-faint); font-family: var(--mono); font-size: 10.5px; }
.evid .usos { display: flex; gap: 4px; flex-wrap: wrap; margin-left: auto; }
.evid .usos button, .evid .quitar {
  font: inherit; font-size: 11px; padding: 3px 8px; border-radius: 6px; cursor: pointer;
  background: var(--panel-2); border: 1px solid var(--line); color: var(--ink-dim);
}
.evid .usos button:hover { border-color: var(--amber-dim); color: var(--ink); }
.evid .quitar { padding: 3px 7px; }

/* En la tabla de resultados una celda se puede fijar como evidencia. */
#results td.fijable { cursor: pointer; }
#results td.fijable:hover { outline: 1px solid var(--amber-dim); outline-offset: -1px; }
#results td.seleccionada { outline: 2px solid var(--amber); outline-offset: -2px; background: rgba(216,162,74,.08); }
.evid-bar {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 8px 12px; margin-top: 8px; border: 1px solid var(--amber-dim); border-radius: 8px;
  background: rgba(216,162,74,.06); font-size: 12.5px;
}
.evid-bar code { font-family: var(--mono); background: none; padding: 0; color: var(--ink); }
.evid-bar .btn { padding: 5px 10px; font-size: 12px; }
.field { margin-bottom: 10px; }
.field label { display: block; font-size: 12px; color: var(--ink-dim); margin-bottom: 5px; }
.field input {
  width: 100%; padding: 10px 12px; border-radius: 8px;
  background: var(--bg-2); border: 1px solid var(--line); color: var(--ink);
}
.field input:focus { outline: none; border-color: var(--accent); }
.field.ok input { border-color: var(--jade); }
.field.bad input { border-color: var(--red); animation: tiembla .3s; }
@keyframes tiembla { 25% { transform: translateX(-4px); } 75% { transform: translateX(4px); } }
.verdict { margin: 10px 0 0; font-size: 14px; min-height: 1.2em; }
.verdict.ok { color: var(--jade); }
.verdict.bad { color: var(--red-claro); }
/* El dictamen en contra: un bloque de papel con su rótulo, no una frase suelta
   en rojo. Se lee en tres saltos —qué, por qué, qué hacer— y los hechos que
   faltan salen como etiquetas para contarlos de un vistazo. */
.verdict.bad {
  position: relative; margin-top: 12px; padding: 12px 14px 12px 15px;
  border-left: 3px solid var(--red); background: rgba(163,60,54,.07); border-radius: 0 var(--r) var(--r) 0;
  animation: veredicto-entra .28s ease-out both;
}
.verdict.bad > p { margin: 0; }
.ver-sello {
  display: inline-block; margin-bottom: 7px; padding: 1px 6px; transform: rotate(-2deg);
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .18em; text-transform: uppercase;
  color: var(--red); border: 1.5px solid currentColor; border-radius: 2px; opacity: .9;
}
.ver-titulo { font-family: var(--serif); font-size: 16.5px; line-height: 1.35; color: var(--ink); }
.ver-porque { margin-top: 5px !important; font-size: 13.5px; line-height: 1.55; color: var(--ink-dim); }
.ver-campos { margin-top: 8px !important; display: flex; flex-wrap: wrap; gap: 5px; }
.ver-campo {
  font-family: var(--mono); font-size: 11.5px; padding: 3px 8px; border-radius: 3px;
  background: rgba(163,60,54,.1); border: 1px dashed var(--red); color: var(--red);
}
.ver-hacer {
  margin-top: 9px !important; padding-top: 8px; border-top: 1px dashed var(--line);
  font-family: var(--mono); font-size: 12.5px; line-height: 1.5; color: var(--amber);
}
.ver-hacer::before { content: "→ "; opacity: .7; }
/* El expediente de lo que no se sostuvo: los dictámenes anteriores de ESTE
   caso, plegados. Quien acertó a la primera no ve nada. Deliberadamente sobrio
   —ni rojo ni filete— para que no compita con el veredicto de arriba, que es
   el que hay que leer ahora: esto es archivo, no noticia. */
.fallos { margin-top: 10px; font-size: 13px; }
.fallos > summary {
  cursor: pointer; list-style: none; padding: 5px 0;
  font-family: var(--mono); font-size: 11px; letter-spacing: .12em; text-transform: uppercase;
  color: var(--ink-dim); border-top: 1px dashed var(--line);
}
.fallos > summary::-webkit-details-marker { display: none; }
.fallos > summary::before { content: "▸ "; opacity: .6; }
.fallos[open] > summary::before { content: "▾ "; }
.fallos > summary:hover { color: var(--amber); }
.fallos-lista { margin: 4px 0 0; padding: 0; list-style: none; }
.fallos-lista > li {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 8px;
  padding: 6px 0; border-bottom: 1px dashed var(--line);
}
.fallos-lista > li:last-child { border-bottom: 0; }
.fallo-n {
  flex: 0 0 auto; font-family: var(--mono); font-size: 10.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-dim); opacity: .75;
}
.fallo-que { flex: 1 1 12em; font-family: var(--serif); font-size: 14px; line-height: 1.35; color: var(--ink-dim); }
.fallo-campos { flex: 1 1 100%; display: flex; flex-wrap: wrap; gap: 4px; }
/* Las etiquetas aquí no gritan: mismo dibujo que en el veredicto, sin color. */
.fallo-campos .ver-campo { background: none; border-color: var(--line); color: var(--ink-dim); font-size: 10.5px; }

@keyframes veredicto-entra { from { opacity: 0; transform: translateY(-4px); } }
html.ahorro .verdict.bad { animation: none; }
@media (prefers-reduced-motion: reduce) { .verdict.bad { animation: none; } }

/* Un fallo de la máquina no es un veredicto: ni verde ni rojo. Avisa en ámbar
   y se queda escrito hasta el siguiente intento. */
.verdict.fallo { color: var(--amber); border-left: 3px solid var(--amber-dim); padding-left: 10px; }

/* Tres botones en fila fluida se apilaban a lo ancho de la columna en cuanto
   ésta se estrechaba, y las dos salidas de emergencia acababan pesando lo
   mismo que pedir una pista. Rejilla: la pista ocupa la fila entera, las
   otras dos se reparten la siguiente. */
.danger-zone { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 14px; }
.danger-zone > #btn-hint, .danger-zone > #btn-reset { grid-column: 1 / -1; }
.danger-zone .btn { min-width: 0; }

.btn {
  border-radius: 8px; padding: 10px 16px; cursor: pointer; border: 1px solid transparent;
  font-size: 14px; transition: background .12s, border-color .12s, color .12s, transform .08s;
}
.btn:active { transform: translateY(1px); }
.btn-primary { background: var(--accent); color: #17130a; font-weight: 600; }
.btn-primary:hover { filter: brightness(1.08); }
.btn-ghost { background: transparent; border-color: var(--line); color: var(--ink-dim); }
.btn-ghost:hover { color: var(--ink); border-color: var(--amber-dim); }
.btn-quiet { font-size: 13px; color: var(--ink-faint); }
/* `opacity: .45` dejaba el texto entre 1.6:1 y 2.9:1: ilegible. Un botón
   apagado se reconoce por el color plano y el borde apagado, no por ser
   transparente. */
.btn:disabled { opacity: .7; cursor: not-allowed; color: var(--ink-faint); border-color: var(--line-soft); }
.btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* solución */
.solution {
  margin-top: 16px; background: var(--panel); border: 1px solid var(--jade);
  border-radius: var(--r); padding: 16px; animation: aparece .35s ease;
}
.solution h3 { font-family: var(--mono); font-size: 11px; letter-spacing: .16em; text-transform: uppercase; color: var(--jade); }
.solution-body { font-size: 14.5px; line-height: 1.68; color: var(--ink); overflow-wrap: anywhere; }
.solution-body p { margin: 0 0 .8em; }
.solution-body ul { margin: 0 0 .9em; padding-left: 1.2em; }
.solution-body blockquote {
  margin: 0 0 .9em; padding: 10px 14px; border-left: 3px solid var(--jade);
  background: rgba(70,195,156,.06); border-radius: 0 6px 6px 0;
}
.maestria { margin: 14px 0 16px; padding: 12px 0 4px; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.maestria h4 { margin: 0 0 6px; font-family: var(--mono); font-size: 11px; letter-spacing: .16em; text-transform: uppercase; color: var(--amber); }
.maestria-leyenda { margin: 0 0 10px; font-family: var(--mono); font-size: 11px; color: var(--ink-faint); display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.maestria-muestra { display: inline-block; width: 14px; height: 6px; border-radius: 1px; margin-left: 8px; }
.maestria-muestra:first-child { margin-left: 0; }
.maestria-muestra.mia, .maestria-barra.mia { background: var(--amber); }
.maestria-muestra.casa, .maestria-barra.casa { background: var(--ink-faint); opacity: .55; }
.maestria-fila { display: grid; grid-template-columns: 92px 1fr 84px; gap: 10px; align-items: center; margin: 0 0 8px; }
.maestria-que { font-family: var(--mono); font-size: 12px; color: var(--ink-dim); }
.maestria-barras { display: grid; gap: 3px; }
.maestria-barra { display: block; height: 6px; border-radius: 1px; transform-origin: left; animation: maestria-crece .6s ease both; }
.maestria-cifras { font-family: var(--mono); font-size: 12px; color: var(--ink-faint); text-align: right; font-variant-numeric: tabular-nums; }
.maestria-cifras b { color: var(--ink); font-weight: 400; }
.maestria-menos .maestria-cifras b { color: var(--jade); }
.maestria-juicio { margin: 10px 0 4px; font-family: var(--serif); font-style: italic; font-size: 14.5px; color: var(--ink); }
.maestria-juicio b { font-family: var(--mono); font-style: normal; font-size: 11px; letter-spacing: .12em; color: var(--ink-faint); margin-right: 6px; }
.maestria-nota { margin: 0 0 8px; font-size: 12px; color: var(--ink-faint); }
@keyframes maestria-crece { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@media (prefers-reduced-motion: reduce) { .maestria-barra { animation: none; } }
.epilogue { font-family: var(--serif); font-style: italic; color: var(--ink-dim); border-top: 1px solid var(--line); padding-top: 12px; margin-top: 4px; }

/* En pantalla estrecha los dos extremos se juntaban y «…del testigoSiguiente»
   se leía como una sola palabra. Que envuelvan antes de tocarse. */
.case-nav {
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: 6px 16px; margin-top: 18px;
  font-size: 13px; font-family: var(--mono);
}
.case-nav > * { min-width: 0; }
.case-nav a { color: var(--ink-dim); text-decoration: none; }
.case-nav a:hover { color: var(--accent); }
.nav-locked { color: var(--ink-faint); opacity: .6; }

/* ---------- consola ---------- */
.editor-wrap { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
.editor-head {
  display: flex; align-items: center; gap: 10px; padding: 9px 13px;
  border-bottom: 1px solid var(--line-soft); background: var(--bg-2);
}
.editor-title { font-family: var(--mono); font-size: 10.5px; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-faint); }
.editor-hint { margin-left: auto; font-family: var(--mono); font-size: 10.5px; color: var(--ink-faint); }

/* Resaltado: un <pre> pintado debajo y un <textarea> transparente encima.
   Las dos capas comparten métrica exacta o el cursor se desalinea. */
.editor { position: relative; }
/* CodeMirror vive aquí. Sus colores y tipografía vienen de las variables del
   juego (ver app/src/editor-cm.js); esto sólo le da el marco. */
.editor .cm-editor { border-bottom: 1px solid var(--line-soft); }
.editor .cm-editor.cm-focused { box-shadow: inset 0 -2px 0 var(--amber-dim); }
.tok-op  { color: var(--ink-dim); }
.tok-kw  { color: #7fb2ff; font-weight: 600; }
.tok-fn  { color: #c58cf0; }
.tok-str { color: #93d68a; }
.tok-num { color: #e8b45e; }
.tok-com { color: var(--ink-faint); font-style: italic; }

.tokenbar {
  position: relative; display: flex; flex-wrap: wrap; gap: 6px; padding: 8px 10px;
  border-top: 1px solid var(--line-soft);
  /* Dos filas visibles; el resto, plegado. 2 × (alto del chip 26 px + hueco 6). */
  max-height: calc(8px + 26px * 2 + 6px + 8px); overflow: hidden;
  /* Y hueco reservado a la derecha para el chip «más», que va en absoluto:
     sin esto se echaba encima del último atajo de la segunda fila y lo dejaba
     cortado a la mitad —«LI» por «LIKE»—. La sombra que llevaba no lo tapaba,
     lo emborronaba. */
  padding-right: 88px;
}
.tokenbar.abierta { padding-right: 10px; }
.tokenbar.abierta { max-height: none; }
.tokenbar button {
  flex: 0 0 auto; height: 26px; padding: 0 9px; border-radius: 6px; cursor: pointer;
  font-family: var(--mono); font-size: 11px; letter-spacing: .02em;
  background: var(--panel-2); border: 1px solid var(--line); color: var(--ink-dim);
}
.tokenbar button:hover { border-color: var(--amber-dim); color: var(--ink); }
.tokenbar button:active { background: var(--accent); color: #17130a; }
/* Los comparadores, un poco más anchos y más claros: son los que más se buscan. */
.tokenbar button[title="="], .tokenbar button[title="<"], .tokenbar button[title=">"],
.tokenbar button[title="<="], .tokenbar button[title=">="], .tokenbar button[title="<>"] {
  min-width: 34px; font-size: 13px; color: var(--ink); padding: 0 8px;
}
.tokenbar .tok-mas {
  position: absolute; right: 8px; bottom: 8px; color: var(--amber); border-color: var(--amber-dim);
  background: var(--panel);
}
.tokenbar.abierta .tok-mas { position: static; box-shadow: none; margin-left: auto; }

.editor-actions { display: flex; align-items: center; gap: 8px; padding: 11px 13px; border-top: 1px solid var(--line-soft); flex-wrap: wrap; }
.run-meta { margin-left: auto; font-family: var(--mono); font-size: 11px; color: var(--ink-faint); text-align: right; }

.results { margin-top: 14px; }
.results-empty { color: var(--ink-faint); font-style: italic; font-size: 14px; }
.error {
  background: rgba(210,86,79,.08); border: 1px solid rgba(210,86,79,.4);
  border-radius: var(--r); padding: 13px 15px;
}
.error.vacio { background: transparent; border-color: var(--line); }
.error strong { color: var(--red-claro); display: block; margin-bottom: 5px; font-size: 13px; }
.error.vacio strong { color: var(--amber); }
.error pre { margin: 0; font-family: var(--mono); font-size: 12.5px; white-space: pre-wrap; color: var(--ink); }
.error .fix { margin: 9px 0 0; font-size: 13px; color: var(--amber); }
.error .fix.archivo {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 10px;
  color: var(--ink); padding: 9px 12px; border-left: 3px solid var(--amber-dim);
  background: rgba(216,162,74,.06); border-radius: 0 8px 8px 0;
}
.error .fix.archivo b { font-family: var(--mono); font-size: 10.5px; letter-spacing: .14em; color: var(--amber); }
.error .fix.archivo span { flex: 1 1 24ch; line-height: 1.5; }
.error .fix.archivo .btn { padding: 4px 10px; font-size: 12px; }
/* Con traducción, el error del motor pasa a nota al pie. */
.error.con-lectura .fix.archivo { margin-top: 2px; }
.error.con-lectura .fix.archivo span { font-size: 14px; }
.error.con-lectura pre {
  margin-top: 11px; padding-top: 9px; border-top: 1px dashed var(--line);
  font-size: 11.5px; color: var(--ink-faint);
}

.results-bar {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-family: var(--mono); font-size: 11px; color: var(--ink-faint); padding: 0 2px 8px;
}
.results-bar .btn { padding: 4px 10px; }
.results-bar span:first-child { margin-right: auto; }

/* La tabla se desplaza de lado cuando hay más columnas de las que caben, y
   hasta ahora no lo decía: en el teléfono la columna `hora` quedaba cortada
   en «2» y parecía un dato roto. Dos sombras ancladas a la caja y dos tapas
   ancladas al contenido: la sombra sólo se ve por el lado que queda por
   recorrer. Sin JavaScript y sin barra siempre visible. */
.table-wrap {
  overflow: auto; max-height: 58vh;
  border: 1px solid var(--line); border-radius: var(--r);
  background-color: var(--panel);
  background-image:
    linear-gradient(to right, var(--panel), rgba(0,0,0,0)),
    linear-gradient(to left,  var(--panel), rgba(0,0,0,0)),
    linear-gradient(to right, rgba(0,0,0,.55), rgba(0,0,0,0)),
    linear-gradient(to left,  rgba(0,0,0,.55), rgba(0,0,0,0));
  background-position: 0 0, 100% 0, 0 0, 100% 0;
  background-repeat: no-repeat;
  background-size: 26px 100%, 26px 100%, 15px 100%, 15px 100%;
  background-attachment: local, local, scroll, scroll;
}
table { border-collapse: collapse; width: 100%; font-family: var(--mono); font-size: 12.5px; }
thead th {
  position: sticky; top: 0; z-index: 2; text-align: left; white-space: nowrap;
  background: var(--panel-2); color: var(--accent); font-weight: 600;
  padding: 9px 12px; border-bottom: 1px solid var(--line); cursor: pointer; user-select: none;
}
thead th:hover { background: var(--line-soft); }
thead th.ordenada { color: var(--ink); }
tbody td { padding: 7px 12px; border-bottom: 1px solid var(--line-soft); white-space: nowrap; color: var(--ink); }
tbody tr:hover td { background: rgba(216,162,74,.05); }
td.null { color: var(--ink-faint); font-style: italic; }
td.num { text-align: right; font-variant-numeric: tabular-nums; }

/* historial */
.history {
  margin-top: 14px; background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r); overflow: hidden;
}
.history summary {
  cursor: pointer; padding: 11px 14px; list-style: none;
  font-family: var(--mono); font-size: 11px; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-dim);
}
.history summary::-webkit-details-marker { display: none; }
.history summary::before { content: "▸ "; color: var(--ink-faint); }
.history[open] summary::before { content: "▾ "; }
.history-count { color: var(--ink-faint); letter-spacing: 0; }
#history { padding: 0 12px 12px; display: grid; grid-template-columns: minmax(0, 1fr); gap: 6px; }
#history > * { min-width: 0; }
.hist-item {
  display: flex; flex-direction: column; gap: 3px; align-items: flex-start; text-align: left;
  background: var(--bg-2); border: 1px solid var(--line-soft); border-radius: 7px;
  padding: 8px 10px; cursor: pointer; width: 100%;
}
.hist-item:hover { border-color: var(--amber-dim); }
.hist-item code { font-family: var(--mono); font-size: 11.5px; color: var(--ink); word-break: break-word; }
.hist-item span { font-family: var(--mono); font-size: 10px; color: var(--ink-faint); }
.hist-item.err span { color: var(--red-claro); }

/* ---------- esquema ---------- */
.schema-head { display: flex; flex-direction: column; gap: 8px; margin-bottom: 10px; }
#schema-filter {
  width: 100%; padding: 8px 11px; border-radius: 8px;
  background: var(--panel); border: 1px solid var(--line); color: var(--ink); font-size: 13px;
}
#schema-filter:focus { outline: none; border-color: var(--amber-dim); }
.tbl { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r); margin-bottom: 10px; overflow: hidden; }
.tbl summary { cursor: pointer; padding: 11px 13px; list-style: none; display: flex; align-items: center; gap: 8px; }
.tbl summary::-webkit-details-marker { display: none; }
.tbl summary b { font-family: var(--mono); font-size: 13px; color: var(--accent); font-weight: 600; }
.tbl summary .rows { margin-left: auto; font-family: var(--mono); font-size: 10.5px; color: var(--ink-faint); }
.tbl .tbl-comment { padding: 0 13px 10px; font-size: 12.5px; color: var(--ink-dim); font-style: italic; margin: -4px 0 0; }
.cols { border-top: 1px solid var(--line-soft); padding: 8px 0; }
.col { display: grid; grid-template-columns: 1fr auto; gap: 4px 10px; padding: 6px 13px; }
.col:hover { background: rgba(255,255,255,.02); }
.col .cname { font-family: var(--mono); font-size: 12px; color: var(--ink); cursor: pointer; }
.col .cname:hover { color: var(--accent); }
.col .ctype { font-family: var(--mono); font-size: 10px; color: var(--ink-faint); text-transform: lowercase; }
.col .ccomment { grid-column: 1 / -1; font-size: 11.5px; color: var(--ink-faint); line-height: 1.45; }
.tbl-actions { display: flex; gap: 6px; flex-wrap: wrap; padding: 8px 13px 2px; }
.tbl-actions .btn { padding: 6px 10px; font-size: 12px; }

/* ---------- manual ---------- */
.modal {
  position: fixed; inset: 0; z-index: 200; display: grid; place-items: center;
  background: rgba(5,7,9,.78); backdrop-filter: blur(6px); padding: 20px;
}

/* La confirmación del juego: sustituye al `confirm()` del navegador, que saca
   de la pantalla completa y en un iframe sin `allow-modals` ni aparece. */
.modal-confirmar { z-index: 700; place-items: center; padding: 20px; }
.confirmar-caja {
  width: min(440px, 100%); padding: 22px 22px 18px;
  background: var(--panel); border: 1px solid var(--amber-dim); border-radius: var(--r);
  box-shadow: 0 24px 60px rgba(0,0,0,.6);
}
.confirmar-caja p { margin: 0 0 18px; font-family: var(--serif); font-size: 16px; line-height: 1.5; color: var(--ink); }
.confirmar-botones { display: flex; gap: 10px; justify-content: flex-end; flex-wrap: wrap; }
#confirmar-area {
  width: 100%; min-height: 118px; margin: 0 0 16px; resize: vertical;
  font-family: var(--mono); font-size: 12.5px; line-height: 1.5; color: var(--ink);
  background: var(--bg-2); border: 1px solid var(--line); border-radius: var(--r); padding: 10px;
}
/* Los creditos son 2.700 lineas de avisos de licencia, no un codigo de cuatro
   caracteres para copiar: el mismo cuadro necesita altura o el aviso viaja
   pero no se puede leer. */
#confirmar-area.larga { min-height: min(52dvh, 460px); }
.modal-card {
  background: var(--panel); border: 1px solid var(--line); border-radius: 14px;
  width: min(760px, 100%); max-height: 88dvh; overflow-y: auto; padding: 22px;
  box-shadow: 0 24px 70px rgba(0,0,0,.6);
}
.modal-head { display: flex; align-items: center; gap: 12px; }
.modal-head h2 { font-family: var(--serif); font-weight: 500; font-size: 24px; margin: 0; }
.modal-head .icon-btn { margin-left: auto; }
.modal-intro { color: var(--ink-dim); font-size: 14px; line-height: 1.6; margin: 8px 0 20px; }
.modal-body { display: grid; grid-template-columns: minmax(0, 1fr); gap: 14px; }
.modal-body > * { min-width: 0; }
.patron {
  background: var(--bg-2); border: 1px solid var(--line-soft); border-radius: var(--r);
  border-left: 3px solid var(--accent); padding: 14px 16px;
}
.patron h3 { font-family: var(--serif); font-size: 17px; font-weight: 600; margin: 0 0 4px; }
.patron-cuando { color: var(--ink-dim); font-size: 13px; line-height: 1.55; margin: 0 0 10px; }
.patron-nota { color: var(--ink-dim); font-size: 13px; line-height: 1.6; margin: 0; overflow-wrap: anywhere; }
.patron.cerrado { border-left-color: var(--line); opacity: .5; }
.patron.primero-cerrado { margin-top: 22px; padding-top: 20px; border-top: 1px solid var(--line); }
.patron.cerrado h3 { color: var(--ink-faint); }
.patron.cerrado .patron-cuando { font-style: italic; margin: 0; }

/* ---------- pestañas móviles ---------- */
.tabbar { display: none; }
@media (max-width: 860px) {
  .view { padding: 16px 12px calc(76px + var(--safe-b)); }
  /* `1fr` a secas y los hijos con `min-width:auto` dejaban que el editor de
   CodeMirror fijara el ancho de la columna: en un teléfono de 390 px la
   página entera medía 555 y se desplazaba de lado, con la tabla, los chips y
   los botones cortados por el borde. `minmax(0, 1fr)` + `min-width: 0` es lo
   que obliga a cada panel a caber y a desplazarse por dentro. */
.case-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; }
.case-grid > * { min-width: 0; }
  /* Las columnas se disuelven y cada bloque va a su pestaña. */
  .zona { display: contents; }
  .zona-rotulo { display: none !important; }
  .case-grid [data-tab] { display: none; }
  .case-grid [data-tab].active { display: block; }
  /* …salvo la navegación entre casos: como panel de pestaña se volvía bloque
     y sus dos extremos se pegaban («…del testigoSiguiente»). Sigue en fila. */
  .case-grid [data-tab].case-nav.active { display: flex; }
  .case-grid [data-tab][hidden] { display: none !important; }
  /* El orden de lectura del expediente en una sola columna. */
  .case-grid .dossier { order: 1; } .case-grid .estado { order: 2; } .case-grid .hints { order: 3; }
  .case-grid .notepad { order: 4; } .case-grid .accuse { order: 5; } .case-grid .danger-zone { order: 6; }
  .case-grid .solution { order: 7; } .case-grid .case-nav { order: 8; }
  .case-grid .results { margin-top: 0; }
  .tabbar {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
    display: grid; grid-template-columns: repeat(3, 1fr); gap: 0;
    background: rgba(10,12,15,.94); backdrop-filter: blur(14px);
    border-top: 1px solid var(--line);
    padding-bottom: var(--safe-b);
  }
  .tabbar button {
    background: none; border: 0; color: var(--ink-faint); padding: 14px 4px;
    font-size: 12px; letter-spacing: .06em; text-transform: uppercase; cursor: pointer;
    border-top: 2px solid transparent;
  }
  .tabbar button.active { color: var(--accent); border-top-color: var(--accent); }
  .editor-hl, .editor textarea { min-height: 160px; font-size: 13px; }
  .card-escena { height: 104px; }
  .dossier { padding: 18px 16px 16px; }
  .table-wrap { max-height: 50vh; }
  .hero { margin: 8px 0 28px; }
  .hero-stats { gap: 16px; }
  .modal { padding: 0; }
  .modal-card { max-height: 100dvh; border-radius: 0; border: 0; padding: 18px 16px calc(24px + var(--safe-b)); }
  /* En móvil el título del caso puede ser largo; la barra superior no es sitio
     para leerlo entero: se lee en el propio expediente. */
  .brand-text strong {
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    max-width: 44vw; font-size: 15px;
  }
  .score { display: none; }
}

/* ---------- toast ---------- */
.toast {
  position: fixed; left: 50%; transform: translateX(-50%);
  /* Por encima de la celebración (500): un aviso disparado durante ella era
     invisible y se perdía sin que nadie lo viera. */
  bottom: calc(88px + var(--safe-b)); z-index: 600;
  background: var(--panel-2); border: 1px solid var(--amber-dim); color: var(--ink);
  padding: 11px 18px; border-radius: 999px; font-size: 13.5px;
  box-shadow: 0 8px 28px rgba(0,0,0,.5);
  animation: aparece .2s ease;
}

/* En escritorio la consola y el esquema se quedan pegados: el expediente es
   largo y no tiene sentido perder de vista la herramienta mientras se lee. */
@media (min-width: 861px) {
  .pane-console, .pane-schema {
    position: sticky; top: 70px;
    max-height: calc(100dvh - 86px);
    overflow-y: auto;
    scrollbar-width: thin;
  }
  .pane-console::-webkit-scrollbar, .pane-schema::-webkit-scrollbar { width: 8px; }
  .pane-console::-webkit-scrollbar-thumb, .pane-schema::-webkit-scrollbar-thumb {
    background: var(--line); border-radius: 4px;
  }
}

/* Temporada 2: la paleta se vuelve verde pantalla. Temporada 3: violeta de
   sótano de archivo. */
body[data-season="t2_mercados"] { --accent: var(--jade); --amber: var(--jade); --amber-dim: #2e7d64; }
body[data-season="t3_forense"]  { --accent: var(--violet); --amber: var(--violet); --amber-dim: #5f4b87; }

/* ---------- oferta de quitar anuncios (sólo en la app) ---------- */
.compra { margin: 8px 0 40px; }
.compra-card {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  background: linear-gradient(168deg, var(--panel-2), var(--panel));
  border: 1px solid var(--amber-dim); border-radius: var(--r); padding: 16px 18px;
}
.compra-card strong { font-family: var(--serif); font-size: 17px; font-weight: 600; }
.compra-card p { margin: 4px 0 0; color: var(--ink-dim); font-size: 13.5px; line-height: 1.5; }
.compra-card .btn { margin-left: auto; white-space: nowrap; }

/* ---------- comportamiento táctil ----------
   En el navegador de escritorio da igual, pero dentro de la app un toque sobre
   una tarjeta abría el menú de selección de texto ("Copiar / Compartir / Leer
   en voz alta") en vez de abrir el expediente. Una app no se lee como una
   página: el texto no se selecciona salvo donde de verdad quieras copiarlo. */
body {
  -webkit-user-select: none; user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
}
/* Y donde sí interesa copiar: la consola, lo que devuelve, el SQL de las
   soluciones y las notas propias. */
#sql, .table-wrap, .results, .solution pre, .hint-body pre, .patron pre,
#notas, .dossier-body, .hint-body, .solution-body, .field input, #schema-filter {
  -webkit-user-select: text; user-select: text;
}
/* Sin el retardo de 300 ms que el navegador reserva por si viene un doble
   toque: en una app, un botón responde al instante o parece rota. */
button, .card, .tabbar button, summary, [data-insert], [data-peek] {
  touch-action: manipulation;
}

/* ================= ESCENAS DE LOS CASOS =================
   Arte vectorial animado con CSS. Todo lo que se mueve aquí usa `transform` y
   `opacity`, que el compositor resuelve sin repintar: en un WebView de móvil
   cualquier otra propiedad animada se nota en el desplazamiento. */

.escena-marco {
  position: relative; overflow: hidden;
  border-radius: 4px 4px 0 0;
  margin: -22px -22px 16px;
  height: 148px;
  background: var(--bg);
}
.escena { display: block; width: 100%; height: 100%; }
/* El papel del expediente empieza justo debajo: un degradado funde la escena
   con él para que no parezca una estampa pegada encima. */
.escena-marco::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 42px;
  background: linear-gradient(transparent, var(--paper));
}

@keyframes esc-flotar { 50% { transform: translateY(-4px); } }
@keyframes esc-latir { 0%, 100% { opacity: .28; } 50% { opacity: .9; } }
@keyframes esc-girar { to { transform: rotate(360deg); } }
@keyframes esc-barrer { 0% { transform: translateY(0); opacity: 0; }
                        12% { opacity: 1; } 88% { opacity: 1; }
                        100% { transform: translateY(78px); opacity: 0; } }
@keyframes esc-temblar { 25% { transform: rotate(-7deg); } 75% { transform: rotate(7deg); } }
@keyframes esc-subir { 0% { transform: translateY(0); opacity: 0; }
                       30% { opacity: .9; } 100% { transform: translateY(-26px); opacity: 0; } }
@keyframes esc-deslizar { to { stroke-dashoffset: -32; } }
@keyframes esc-caer { 0%, 62% { transform: translateY(-16px); }
                      74% { transform: translateY(0); } 100% { transform: translateY(-16px); } }
@keyframes esc-entrar { from { opacity: 0; transform: translateY(8px); } }
@keyframes esc-apagarse { 0%, 100% { opacity: .38; } 50% { opacity: .08; } }
@keyframes esc-inclinar { 0%, 100% { transform: rotate(-7deg); } 50% { transform: rotate(4deg); } }

.c-motivo .m-flotar { animation: esc-flotar 6s ease-in-out infinite; }
.m-carpeta { animation: esc-flotar 4.2s ease-in-out infinite; }
.m-escaneo { animation: esc-barrer 3.4s ease-in-out infinite; }
.m-timbre { animation: esc-temblar .28s ease-in-out 6; transform-origin: 200px 93px; }
.m-ondas { animation: esc-latir 1.6s ease-in-out infinite; }
.m-burbuja { animation: esc-subir 3.2s ease-in-out infinite; }
.m-burbuja.m-b2 { animation-delay: 1.1s; }
.m-aguja { animation: esc-girar 6s linear infinite; }
.m-luzpuerta { animation: esc-latir 5s ease-in-out infinite; }
.m-vagon { animation: esc-flotar 3s ease-in-out infinite; }
.m-haz { animation: esc-latir 7s ease-in-out infinite; transform-origin: 200px 71px; }
.m-haz2 { animation-delay: 3.5s; }
.m-vela { animation: esc-entrar .5s ease-out both; }
.m-gota { animation: esc-flotar 2.4s ease-in-out infinite; }
.m-reflejo { animation: esc-latir 3.6s ease-in-out infinite; }
.m-flecha { stroke-dasharray: 4 6; animation: esc-deslizar 1.6s linear infinite; }
.m-flecha.m-f2 { animation-direction: reverse; }
.m-hueco { animation: esc-latir 2.2s ease-in-out infinite; }
.m-congelada { stroke-dasharray: 5 4; animation: esc-deslizar 3s linear infinite; }
.m-pulso { animation: esc-latir 1.4s ease-in-out infinite; }
.m-adelanto { animation: esc-flotar 3.4s ease-in-out infinite; }
.m-cancel { animation: esc-latir 1.8s steps(1) infinite; }
.m-pared { animation: esc-apagarse 3.2s ease-in-out infinite; }
.m-barrera { transform-origin: 222px 108px; animation: esc-inclinar 4.5s ease-in-out infinite; }
.m-moneda { animation: esc-subir 2.8s ease-in-out infinite; }
.m-flujo { animation: esc-deslizar 1.4s linear infinite; }
.m-hoja { animation: esc-entrar .5s ease-out both; }
.m-x4 { animation: esc-latir 2.4s ease-in-out infinite; }
.m-copia { animation: esc-flotar 5s ease-in-out infinite; }
.m-sellar { animation: esc-caer 3.2s ease-in-out infinite; }
.m-balancear { animation: esc-inclinar 5s ease-in-out infinite; }
.m-hora-repetida { transform-origin: 200px 96px; animation: esc-girar 8s steps(12) infinite; }
.m-borrarse { animation: esc-apagarse 4s ease-in-out infinite; }

/* ---------- introducción: una viñeta por párrafo ----------
   La primera versión era un texto que crecía sobre una imagen fija y leía como
   un libro. Ahora cada párrafo trae su propio plano a pantalla completa y el
   anterior se funde por debajo: el montaje es lo que dramatiza, no la
   tipografía. */
.intro {
  position: fixed; inset: 0; z-index: 400; overflow: hidden;
  background: var(--bg); cursor: pointer;
  animation: intro-abrir .5s ease both;
}
/* Cerrar no es apagar la luz: es entrar. La capa empuja hacia dentro y se
   desenfoca mientras se va, de modo que el expediente que aparece debajo se
   lee como el sitio al que acaba de llegar la cámara y no como otra pantalla.
   Medio segundo: lo justo para que el gesto se complete sin hacer esperar a
   quien pulsó «saltar». */
.intro.cerrando { animation: intro-cerrar .5s cubic-bezier(.4,0,.25,1) both; }
@keyframes intro-abrir  { from { opacity: 0; } }
@keyframes intro-cerrar {
  from { opacity: 1; transform: scale(1);    filter: blur(0); }
  to   { opacity: 0; transform: scale(1.14); filter: blur(9px); }
}

/* El lienzo ocupa toda la pantalla; las capas se apilan y se funden. */
.intro-lienzo { position: absolute; inset: 0; }
.plano-capa {
  position: absolute; inset: 0;
  animation: plano-entrar .9s ease both;
}
@keyframes plano-entrar { from { opacity: 0; } }
.plano { width: 100%; height: 100%; display: block; }

/* ---------- movimiento de cámara ----------
   Antes había cuatro recorridos que se turnaban por número de orden y los
   cuatro eran el mismo gesto: un zoom de quince segundos. Con viñetas de cinco
   segundos sólo se veía el primer tercio de la curva, así que las cuatro
   «cámaras» se leían como una sola repetida. Ahora hay seis gestos distintos
   —abrir, cerrar, panear a un lado y a otro, bajar, subir, quedarse quieto— y
   los elige `camara.js` por el TAMAÑO del plano: a un plano general se le abre
   y a un primer plano se le empuja.

   Nueve segundos, no quince: el movimiento tiene que completar su lectura
   dentro de la viñeta. Y la curva termina en un tramo casi plano
   (cubic-bezier con el último control alto) para que la cámara se pose en vez
   de frenar en seco cuando la viñeta se alarga. */
@keyframes cam-empujar   { from { transform: scale(1.02) translate(0, 0); }      to { transform: scale(1.17) translate(-1%, -1%); } }
@keyframes cam-retirar   { from { transform: scale(1.20) translate(1%, 1%); }    to { transform: scale(1.03) translate(0, 0); } }
@keyframes cam-barrer-der{ from { transform: scale(1.13) translate(-3.5%, 0); }  to { transform: scale(1.09) translate(3.5%, -.5%); } }
@keyframes cam-barrer-izq{ from { transform: scale(1.13) translate(3.5%, -.5%); } to { transform: scale(1.09) translate(-3.5%, 0); } }
@keyframes cam-caer      { from { transform: scale(1.12) translate(0, -3.5%); }  to { transform: scale(1.08) translate(0, 2.5%); } }
@keyframes cam-alzar     { from { transform: scale(1.12) translate(0, 3%); }     to { transform: scale(1.08) translate(0, -2.5%); } }
/* «Deriva» es casi un plano fijo: se reserva para la frase que tiene que
   aterrizar. Una cámara que se para es un signo de puntuación. */
@keyframes cam-deriva    { from { transform: scale(1.06) translate(-.6%, .4%); } to { transform: scale(1.09) translate(.6%, -.4%); } }
/* La última viñeta entrega al expediente: empujón corto y decidido. */
@keyframes cam-empujar-fuerte { from { transform: scale(1.01); } to { transform: scale(1.22) translate(0, -1.5%); } }

/* La cámara mueve el ENCUADRE, no la imagen: dentro del encuadre van el cuadro
   (el JPEG) y el celuloide (el SVG vivo que va encima), y los dos tienen que
   viajar juntos. Si se animaran por separado, la aguja se saldría de la esfera
   en cuanto la cámara empujase. */
.encuadre {
  position: absolute; inset: 0; will-change: transform;
  --cam-dur: 9s;
  animation-duration: var(--cam-dur);
  animation-timing-function: cubic-bezier(.16, .62, .24, 1);
  animation-fill-mode: both;
}
.encuadre.cam-empujar        { animation-name: cam-empujar; }
.encuadre.cam-retirar        { animation-name: cam-retirar; }
.encuadre.cam-barrer-der     { animation-name: cam-barrer-der; }
.encuadre.cam-barrer-izq     { animation-name: cam-barrer-izq; }
.encuadre.cam-caer           { animation-name: cam-caer; }
.encuadre.cam-alzar          { animation-name: cam-alzar; }
.encuadre.cam-deriva         { animation-name: cam-deriva; --cam-dur: 14s; }
.encuadre.cam-empujar-fuerte { animation-name: cam-empujar-fuerte; --cam-dur: 5.5s;
                               animation-timing-function: cubic-bezier(.3, 0, .2, 1); }

/* El celuloide. Mismo viewBox y mismo `slice` que el cuadro, en una caja del
   mismo tamaño: las dos capas hacen la misma cuenta y caen píxel sobre píxel.
   Entra con el cuadro, no antes, o durante medio segundo se verían cuatro
   luces flotando sobre el plano anterior. */
.cel {
  position: absolute; inset: 0; width: 100%; height: 100%;
  pointer-events: none; opacity: 0; transition: opacity .6s ease;
  /* Capa propia, a propósito.
     El celuloide NO es gratis, y conviene decirlo con precisión: en SVG sólo
     `transform` y `opacity` sobre un elemento promovido van por el compositor.
     `fill-opacity` (las ventanas) y `stroke-dashoffset` (los flujos, el
     gráfico) obligan a REPINTAR el elemento. Son elementos diminutos, pero si
     comparten capa con el cuadro, cada repintado ensucia también el rectángulo
     del JPEG que hay debajo y obliga a re-rasterizar esa zona de la imagen.
     Aislarlo cuesta una textura del tamaño del encuadre y ahorra exactamente
     eso. Por eso la mayoría de las animaciones de aquí abajo van con `steps`:
     una ventana que se apaga en escalones repinta tres veces por ciclo, no
     sesenta veces por segundo. */
  will-change: transform;
  contain: paint;
}
/* `listo` lo pone quien monta la escena, sobre el contenedor del celuloide:
   el encuadre en la introducción, `.titulo-escena` en la portada. */
.listo > .cel { opacity: 1; }


/* ---------- el montaje ----------
   Tres formas de pasar de una viñeta a otra, elegidas por `camara.js` según
   quién hable. Un fundido para todo era lo que dejaba la intro sin ritmo: el
   corte es la puntuación del cine y aquí no existía. */
.plano-capa.corte  { animation-duration: .09s; }
.plano-capa.corte .pintado { transition-duration: .09s; }
.plano-capa.golpe  { animation-duration: .34s; }
.plano-capa.golpe .pintado { transition-duration: .34s; }

/* El destello de un fotograma que acompaña al corte seco. Da el golpe de
   relámpago sin tocar el plano: es una capa de luz que aparece y se va. */
.intro-destello {
  position: absolute; inset: 0; pointer-events: none; opacity: 0; z-index: 3;
  background: radial-gradient(120% 90% at 50% 40%, rgba(226,177,90,.30), rgba(190,215,255,.10) 55%, transparent 75%);
}
.intro-destello.dispara { animation: destello .22s ease-out both; }
@keyframes destello { 0% { opacity: .85; } 100% { opacity: 0; } }

/* ---------- atmósfera viva ----------
   El plano es un JPEG: la lluvia, la lámpara y el polvo que trae pintados
   están congelados. Estas capas van por encima y sólo mueven transformación y
   opacidad, así que cuestan lo que cuesta componer, no repintar. Se encienden
   una a una según el plano (ver `clima()` en camara.js). */
.intro-clima {
  position: absolute; inset: 0; pointer-events: none; z-index: 2; overflow: hidden;
  --lx: 50%; --ly: 20%;
  /* El polvo y el haz toman el color de la luz de la temporada, no un ámbar
     fijo: en La Mesa la luz es verde de monitor y en Forense es violeta de
     laboratorio, y motas cálidas flotando ahí dentro se leen como un filtro
     pegado encima en vez de como el aire de la sala. */
  --mota: 255, 242, 214;
  --halo: rgba(226,177,90,.16);
}
body[data-season="t2_mercados"] .intro-clima { --mota: 214, 255, 238; --halo: rgba(70,195,156,.15); }
body[data-season="t3_forense"]  .intro-clima { --mota: 232, 224, 255; --halo: rgba(154,127,208,.16); }
.intro-clima > div { position: absolute; inset: 0; opacity: 0; transition: opacity 1.1s ease; }
/* Media opacidad: debajo ya hay lluvia pintada y en el mismo ángulo. Lo que
   hace falta no es más agua, es que el agua que ya está se mueva; si la capa
   viva pesa igual que la pintada se ve la rejilla y se pierde el cuadro. */
.intro-clima.lluvia   .clima-lluvia { opacity: .55; }
.intro-clima.polvo    .clima-polvo  { opacity: 1; }
.intro-clima.polvo    .clima-haz    { opacity: 1; }
.intro-clima.parpadeo .clima-haz    { opacity: 1; }

/* Lluvia: el mismo truco que la lluvia de la página —dos rejillas de rayas que
   se trasladan un periodo exacto— pero encerrada en el plano y algo más suave,
   porque debajo ya hay lluvia pintada y dos aguaceros no caben. */
.clima-lluvia::before, .clima-lluvia::after {
  content: ""; position: absolute; left: -14%; right: -14%; top: -760px; bottom: -760px;
  background-image: repeating-linear-gradient(104deg, transparent 0 24px, rgba(196,218,255,.26) 24px 25px, transparent 25px 50px);
  background-size: 480px 480px;
  animation: clima-cae-a 1.25s linear infinite; will-change: transform;
}
.clima-lluvia::after {
  background-image: repeating-linear-gradient(99deg, transparent 0 40px, rgba(196,218,255,.15) 40px 41px, transparent 41px 78px);
  background-size: 720px 720px;
  animation: clima-cae-b 1.9s linear infinite;
}
@keyframes clima-cae-a { to { transform: translate3d(-118px, 480px, 0); } }
@keyframes clima-cae-b { to { transform: translate3d(-170px, 720px, 0); } }

/* Polvo en el haz: dos rejillas de puntos que suben muy despacio. Es lo que
   convierte un interior pintado en un interior habitado —el aire se mueve— y
   es la razón por la que un plano de un objeto bajo un foco ya no se lee como
   una ilustración quieta. */
.clima-polvo::before, .clima-polvo::after {
  content: ""; position: absolute; left: 0; right: 0; top: -60%; bottom: -60%;
  background-image:
    radial-gradient(2.2px 2.2px at 18% 12%, rgba(var(--mota),.78), transparent 62%),
    radial-gradient(1.7px 1.7px at 62% 34%, rgba(var(--mota),.60), transparent 62%),
    radial-gradient(2.6px 2.6px at 84% 66%, rgba(var(--mota),.46), transparent 62%),
    radial-gradient(1.6px 1.6px at 37% 78%, rgba(var(--mota),.66), transparent 62%),
    radial-gradient(1.4px 1.4px at 8% 58%, rgba(var(--mota),.50), transparent 62%),
    radial-gradient(2.0px 2.0px at 72% 88%, rgba(var(--mota),.40), transparent 62%);
  background-size: 240px 240px;
  /* El polvo sólo se ve donde da la luz: fuera del cono, nada. */
  -webkit-mask-image: radial-gradient(60% 55% at var(--lx) var(--ly), #000 0%, rgba(0,0,0,.45) 45%, transparent 78%);
          mask-image: radial-gradient(60% 55% at var(--lx) var(--ly), #000 0%, rgba(0,0,0,.45) 45%, transparent 78%);
  animation: polvo-sube 26s linear infinite; will-change: transform;
}
.clima-polvo::after {
  background-size: 400px 400px;
  animation: polvo-sube 41s linear infinite reverse;
  opacity: .7;
}
@keyframes polvo-sube { to { transform: translate3d(22px, -260px, 0); } }

/* El haz: la lámpara respira. Irregular a propósito —tres pausas desiguales—
   porque un parpadeo de seno perfecto se lee como un efecto y no como una
   bombilla. */
.clima-haz {
  background: radial-gradient(46% 40% at var(--lx) var(--ly), var(--halo), transparent 70%);
  animation: haz-respira 7.3s ease-in-out infinite;
  mix-blend-mode: screen;
}
@keyframes haz-respira {
  0%, 100% { opacity: .55; }
  17%      { opacity: .95; }
  23%      { opacity: .62; }
  48%      { opacity: 1; }
  71%      { opacity: .48; }
}
/* En las pantallas no respira: parpadea, que es lo que hace un monitor. */
.intro-clima.parpadeo .clima-haz {
  background: radial-gradient(52% 44% at var(--lx) var(--ly), rgba(127,178,255,.20), transparent 72%);
  animation: haz-parpadea 3.1s steps(1, end) infinite;
}
@keyframes haz-parpadea {
  0%, 44%  { opacity: .9; }
  46%      { opacity: .45; }
  48%, 88% { opacity: .85; }
  90%      { opacity: .55; }
  92%      { opacity: .9; }
}

/* Cartel de apertura, centrado sobre el primer plano. Se retira en cuanto
   empieza el relato. */
.intro-titulo {
  position: absolute; inset: 0; display: grid; align-content: center; justify-items: center;
  text-align: center; padding: 0 28px; z-index: 4;
  background: radial-gradient(closest-side, rgba(10,12,15,.72), rgba(10,12,15,.35) 70%, transparent);
  transition: opacity .6s ease, transform .7s cubic-bezier(.4,0,.3,1), filter .6s ease;
}
/* El cartel no se va: se desenfoca y se aleja, en la misma dirección en que la
   cámara acaba de empezar a moverse. Que el rótulo salga por donde entra el
   plano es lo que hace que el corte al relato no se note. */
.intro.en-relato .intro-titulo {
  opacity: 0; transform: translateY(-22px) scale(1.04); filter: blur(7px);
  pointer-events: none;
}

.intro-num {
  font-family: var(--mono); font-size: 11px; letter-spacing: .2em; color: var(--accent);
  margin: 0 0 14px; display: inline-block; overflow: hidden; white-space: nowrap;
  border-right: 2px solid var(--accent);
  animation: intro-teclear 1.1s steps(30, end) .3s both, intro-cursor .7s step-end 4;
}
@keyframes intro-teclear { from { width: 0; } to { width: 100%; } }
@keyframes intro-cursor { 50% { border-color: transparent; } }
/* El título no sube: se ENFOCA. Entra desenfocado y un punto más grande, como
   un rótulo de crédito que el proyector acaba de encontrar, y se posa. Subir
   desde abajo era el mismo gesto que usaban el subtítulo, la viñeta y media
   interfaz: tres elementos seguidos con la misma animación es lo que hace que
   una intro parezca una plantilla. */
.intro-titulo h2 {
  font-family: var(--serif); font-size: clamp(30px, 8vw, 54px); font-weight: 500;
  letter-spacing: -.02em; margin: 0 0 10px; text-shadow: 0 4px 26px rgba(0,0,0,.8);
  animation: intro-enfocar 1s cubic-bezier(.2,.75,.25,1) .85s both;
}
@keyframes intro-enfocar {
  from { opacity: 0; filter: blur(11px); transform: scale(1.06); letter-spacing: .06em; }
  60%  { opacity: 1; }
  to   { opacity: 1; filter: blur(0);    transform: scale(1);    letter-spacing: -.02em; }
}
/* El subtítulo llega detrás de un filete que se dibuja de izquierda a derecha:
   otro gesto, no el mismo con retardo. */
.intro-tagline {
  position: relative;
  font-family: var(--serif); font-style: italic; color: var(--ink-dim);
  font-size: clamp(14px, 3.6vw, 18px); margin: 0; padding-top: 12px;
  text-shadow: 0 2px 14px rgba(0,0,0,.9);
  animation: intro-velar .8s ease-out 1.7s both;
}
.intro-tagline::before {
  content: ""; position: absolute; top: 0; left: 50%; width: 92px; height: 1px;
  background: var(--accent); opacity: .6;
  transform: translateX(-50%) scaleX(0); transform-origin: left center;
  animation: intro-filete .6s cubic-bezier(.2,.8,.3,1) 1.5s both;
}
@keyframes intro-velar  { from { opacity: 0; } }
@keyframes intro-filete { to { transform: translateX(-50%) scaleX(1); } }
@keyframes intro-subir  { from { opacity: 0; transform: translateY(16px); } }

/* El pie: la viñeta de texto y los controles, sobre un velo que garantiza que
   el texto se lea encima de cualquier plano. */
.intro-pie {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 5;
  padding: 60px 20px calc(14px + var(--safe-b));
  background: linear-gradient(transparent, rgba(8,10,13,.86) 38%, rgba(8,10,13,.97));
}
.intro-viñeta {
  width: min(660px, 100%); margin: 0 auto 14px;
  animation: vineta-entrar .45s cubic-bezier(.2,.8,.3,1) both;
}
@keyframes vineta-entrar { from { opacity: 0; transform: translateY(12px); } }
/* Una voz no aparece igual que la narración: entra de lado, desde su propio
   filete de color, como una réplica en un guion. La narración es el papel; la
   voz es alguien que interrumpe. */
.intro-viñeta.con-voz { animation-name: vineta-voz; animation-duration: .42s; }
@keyframes vineta-voz { from { opacity: 0; transform: translateX(-14px); } }
.intro-viñeta:empty { display: none; }

/* ---------- el texto se dice, no aparece ----------
   Cada palabra entra con dieciocho milisegundos de retraso sobre la anterior.
   No es un efecto de máquina de escribir —eso obliga a esperar y compite con
   la narración—: la frase está completa en menos de medio segundo, pero el
   ojo percibe que ALGUIEN la está diciendo. El retardo lo pone el JS en
   `--i` y el tope de la cascada lo fija `--paso`, para que un párrafo largo no
   tarde más que uno corto. */
.v-texto .pal {
  display: inline-block;
  animation: palabra-entra .34s ease-out both;
  animation-delay: calc(var(--i, 0) * var(--paso, 18ms));
}
@keyframes palabra-entra { from { opacity: 0; transform: translateY(.22em); filter: blur(2px); } }

.v-texto {
  font-family: var(--serif); font-size: clamp(16px, 4.4vw, 21px); line-height: 1.55;
  color: var(--ink); margin: 0; text-shadow: 0 2px 12px rgba(0,0,0,.7);
}
.v-nombre {
  display: block; font-family: var(--mono); font-size: 11px; letter-spacing: .18em;
  text-transform: uppercase; color: var(--voz, var(--accent)); margin-bottom: 6px;
  transform-origin: left center;
  animation: voz-sello .42s cubic-bezier(.2,1.5,.4,1) both;
}
/* El rótulo de quien habla es una pestaña de archivador (ver «pestañas, no
   barras»), así que no se funde: se SELLA. Llega un punto grande y se asienta,
   que es lo que hace un tampón contra el papel. Es el gesto que anuncia el
   cambio de voz antes de que se lea el nombre. */
@keyframes voz-sello { from { opacity: 0; transform: scale(1.5) rotate(-2.5deg); } }
.intro-viñeta.con-voz {
  border-left: 2px solid var(--voz, var(--ink-faint)); padding-left: 16px;
}
.intro-viñeta.con-voz .v-texto {
  font-style: italic; color: var(--ink-dim); font-size: clamp(15px, 4.1vw, 19px);
}
.intro-viñeta[data-voz="pericial"]     { --voz: #7fb2ff; }
.intro-viñeta[data-voz="centralita"] { --voz: #e2705a; }
.intro-viñeta[data-voz="archivo"]    { --voz: #d8a24a; }
.intro-viñeta[data-voz="internos"]   { --voz: #9a7fd0; }
.intro-viñeta[data-voz="instruccion"]     { --voz: #46c39c; }
.intro-viñeta[data-voz="guardia"]     { --voz: #8b96a5; }
.intro-viñeta[data-voz="fiscalia"]   { --voz: #c9a227; }

.intro-pasos {
  display: flex; justify-content: center; gap: 5px;
  width: min(660px, 100%); margin: 0 auto 12px;
}
.intro-pasos i {
  flex: 0 1 16px; min-width: 5px; height: 2px; border-radius: 1px;
  background: var(--ink-faint); opacity: .28;
  transition: opacity .3s ease, background-color .3s ease, flex-basis .45s cubic-bezier(.2,.8,.3,1);
}
.intro-pasos i.vista { opacity: .55; background: var(--accent); }
/* La viñeta en la que estás es más larga, no sólo más clara: en una fila de
   guiones idénticos «dónde voy» se resuelve contando, y contar saca de la
   historia. */
.intro-pasos i.aqui { opacity: 1; flex-basis: 30px; }
.intro-pasos:empty { display: none; }
.intro-controles {
  display: flex; align-items: center; gap: 14px;
  width: min(660px, 100%); margin: 0 auto;
}
.intro-avanzar {
  flex: 1; text-align: center; margin: 0;
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--ink-faint);
  animation: intro-latir 2.4s ease-in-out infinite both;
}
@keyframes intro-latir { 0%, 100% { opacity: .35; } 50% { opacity: .85; } }

/* Volver a ver la introducción. Va justo debajo de la ilustración, no al final
   del expediente: quien abrió el caso con una versión anterior no tiene otra
   forma de enterarse de que existe. */
.dossier-intro {
  display: block; width: 100%; margin: 0 0 14px;
  background: transparent; border: 1px solid rgba(0,0,0,.16);
  color: var(--paper-dim); font-size: 13px;
  font-family: var(--mono); letter-spacing: .04em;
}
.dossier-intro:hover { color: var(--paper-ink); border-color: rgba(0,0,0,.4); }
/* Sin ver todavía: se señala, pero sin gritar. */
.dossier-intro.sin-ver {
  color: #7a5c1f; border-color: rgba(122,92,31,.5);
  background: rgba(216,162,74,.10);
}

/* ---------- lo que se mueve dentro del plano ----------
 *
 * Estas clases ya existían y llevaban meses sin ejecutarse: el elemento que
 * las lleva acababa cocido dentro del JPEG. Ahora `planos.js` los marca con
 * `vivo()`, `celuloide.js` los saca del cuadro y aquí se animan de verdad.
 *
 * Todo lo de abajo es `transform`, `opacity`, `fill-opacity` o
 * `stroke-dashoffset`: nada que obligue a re-pintar la escena. Y ninguna toca
 * el atributo `opacity` del dibujo —se usa `fill-opacity`, que MULTIPLICA— para
 * no aplanar de un golpe el trabajo de quien decidió que esa ventana estaba al
 * 30% y aquella al 80%. */

/* El foco: la luz respira, con tres pausas desiguales. Un parpadeo senoidal
   perfecto se lee como un efecto; una bombilla real no tiene ritmo. */
.p-foco { animation: foco-respira 6.7s ease-in-out infinite; }
@keyframes foco-respira {
  0%, 100% { opacity: .82; }
  19%      { opacity: 1; }
  26%      { opacity: .74; }
  52%      { opacity: .97; }
  77%      { opacity: .68; }
}

/* Las ventanas de la ciudad. Casi siempre encendidas; de vez en cuando una se
   apaga un segundo. El desfase lo dan `nth-child` y `--t`: sin él las
   cuatrocientas ventanas parpadearían a la vez y la ciudad parecería un
   letrero, no una ciudad. */
.p-luces rect, .p-ventana {
  animation: ventana-vela var(--d, 9s) steps(1, end) infinite;
  animation-delay: calc(var(--t, 0s) * -1);
}
@keyframes ventana-vela {
  0%, 89%   { fill-opacity: 1; }
  90%, 95%  { fill-opacity: .08; }
  96%, 100% { fill-opacity: 1; }
}
/* Doce cubos, cada uno con su periodo y su desfase, y un solo módulo para que
   cada ventana caiga en exactamente una regla. Con cuatro cubos las ventanas
   de un mismo cubo se apagaban A LA VEZ —cinco o seis de golpe— y eso no se
   lee como una ciudad: se lee como un letrero. Los periodos no son múltiplos
   entre sí, así que el patrón tarda minutos en repetirse. */
.p-luces rect:nth-child(12n+1)  { --d: 11s;   --t: 1.7s; }
.p-luces rect:nth-child(12n+2)  { --d: 7.5s;  --t: 4.2s; }
.p-luces rect:nth-child(12n+3)  { --d: 13s;   --t: 8.1s; }
.p-luces rect:nth-child(12n+4)  { --d: 9.5s;  --t: 2.6s; }
.p-luces rect:nth-child(12n+5)  { --d: 17s;   --t: 6.4s; }
.p-luces rect:nth-child(12n+6)  { --d: 6.2s;  --t: .9s; }
.p-luces rect:nth-child(12n+7)  { --d: 14.5s; --t: 11.3s; }
.p-luces rect:nth-child(12n+8)  { --d: 8.3s;  --t: 5.5s; }
.p-luces rect:nth-child(12n+9)  { --d: 19s;   --t: 3.1s; }
.p-luces rect:nth-child(12n+10) { --d: 10.4s; --t: 7.8s; }
.p-luces rect:nth-child(12n+11) { --d: 12.7s; --t: .4s; }
.p-luces rect:nth-child(12n)    { --d: 15.6s; --t: 9.6s; }

/* Los ojos del retrato. El plano se llama «alguien te está mirando y no le ves
   la cara»: que parpadee es el único movimiento que ese plano necesita, y es
   el que lo convierte de ilustración en presencia. */
.p-ojos ellipse {
  transform-box: fill-box; transform-origin: center;
  animation: parpadeo 6.4s steps(1, end) infinite;
}
.p-ojos ellipse:last-child { animation-delay: -.04s; }   /* nunca a la vez exacta */
@keyframes parpadeo {
  0%, 95%   { transform: scaleY(1); }
  96%, 98%  { transform: scaleY(.08); }
  99%, 100% { transform: scaleY(1); }
}

/* El polvo que cruza la rendija de la puerta. */
.p-mota {
  animation: mota-sube 14s linear infinite;
  animation-delay: calc(var(--t, 0s) * -1);
}
@keyframes mota-sube {
  0%   { transform: translate(0, 10px);   opacity: 0; }
  20%  { opacity: .8; }
  80%  { opacity: .8; }
  100% { transform: translate(-6px, -34px); opacity: 0; }
}

/* La línea del gráfico se redibuja: en una sala de monitores el dato llega,
   no está. `pathLength` normaliza el trazo para que la cuenta salga igual en
   una línea corta y en una larga. */
/* `pathLength="100"` va en el marcado, no aquí: es un atributo SVG y como
   propiedad CSS no existe. Normaliza el trazo para que la misma cuenta sirva
   en una línea corta y en una larga. */
.p-linea {
  stroke-dasharray: 100;
  animation: linea-traza 7s ease-in-out infinite;
}
@keyframes linea-traza {
  0%       { stroke-dashoffset: 100; }
  35%, 82% { stroke-dashoffset: 0; }
  100%     { stroke-dashoffset: -100; }
}

/* El flujo de la red: el dato corriendo por el enlace hacia el sumidero. */
.p-flujo { stroke-dasharray: 4 6; animation: flujo-corre 1.6s linear infinite; }
@keyframes flujo-corre { to { stroke-dashoffset: -20; } }

/* El sumidero: el nodo donde acaba todo, latiendo. */
.p-sumidero {
  transform-box: fill-box; transform-origin: center;
  animation: sumidero-late 2.4s ease-in-out infinite;
}
@keyframes sumidero-late {
  0%, 100% { transform: scale(1);    opacity: .85; }
  50%      { transform: scale(1.09); opacity: 1; }
}

/* Las hojas y los billetes: flotan, no caen. Caer obliga a un bucle con
   costura visible; flotar no tiene principio ni final y a seis segundos por
   ciclo el ojo no encuentra dónde empieza. */
.p-hoja {
  transform-box: fill-box; transform-origin: center;
  animation: hoja-flota 6.5s ease-in-out infinite alternate;
}
@keyframes hoja-flota {
  from { transform: translate(0, 0)       rotate(0); }
  to   { transform: translate(-2px, -5px) rotate(1.4deg); }
}

/* La aguja del reloj, a un tic por segundo. Sesenta pasos en sesenta segundos:
   es un segundero de verdad, y en el plano que se llama «el tiempo como
   sospechoso» oír el tic con los ojos es la mitad del trabajo. */
.p-aguja { animation: aguja-tic 60s steps(60, end) infinite; }
@keyframes aguja-tic { to { transform: rotate(360deg); } }

/* La moneda gira sobre su canto. */
.p-moneda { animation: moneda-gira 7.5s ease-in-out infinite; }
@keyframes moneda-gira {
  0%, 62%, 100% { transform: scaleX(1); }
  78%           { transform: scaleX(.14); }
}

/* El neón. No respira: ZUMBA. Un tubo de gas no se apaga suave, se corta y
   vuelve, y a veces dos veces seguidas. Por eso va con `steps`: cualquier
   interpolación lo convertiría en una lámpara de mesa. */
.p-neon { animation: neon-zumba 5.4s steps(1, end) infinite; }
@keyframes neon-zumba {
  0%, 46%   { opacity: 1; }
  47%       { opacity: .25; }
  48%, 51%  { opacity: 1; }
  52%       { opacity: .3; }
  53%, 88%  { opacity: 1; }
  89%       { opacity: .2; }
  90%, 100% { opacity: 1; }
}

/* El haz del faro. Es el único plano cuyo nombre ya decía lo que tenía que
   hacer —«el faro BARRIENDO el agua»— y estaba quieto. Barre de verdad, y se
   apaga en los extremos: un faro gira, y sólo se le ve el haz cuando apunta
   hacia aquí. */
.p-barrido {
  transform-origin: 72px 118px;
  animation: faro-barre 11s ease-in-out infinite;
}
@keyframes faro-barre {
  0%, 100% { transform: rotate(-13deg); opacity: .15; }
  22%      { opacity: 1; }
  50%      { transform: rotate(13deg);  opacity: .9; }
  78%      { opacity: 1; }
}

/* Las sillas vacías. Cada hueco late en su momento, no todos a la vez: una
   sala donde faltan seis personas no parpadea al unísono. */
.p-huecos rect {
  animation: hueco-late 4.6s ease-in-out infinite;
  animation-delay: calc(var(--t, 0s) * -1);
}
@keyframes hueco-late { 50% { opacity: .02; } }

/* La alarma: lo rojo del plano, latiendo despacio. Más lento que el foco y sin
   volver del todo al mismo sitio, para que no se lea como decoración. */
.p-alarma { animation: alarma-late 3.4s ease-in-out infinite; }
@keyframes alarma-late {
  0%, 100% { opacity: .72; }
  50%      { opacity: 1; }
}

/* La balanza. El plano se llama «y no pesan lo mismo»: que el fiel oscile un
   grado es la frase entera. El pivote es donde el astil cruza la columna. */
.p-balanza {
  transform-origin: 200px 98px;
  animation: balanza-oscila 7.2s ease-in-out infinite alternate;
}
@keyframes balanza-oscila {
  from { transform: rotate(-.9deg); }
  to   { transform: rotate(.9deg); }
}

/* El agua del puerto devolviendo la luz de la farola. */
.p-reflejo { animation: agua-ondula 5.2s ease-in-out infinite alternate; }
@keyframes agua-ondula {
  from { transform: translateX(-2.5px) scaleY(1);    opacity: .8; }
  to   { transform: translateX(2.5px)  scaleY(1.07); opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  /* El celuloide se queda: es el dibujo. Lo que se apaga es su movimiento. */
  .cel * { animation: none !important; }
  .encuadre, .plano, .plano-capa, .intro-num, .intro-titulo h2, .intro-tagline,
  .intro-tagline::before, .intro-avanzar, .intro-viñeta, .v-texto .pal,
  .v-nombre, .intro.cerrando, .p-ventana, .p-linea,
  .p-flujo, .p-sumidero, .p-hoja, .p-aguja {
    animation-duration: .01s !important; animation-delay: 0s !important;
    animation-iteration-count: 1 !important;
  }
  /* Sin movimiento no hay cámara ni atmósfera: el plano se queda quieto y
     limpio. Se desactiva el desenfoque del cierre, que sin animación se
     quedaría congelado encima del expediente. */
  .intro.cerrando { filter: none !important; transform: none !important; }
  .clima-lluvia::before, .clima-lluvia::after,
  .clima-polvo::before, .clima-polvo::after, .clima-haz { animation: none !important; }
  .intro-clima { opacity: .5; }
  .intro-destello.dispara { animation: none !important; }
}

/* ================= CAPA DE JUEGO ================= */

/* Rango del jugador, en la portada */
.rango { margin-top: 26px; max-width: 380px; }
.rango-cab { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin-bottom: 7px; }
.rango-cab strong {
  font-family: var(--serif); font-size: 18px; font-weight: 600; color: var(--accent);
}
.rango-cab span { font-size: 12px; color: var(--ink-faint); }
.rango-barra { height: 3px; background: var(--line-soft); border-radius: 3px; overflow: hidden; }
.rango-barra div {
  height: 100%; background: var(--accent); border-radius: 3px;
  transition: width .8s cubic-bezier(.2,.8,.3,1);
}

/* Medalla en la tarjeta del archivo */
.medalla { font-size: 13px; line-height: 1; }
.med-bronce { color: #b07a4a; }
.med-plata  { color: #aab4c0; }
.med-oro    { color: var(--amber); text-shadow: 0 0 8px rgba(216,162,74,.55); }

/* Objetivos secundarios del caso */
.objetivos { list-style: none; margin: 10px 0 0; padding: 0; display: grid; gap: 5px; }
.objetivos li {
  display: flex; align-items: baseline; gap: 8px;
  font-size: 12.5px; color: var(--ink-faint);
  font-family: var(--mono);
}
.objetivos li em { color: var(--ink-faint); opacity: .7; font-style: normal; font-size: 11px; }
.objetivos li.ok { color: var(--jade); }
/* La marca de la casa va aparte: no cuenta para la medalla, así que tampoco
   se pinta como los otros tres. Un filete arriba la separa —es otra cosa, no
   un cuarto requisito— y cumplida se enciende en ámbar, no en jade: el jade
   es «has cerrado el caso», esto es «lo has cerrado como el archivo». */
/* ---------- la tira de hojas de la consola ----------
   Números, no nombres: nombrar cuatro borradores es trabajo que el jugador no
   ha pedido, y a la tercera nadie recuerda cuál era «consulta2». El punto dice
   cuáles llevan algo escrito, que es lo único que hace falta ver de un vistazo.
   Va pegada al editor, como la pestaña de una carpeta al expediente. */
.hojas { display: flex; gap: 3px; padding: 0 2px; }
.hoja {
  min-width: 26px; height: 22px; padding: 0 7px;
  font-family: var(--mono); font-size: 11px; line-height: 1;
  color: var(--ink-faint); background: var(--panel-2);
  border: 1px solid var(--line); border-bottom: 0;
  border-radius: 4px 4px 0 0; cursor: pointer;
  position: relative; transition: color .12s, background-color .12s;
}
.hoja:hover { color: var(--ink); }
.hoja.activa {
  color: var(--accent); background: var(--panel);
  /* Un pelo más alta y sin filete abajo: es la hoja que está encima del
     montón, no un botón seleccionado. */
  height: 24px; margin-bottom: -1px; border-color: var(--line);
}
/* El punto de «tiene algo escrito». En la activa no se pinta: ya la estás
   viendo, y un adorno que no informa es ruido. */
.hoja.usada:not(.activa)::after {
  content: ""; position: absolute; left: 50%; bottom: 3px;
  width: 3px; height: 3px; margin-left: -1.5px; border-radius: 50%;
  background: var(--accent); opacity: .65;
}
.hoja.nueva { color: var(--ink-faint); opacity: .6; font-size: 13px; }
/* Cerrar la hoja de delante. Va al final de la tira y no dentro de cada
   pestaña: a 26 px de ancho, una × dentro del número se pulsa sin querer. */
.hoja.cerrar { color: var(--ink-faint); opacity: .45; font-size: 13px; }
.hoja.cerrar:hover { opacity: 1; color: var(--red-claro, #e2705a); }
.hoja.nueva:hover { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .hoja { transition: none; } }

.objetivos li.extra {
  margin-top: 6px; padding-top: 7px; border-top: 1px dashed var(--line-soft);
}
.objetivos li.extra.ok { color: var(--amber); }
.objetivos li.fallado { opacity: .45; text-decoration: line-through; text-decoration-thickness: 1px; }
.obj-icono { width: 12px; text-align: center; }

/* ---------- pantalla de caso resuelto ---------- */
.celebracion {
  position: fixed; inset: 0; z-index: 500;
  display: grid; place-items: center; padding: 20px;
  background: rgba(5,7,9,.82); backdrop-filter: blur(8px);
  animation: cel-entrar .35s ease both;
}
@keyframes cel-entrar { from { opacity: 0; } }

.cel-caja {
  position: relative; z-index: 2;
  width: min(460px, 100%); max-height: 88dvh; overflow-y: auto;
  background: var(--panel); border: 1px solid var(--line); border-radius: 14px;
  padding: 26px 24px 22px; text-align: center;
  box-shadow: 0 30px 80px rgba(0,0,0,.7);
  animation: cel-subir .45s cubic-bezier(.2,.9,.3,1) both;
}
@keyframes cel-subir { from { opacity: 0; transform: translateY(22px) scale(.97); } }

.cel-sello {
  width: 128px; height: 128px; margin: 4px auto 16px;
  display: grid; place-items: center; border-radius: 50%;
  border: 3px solid currentColor; color: var(--jade);
  font-family: var(--mono); font-size: 15px; letter-spacing: .14em; line-height: 1.35;
  transform: rotate(-9deg);
  animation: cel-sellar .55s cubic-bezier(.2,1.7,.4,1) .12s both;
}
/* El sello cae de golpe, como en la carpeta: es el mismo gesto, más grande. */
@keyframes cel-sellar {
  0%   { transform: rotate(-30deg) scale(2.4); opacity: 0; }
  55%  { transform: rotate(-6deg) scale(.92); opacity: 1; }
  100% { transform: rotate(-9deg) scale(1); }
}
.cel-sello.cel-bronce { color: #b07a4a; }
.cel-sello.cel-plata  { color: #aab4c0; }
.cel-sello.cel-oro    { color: var(--amber); box-shadow: 0 0 34px rgba(216,162,74,.34); }

.cel-caja h2 { font-family: var(--serif); font-size: 23px; font-weight: 500; margin: 0 0 2px; }
.cel-medalla {
  font-family: var(--mono); font-size: 11px; letter-spacing: .18em; text-transform: uppercase;
  color: var(--ink-faint); margin: 0 0 18px;
}

.cel-objetivos { list-style: none; margin: 0 0 18px; padding: 0; display: grid; gap: 7px; text-align: left; }
.cel-objetivos li {
  display: flex; align-items: baseline; gap: 9px;
  font-size: 13px; color: var(--ink-faint);
  background: var(--bg-2); border: 1px solid var(--line-soft); border-radius: 8px; padding: 8px 11px;
  animation: cel-fila .4s ease both;
}
.cel-objetivos li:nth-child(1) { animation-delay: .5s; }
.cel-objetivos li:nth-child(2) { animation-delay: .62s; }
.cel-objetivos li:nth-child(3) { animation-delay: .74s; }
@keyframes cel-fila { from { opacity: 0; transform: translateX(-10px); } }
.cel-objetivos li.ok { color: var(--jade); border-color: rgba(70,195,156,.35); }
.cel-objetivos li em { margin-left: auto; font-style: normal; font-size: 11px; opacity: .7; }
.cel-icono { width: 14px; text-align: center; }

.cel-etiqueta {
  display: block; font-family: var(--mono); font-size: 10px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--ink-faint); margin-bottom: 4px;
}
.cel-patron {
  background: rgba(216,162,74,.07); border: 1px solid var(--amber-dim);
  border-radius: 9px; padding: 11px 13px; margin-bottom: 16px; text-align: left;
  animation: cel-fila .45s ease .9s both;
}
.cel-patron strong { display: block; font-family: var(--serif); font-size: 15.5px; }
.cel-patron strong + strong { margin-top: 4px; }

.cel-rango { text-align: left; margin-bottom: 20px; animation: cel-fila .45s ease 1s both; }
.cel-barra { height: 3px; background: var(--line-soft); border-radius: 3px; overflow: hidden; margin: 6px 0 6px; }
.cel-barra div { height: 100%; background: var(--accent); animation: cel-barra 1s ease 1.1s both; }
@keyframes cel-barra { from { width: 0 !important; } }
.cel-rango p { margin: 0; font-size: 12.5px; color: var(--ink-faint); }

/* Papeles de archivo cayendo por detrás de la tarjeta */
.cel-papeles { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
.cel-papeles i {
  position: absolute; top: -14%; display: block;
  background: var(--paper); opacity: .85; border-radius: 1px;
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.12);
  animation-name: cel-caer; animation-timing-function: linear; animation-iteration-count: 1;
  animation-fill-mode: both;
}
@keyframes cel-caer {
  0%   { transform: translateY(0) rotate(0); opacity: 0; }
  8%   { opacity: .9; }
  100% { transform: translateY(112vh) rotate(var(--giro)); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .cel-papeles { display: none; }
  .cel-sello, .cel-caja, .cel-objetivos li, .cel-patron, .cel-rango, .cel-barra div {
    animation-duration: .01s !important; animation-delay: 0s !important;
  }
}

/* ---------- micro-animaciones de la interfaz ----------
   Cortas y sólo a la entrada. Nada que se repita mientras se lee, y nada que
   retrase un toque: si una animación hace esperar para actuar, sobra. */

@keyframes ui-entrar { from { opacity: 0; transform: translateY(10px); } }
@keyframes ui-fundir { from { opacity: 0; } }

.carpetas .carpeta { animation: ui-entrar .42s cubic-bezier(.2,.8,.3,1) both; }
/* El escalonado se corta a la sexta: más allá, quien llega abajo tras
   desplazarse encontraría tarjetas todavía apareciendo. */
.carpetas .carpeta:nth-child(1) { animation-delay: .02s; }
.carpetas .carpeta:nth-child(2) { animation-delay: .06s; }
.carpetas .carpeta:nth-child(3) { animation-delay: .10s; }
.carpetas .carpeta:nth-child(4) { animation-delay: .14s; }
.carpetas .carpeta:nth-child(5) { animation-delay: .18s; }
.carpetas .carpeta:nth-child(n+6) { animation-delay: .2s; }

.hero { animation: ui-entrar .5s ease-out both; }
.season { animation: ui-fundir .5s ease-out both; }

.case-grid > .pane { animation: ui-entrar .38s cubic-bezier(.2,.8,.3,1) both; }
.case-grid > .pane:nth-child(2) { animation-delay: .06s; }
.case-grid > .pane:nth-child(3) { animation-delay: .12s; }

.results .table-wrap { animation: ui-entrar .3s ease-out both; }
.results-bar { animation: ui-fundir .3s ease-out both; }

/* El botón de ejecutar late mientras trabaja: en el móvil, una consulta de dos
   segundos sin señal de vida parece un toque perdido. */
#btn-run:disabled { animation: ui-latir 1.1s ease-in-out infinite; }
@keyframes ui-latir { 50% { opacity: .55; } }

@media (prefers-reduced-motion: reduce) {
  .carpetas .carpeta, .hero, .cajon, .case-grid > .pane, .results .table-wrap, .results-bar {
    animation: none !important;
  }
  #btn-run:disabled { animation: none; }
}

/* ---------- la línea de una voz ----------
 * Abajo, con el color de la voz, el tiempo justo de leerla. Es el mismo objeto
 * que el coach del tutorial, sin botones: una voz interior, no un aviso. */
.voz-linea {
  position: fixed; left: 12px; right: 12px; bottom: calc(76px + var(--safe-b)); z-index: 320;
  max-width: 520px; margin: 0 auto; cursor: pointer;
  background: rgba(21,26,33,.94); border: 1px solid var(--line); border-left: 3px solid var(--voz, var(--amber));
  border-radius: 10px; padding: 10px 14px 11px 16px; box-shadow: 0 16px 40px rgba(0,0,0,.55);
  backdrop-filter: blur(8px);
  animation: voz-entrar .4s cubic-bezier(.2,.9,.3,1) both;
}
@media (min-width: 900px) { .voz-linea { left: auto; right: 24px; bottom: 24px; max-width: 420px; } }
.voz-linea.saliendo { animation: voz-salir .35s ease both; }
.voz-cab { display: flex; align-items: baseline; gap: 10px; margin-bottom: 4px; }
.voz-quien { font-family: var(--mono); font-size: 10.5px; letter-spacing: .16em; color: var(--voz, var(--amber)); }
.voz-sobre { font-family: var(--mono); font-size: 10px; color: var(--ink-faint); margin-left: auto; text-align: right; }
.voz-texto { margin: 0; font-family: var(--serif); font-size: 14.5px; line-height: 1.45; color: var(--ink); }
@keyframes voz-entrar { from { opacity: 0; transform: translateY(12px); } }
@keyframes voz-salir  { to   { opacity: 0; transform: translateY(-6px); } }
body.con-coach .voz-linea { display: none; }   /* el coach ya habla */
html.ahorro .voz-linea { backdrop-filter: none; }
@media (prefers-reduced-motion: reduce) { .voz-linea, .voz-linea.saliendo { animation: none; } }

/* Los colores de las voces, compartidos por la introducción, el coach, la
   línea y la placa. */
[data-voz="archivo"]    { --voz: #c9a86b; }
[data-voz="pericial"]     { --voz: #7fb2ff; }
[data-voz="internos"]   { --voz: #d2564f; }
[data-voz="instruccion"]     { --voz: #46c39c; }
[data-voz="guardia"]     { --voz: #9a7fd0; }
[data-voz="centralita"] { --voz: #e8b45e; }
[data-voz="fiscalia"]   { --voz: #e07a6f; }

/* Las voces en la placa: siete filas, una marca por técnica. Es la ficha del
   personaje, y el personaje son las voces. */
.voces-ficha { display: grid; gap: 6px; margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--line-soft); }
.voz-fila { display: grid; grid-template-columns: 92px 1fr auto; align-items: center; gap: 8px; }
.voz-fila .voz-quien { font-size: 9.5px; letter-spacing: .14em; }
.voz-marcas { display: flex; gap: 3px; }
.voz-marcas i { display: block; width: 9px; height: 9px; border-radius: 2px; border: 1px solid var(--line); }
.voz-marcas i.on { background: var(--voz, var(--amber)); border-color: transparent; box-shadow: 0 0 6px color-mix(in srgb, var(--voz, var(--amber)) 45%, transparent); }
.voz-fila em { font-style: normal; font-family: var(--mono); font-size: 9.5px; letter-spacing: .08em; color: var(--ink-faint); }
.voz-fila.afilada em { color: var(--voz); }

/* ---------- ajustes de narración ---------- */
.ajustes-voz {
  background: var(--bg-2); border: 1px solid var(--line-soft); border-radius: var(--r);
  padding: 14px 16px; margin-bottom: 18px; display: grid; gap: 10px;
}
.ajuste { display: flex; align-items: center; gap: 12px; font-size: 13px; color: var(--ink-dim); }
.ajuste > span { flex: 0 0 84px; }
.ajuste select, .ajuste input[type="range"] { flex: 1; min-width: 0; }
.ajuste select {
  background: var(--panel); color: var(--ink); border: 1px solid var(--line);
  border-radius: 7px; padding: 7px 9px; font-size: 12.5px;
}
.ajuste input[type="range"] { accent-color: var(--accent); }
.ajustes-nota { color: var(--ink-faint); font-size: 12.5px; line-height: 1.55; margin: 0; }


/* ---------- consumo: que el teléfono no se caliente ----------
 *
 * Tres cosas cuestan de verdad en un móvil y las tres estaban aquí:
 *
 * 1. **Animar dentro de un filtro SVG.** Ya arreglado en `escenas.js`: el
 *    motivo y la luna salieron de los grupos filtrados. Un `feTurbulence`
 *    recalculándose sesenta veces por segundo por tarjeta es todo el
 *    presupuesto térmico del aparato.
 * 2. **Componer lo que no se ve.** El archivo pinta veintidós tarjetas. Ya
 *    estaban congeladas, pero el navegador seguía rasterizando las veintidós
 *    escenas —con sus filtros— aunque en pantalla cupieran tres.
 * 3. **Seguir animando con la app en segundo plano.** Nada lo impedía.
 */

/* Con la app en segundo plano no se anima nada. `paused` en vez de `none`
   para que al volver siga donde estaba y no dé un salto. */
html.pausa *,
html.pausa *::before,
html.pausa *::after { animation-play-state: paused !important; }

/* Ahorro de batería. Se enciende solo en aparatos con poca memoria o pocos
   núcleos, y a mano desde la barra. Quita lo caro y deja el juego intacto:
   el óleo, el grano y la lluvia son atmósfera, no información. */
html.ahorro svg *,
html.ahorro .plano,
html.ahorro .rain { animation: none !important; }
html.ahorro [filter] { filter: none !important; }
html.ahorro .grain { display: none; }
html.ahorro .rain { opacity: .07; }
html.ahorro .cel-papeles { display: none; }
html.ahorro .topbar,
html.ahorro .modal,
html.ahorro .hoja { backdrop-filter: none; }


/* ---------- válvulas anti-atasco ---------- */

/* Un hecho revelado se queda escrito y bloqueado: se pidió ver una pieza, no
   volver a teclearla. */
.field.revelado input { color: var(--ink-dim); border-style: dashed; }

/* El empujón de ARCHIVO cuando el jugador lleva consultas sin abrir una tabla
   que importa. Se pinta como una voz interior, no como un aviso del sistema. */
.olfato {
  margin-top: 10px; padding: 10px 14px; border-left: 3px solid var(--amber-dim);
  background: rgba(216,162,74,.06); border-radius: 0 8px 8px 0; font-size: 13.5px;
}
.olfato b { font-family: var(--mono); font-size: 10.5px; letter-spacing: .14em; color: var(--amber); margin-right: 8px; }
.olfato code { font-family: var(--mono); }


/* ---------- pantalla de título ----------
 *
 * Lo primero que se ve. Una portada pintada a pantalla completa con tres
 * capas que se mueven poco y despacio —la escena con paralaje al ratón, la
 * niebla derivando, la viñeta quieta— y el nombre del juego con tipografía
 * propia. Sin barra, sin chrome: el mundo antes que la interfaz.
 */
.titulo {
  position: fixed; inset: 0; z-index: 60; overflow: hidden; background: var(--bg);
  display: grid; place-items: end start; cursor: pointer; user-select: none;
  --px: 0; --py: 0;
}
.titulo-escena {
  position: absolute; inset: -4%; will-change: transform;
  transform: translate(calc(var(--px) * -12px), calc(var(--py) * -8px)) scale(1.04);
  transition: transform .6s cubic-bezier(.2,.8,.2,1);
}
.titulo-escena svg { width: 100%; height: 100%; display: block; }
.titulo-niebla {
  position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(60% 40% at 30% 78%, rgba(30,42,53,.55), transparent 70%),
    radial-gradient(50% 30% at 75% 70%, rgba(30,42,53,.35), transparent 70%);
  animation: niebla-deriva 26s ease-in-out infinite alternate;
  transform: translate(calc(var(--px) * -22px), 0);
}
@keyframes niebla-deriva { from { background-position: 0 0, 0 0; } to { background-position: 60px 0, -80px 0; } }
.titulo-vineta {
  position: absolute; inset: 0; pointer-events: none;
  background:
    linear-gradient(to top, rgba(10,12,15,.92) 0%, rgba(10,12,15,.55) 30%, transparent 60%),
    radial-gradient(90% 70% at 50% 40%, transparent 55%, rgba(10,12,15,.7) 100%);
}
.titulo-bloque {
  position: relative; z-index: 2; padding: 0 clamp(20px, 6vw, 72px) clamp(36px, 8vh, 84px);
  max-width: 720px; animation: ui-entrar .9s .2s cubic-bezier(.2,.8,.2,1) both;
}
.titulo-sobre {
  font-family: var(--mono); font-size: 11px; letter-spacing: .22em; text-transform: uppercase;
  color: var(--amber); margin: 0 0 14px; opacity: .9;
}
.titulo-nombre {
  font-family: var(--serif); font-weight: 500; line-height: .92; margin: 0;
  font-size: clamp(56px, 11vw, 132px); letter-spacing: -.03em; color: var(--paper);
  text-shadow: 0 2px 0 rgba(0,0,0,.35), 0 18px 50px rgba(0,0,0,.6);
}
.titulo-nombre span { display: block; font-size: .42em; letter-spacing: .18em; text-transform: uppercase; font-weight: 400; color: var(--ink-dim); margin-bottom: .1em; }
.titulo-nombre em { font-style: italic; color: var(--paper); }
.titulo-trazo { width: min(300px, 60vw); height: 14px; color: var(--amber); margin: 6px 0 14px; display: block; }
.titulo-lema { font-family: var(--serif); font-style: italic; font-size: clamp(15px, 2vw, 19px); color: var(--ink-dim); margin: 0 0 26px; max-width: 46ch; }
.titulo-menu { display: flex; flex-wrap: wrap; gap: 10px; }
.titulo-btn {
  font: inherit; font-size: 14px; letter-spacing: .04em; cursor: pointer;
  padding: 12px 20px; border-radius: 4px; color: var(--ink);
  background: rgba(21,26,33,.72); border: 1px solid var(--line);
  backdrop-filter: blur(6px); transition: border-color .2s, background .2s, transform .2s;
}
.titulo-btn:hover { border-color: var(--amber-dim); background: rgba(27,33,42,.9); transform: translateY(-1px); }
/* El foco tenía `outline: none` y se confiaba al cambio de borde; en el botón
   primario el borde ya es ámbar, así que con el teclado no pasaba nada
   visible en el botón más importante del juego. El anillo va en color papel
   para que se vea igual sobre el ámbar que sobre el panel oscuro. */
.titulo-btn:focus-visible {
  border-color: var(--amber-dim); transform: translateY(-1px);
  outline: 2px solid var(--paper); outline-offset: 3px;
}
.titulo-btn.primario { background: var(--amber); color: #17130a; border-color: var(--amber); font-weight: 600; }
.titulo-btn.primario:hover { background: #e6b45e; }
.titulo-btn.primario small { display: block; font-weight: 400; font-size: 11.5px; opacity: .8; letter-spacing: .02em; }
.titulo-pie {
  position: absolute; right: clamp(16px, 4vw, 40px); bottom: clamp(14px, 3vh, 28px); z-index: 2; margin: 0;
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .18em; text-transform: uppercase; color: var(--ink-faint);
  animation: ui-latir 3.2s ease-in-out infinite;
}
.titulo .brand-oculta { display: none; }
body.en-titulo .topbar, body.en-titulo .rain { display: none; }

/* ---------- el archivo: caso activo, placa y carpetas ---------- */
.cabecera-archivo {
  display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(260px, .9fr); gap: 18px;
  margin: 8px 0 40px; align-items: stretch; animation: ui-entrar .5s ease-out both;
}
@media (max-width: 860px) { .cabecera-archivo { grid-template-columns: 1fr; } }

/* El caso activo: la escena pintada en grande y el botón de seguir. Es lo
   único que un jugador que vuelve necesita ver antes de decidir nada. */
.activo {
  position: relative; min-height: 260px; border-radius: var(--r); overflow: hidden;
  border: 1px solid var(--line); background: var(--panel); cursor: pointer;
}
.activo .activo-escena { position: absolute; inset: 0; }
.activo .activo-escena svg { width: 100%; height: 100%; display: block; }
.activo .activo-sombra { position: absolute; inset: 0; background: linear-gradient(to top, rgba(10,12,15,.95) 0%, rgba(10,12,15,.6) 45%, rgba(10,12,15,.05) 100%); }
.activo .activo-texto { position: relative; z-index: 1; padding: 28px 26px 24px; display: flex; flex-direction: column; justify-content: flex-end; min-height: 260px; }
.activo-sobre { font-family: var(--mono); font-size: 10.5px; letter-spacing: .2em; text-transform: uppercase; color: var(--amber); margin: 0 0 8px; }
.activo h2 { font-family: var(--serif); font-weight: 500; font-size: clamp(24px, 3.4vw, 36px); margin: 0 0 6px; text-wrap: balance; }
.activo .activo-lema { color: var(--ink-dim); font-style: italic; font-family: var(--serif); margin: 0 0 16px; font-size: 15px; }
.activo .activo-pie { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.activo .activo-pie .meta { font-family: var(--mono); font-size: 11px; color: var(--ink-faint); letter-spacing: .06em; }
.activo:hover .activo-escena { transform: scale(1.02); }
.activo .activo-escena { transition: transform .6s ease; }
/* El motivo del caso queda detrás del texto: se atenúa para que sea fondo y no
   compita con el título. */
.activo .c-motivo { opacity: .7; }

/* La placa: el rango y los números, como la ficha de un policía. */
.ficha {
  border: 1px solid var(--line); border-radius: var(--r); background: var(--panel);
  padding: 18px 20px; display: flex; flex-direction: column; gap: 14px;
  background-image: repeating-linear-gradient(0deg, transparent 0 22px, rgba(255,255,255,.015) 22px 23px);
}
.ficha-sobre { font-family: var(--mono); font-size: 10.5px; letter-spacing: .2em; text-transform: uppercase; color: var(--ink-faint); margin: 0; }
.ficha .rango { margin: 0; }
.ficha-stats { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 16px; margin-top: auto; }
.ficha-stats .hero-stat b { font-size: 20px; }

html.ahorro .titulo-niebla, html.ahorro .titulo-pie { animation: none; }
html.ahorro .titulo-escena, html.ahorro .titulo-niebla { transform: none; transition: none; }
@media (prefers-reduced-motion: reduce) {
  .titulo-niebla, .titulo-pie, .titulo-bloque, .cabecera-archivo { animation: none !important; }
  .titulo-escena, .titulo-niebla { transform: none !important; }
}


/* ---------- el coach del tutorial ----------
 * Una voz interior, no un cuadro de ayuda: mismo color por voz que en la
 * introducción, abajo, sin tapar la consola. */
.coach {
  position: fixed; left: 12px; right: 12px; bottom: calc(66px + var(--safe-b)); z-index: 300;
  max-width: 520px; margin: 0 auto;
  background: rgba(21,26,33,.94); border: 1px solid var(--line); border-left: 3px solid var(--voz, var(--amber));
  border-radius: 10px; padding: 12px 14px 12px 16px; box-shadow: 0 16px 40px rgba(0,0,0,.55);
  backdrop-filter: blur(8px);
}
@media (min-width: 900px) { .coach { left: auto; right: 24px; bottom: 24px; max-width: 420px; } }
.coach.entra { animation: ui-entrar .35s cubic-bezier(.2,.8,.3,1) both; }
.coach-cab { display: flex; align-items: center; gap: 10px; margin-bottom: 6px; }
.coach-voz { font-family: var(--mono); font-size: 10.5px; letter-spacing: .16em; color: var(--voz, var(--amber)); }
.coach-paso { font-family: var(--mono); font-size: 10px; color: var(--ink-faint); margin-left: auto; }
.coach-cerrar { background: none; border: 0; color: var(--ink-faint); cursor: pointer; font-size: 14px; padding: 2px 4px; }
.coach-cerrar:hover { color: var(--ink); }
.coach-texto { margin: 0 0 10px; font-family: var(--serif); font-size: 15px; line-height: 1.5; color: var(--ink); }
.coach-acciones { display: flex; gap: 8px; flex-wrap: wrap; }
.coach-acciones .btn { padding: 7px 12px; font-size: 12.5px; }
/* Los colores por voz están en «la línea de una voz», compartidos. */
@media (prefers-reduced-motion: reduce) { .coach.entra { animation: none; } }

/* Mientras el coach está en pantalla, el expediente deja sitio debajo. */
body.con-coach .case-grid > .zona:last-child > :last-child, body.con-coach .case-grid [data-tab].active:last-of-type { margin-bottom: 190px; }
@media (min-width: 1181px) { body.con-coach .zona-der { padding-bottom: 240px; } body.con-coach .zona-izq { padding-bottom: 0; } }

/* El foco del tutorial: un recorte de luz. La sombra de 9999px apaga el resto
   de la pantalla; el aro ámbar late para que el ojo vaya solo. No bloquea
   toques: es una indicación, no una jaula. */
.foco-tutorial {
  position: fixed; z-index: 290; pointer-events: none; border-radius: 8px;
  box-shadow: 0 0 0 9999px rgba(6, 8, 11, .74), 0 0 0 3px var(--amber), 0 0 26px rgba(216,162,74,.55);
  transition: left .25s ease, top .25s ease, width .25s ease, height .25s ease;
  animation: foco-latir 1.6s ease-in-out infinite;
}
.foco-tutorial.oculto { display: none; }
@keyframes foco-latir {
  50% { box-shadow: 0 0 0 9999px rgba(6, 8, 11, .74), 0 0 0 5px var(--amber), 0 0 34px rgba(216,162,74,.75); }
}
html.ahorro .foco-tutorial { animation: none; }
@media (prefers-reduced-motion: reduce) { .foco-tutorial { animation: none; transition: none; } }


/* ---------- el puesto de trabajo ----------
 *
 * La vista de un caso tiene tres trabajos y se lee de izquierda a derecha en
 * ese orden: LEER el expediente, CONSULTAR los datos, PROBAR lo que se
 * afirma. Cada columna es uno. En pantalla grande la vista ocupa el alto de la
 * ventana y cada columna se desplaza por su cuenta: la consola crece hasta el
 * borde, el tablero de hechos queda siempre a la vista junto a los
 * resultados —fijar una celda y verla aparecer al lado— y el expediente se
 * lee sin arrastrar consigo todo lo demás. En tablet son dos columnas; en el
 * móvil, pestañas (más arriba).
 */
/* Sólo a partir de tablet: en el móvil mandan las pestañas (más arriba). */
@media (min-width: 861px) {
  /* Las laterales eran fijas —400 y 360— y se las pagaba entera la consola:
     en una ventana de 1280 la columna donde se escribe SQL y se leen los
     resultados se quedaba con 456 px, la más estrecha de las tres, siendo
     donde se pasa el 95 % del tiempo. Con `clamp` las laterales ceden en
     pantallas pequeñas y recuperan su tamaño en las grandes. */
  .case-grid { display: grid; gap: 14px; align-items: start;
    grid-template-columns: minmax(0, clamp(320px, 26vw, 400px)) minmax(0, 1fr) minmax(0, clamp(292px, 23vw, 360px)); }
  .zona { min-width: 0; display: flex; flex-direction: column; gap: 12px; }
}
.zona-rotulo {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .22em; text-transform: uppercase;
  color: var(--ink-faint); margin: 0 0 -4px 2px;
}
.zona-rotulo::before { content: "// "; color: var(--line); }
.case-grid .hints, .case-grid .notepad, .case-grid .accuse, .case-grid .history, .case-grid .results,
.case-grid .solution, .case-grid .danger-zone, .case-grid .case-nav, .case-grid .statbar, .case-grid .objetivos { margin-top: 0; }

/* Tablet: el expediente y la acusación comparten la columna izquierda. */
@media (min-width: 861px) and (max-width: 1180px) {
  .case-grid { grid-template-columns: minmax(0, 360px) minmax(0, 1fr); }
  .zona-izq { grid-column: 1; grid-row: 1; }
  .zona-der { grid-column: 1; grid-row: 2; }
  .zona-centro { grid-column: 2; grid-row: 1 / span 2; }
}

/* Escritorio: la vista cabe en la ventana y las columnas se desplazan solas. */
@media (min-width: 1181px) {
  body.en-caso { height: 100dvh; overflow: hidden; display: flex; flex-direction: column; }
  body.en-caso .topbar { flex: 0 0 auto; }
  body.en-caso .view-caso {
    flex: 1 1 0; min-height: 0; max-width: 1760px; width: 100%;
    padding: 14px 18px 14px; display: flex; flex-direction: column;
  }
  .view-caso .case-grid { flex: 1 1 0; min-height: 0; align-items: stretch; }
  .zona { min-height: 0; overflow-y: auto; overflow-x: hidden; padding: 2px 6px 2px 2px; scrollbar-width: thin; scrollbar-color: var(--line) transparent; }
  .zona::-webkit-scrollbar { width: 8px; }
  .zona::-webkit-scrollbar-thumb { background: var(--line); border-radius: 8px; }
  /* La consola: el editor arriba, fijo; los resultados se quedan el resto. */
  /* Con barra por si aun así no cabe: un contenedor que se desplaza sin
     poder desplazarse a mano deja el editor fuera de la vista para siempre. */
  .zona-centro { overflow-y: auto; }
  /* El editor cede antes que los resultados: con la barra de atajos abierta
     en una ventana baja, lo que se encoge (y se desplaza) es el editor, y la
     tabla conserva sitio para verse. */
  /* El editor mide lo que mide: nunca se recorta ni se desplaza por dentro
     (en una ventana baja dejaba el botón de ejecutar fuera de la vista). Si
     no cabe todo, se desplaza la columna entera, que sí tiene barra. */
  .zona-centro .editor-wrap { flex: 0 0 auto; }
  .zona-centro .results { flex: 1 1 0; min-height: 320px; display: flex; flex-direction: column; }
  .zona-centro .results > .table-wrap { flex: 1 1 0; min-height: 0; max-height: none; }
  .zona-centro .results > .error, .zona-centro .results > .vacio { flex: 0 0 auto; }
  .zona-centro .history { flex: 0 0 auto; }
  .zona-centro .history[open] { max-height: 40%; overflow: auto; }
  .zona-der .datos { flex: 0 0 auto; }
}

/* El editor con algo de cuerpo en el escritorio: tres o cuatro líneas de
   consulta a la vista sin desplazar. */
@media (min-width: 861px) { .editor .cm-editor { min-height: 132px; } }

/* La consola vacía: un empujón, no un hueco. */
.vacio {
  border: 1px dashed var(--line); border-radius: var(--r); padding: 22px 20px;
  background: linear-gradient(180deg, rgba(255,255,255,.015), transparent);
}
.vacio-titulo { margin: 0 0 4px; font-family: var(--serif); font-size: 17px; color: var(--ink); }
.vacio-texto { margin: 0 0 14px; font-size: 13.5px; color: var(--ink-dim); line-height: 1.55; }
.vacio-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.vacio-chip {
  font-family: var(--mono); font-size: 12px; color: var(--ink-dim);
  background: var(--panel); border: 1px solid var(--line); border-radius: 8px; padding: 8px 12px; cursor: pointer;
  transition: border-color .12s, color .12s;
}
.vacio-chip b { color: var(--amber); font-weight: 600; }
.vacio-chip:hover { border-color: var(--amber-dim); color: var(--ink); }

/* El tablero de hechos: es el sitio al que va todo lo demás, y se nota. */
.accuse {
  /* Papel, como el expediente: la paleta local se define arriba, junto a `.accuse`. */
  background: var(--paper) linear-gradient(180deg, rgba(0,0,0,.035), transparent 90px);
  border: 0;
  border-radius: var(--r); padding: 16px 16px 14px;
}
.accuse h3 { font-family: var(--serif); font-size: 18px; font-weight: 600; letter-spacing: 0; text-transform: none; color: var(--ink); }
.hechos-cuenta { padding: 3px 9px; border: 1px solid var(--line); border-radius: 999px; white-space: nowrap; }
.hechos-cuenta.ok { border-color: var(--jade); }
#btn-answer { width: 100%; padding: 12px 16px; font-weight: 600; letter-spacing: .02em; }
.accuse .field:last-of-type { margin-bottom: 0; }
.prueba { margin: 12px 0; }
.prueba select { text-overflow: ellipsis; }

/* El estado del caso: cuatro cifras y los tres objetivos, no una línea de log. */
.estado { background: var(--panel); border: 1px solid var(--line-soft); border-radius: var(--r); padding: 12px 14px 10px; }
.statbar { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; margin: 0; }
.statbar .stat {
  display: flex; flex-direction: column-reverse; gap: 2px; min-width: 0;
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-faint);
}
.statbar .stat b { font-size: 15px; letter-spacing: 0; color: var(--ink); font-weight: 600; font-variant-numeric: tabular-nums; }
.estado .objetivos { margin: 10px 0 0; padding-top: 10px; border-top: 1px solid var(--line-soft); }
.objetivos li.ok { color: var(--jade); }
.objetivos li.ok .obj-icono { color: var(--jade); }
.objetivos li.fallado { color: var(--ink-faint); text-decoration: line-through; text-decoration-color: rgba(255,255,255,.18); }

/* Los datos: título y filtro en una línea cuando cabe. */
.datos .schema-head { flex-direction: row; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; }
/* El marcador del filtro se cortaba a media palabra en la columna estrecha.
   Con esta base, cuando no cabe junto al título baja a su propia línea
   entero, en vez de encogerse hasta recortar el texto. */
.datos .schema-head input { flex: 1 1 100%; min-width: 0; }
.datos #schema-filter { width: auto; flex: 1 1 140px; min-width: 120px; }
.danger-zone .btn { padding: 8px 12px; font-size: 13px; }

/* El botón del otro idioma en la portada: presente, discreto. */
.titulo-idioma { opacity: .8; }


/* ---------- el expediente 88-C ----------
 * La serie hecha tangible: un tablero de corcho en el archivo al que cada
 * caso cerrado aporta una nota. Las notas son fichas mecanografiadas,
 * pinchadas con un giro pequeño; los huecos, fichas en blanco. */
.hilo { margin: 0 0 30px; }
.hilo-cab { display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap; margin-bottom: 12px; }
.hilo-cab h2 { font-family: var(--serif); font-size: 24px; font-weight: 600; margin: 0; letter-spacing: -.01em; }
.hilo-cab .hilo-cuenta { font-family: var(--mono); font-size: 11px; letter-spacing: .14em; text-transform: uppercase; color: var(--amber); }
.hilo-cab .hilo-vacio { font-size: 13.5px; color: var(--ink-faint); font-style: italic; margin: 0; }
.corcho {
  position: relative; display: grid; gap: 10px; padding: 16px;
  grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
  background:
    radial-gradient(circle at 20% 30%, rgba(255,255,255,.03), transparent 40%),
    linear-gradient(180deg, #2a2016, #211a12);
  border: 1px solid #3a2e21; border-radius: var(--r);
  box-shadow: inset 0 0 40px rgba(0,0,0,.45);
}
.nota {
  position: relative; min-height: 96px; padding: 12px 12px 10px;
  background: var(--paper); color: var(--paper-ink);
  font-family: var(--mono); font-size: 11.5px; line-height: 1.45;
  transform: rotate(var(--giro, 0deg));
  box-shadow: 0 6px 14px rgba(0,0,0,.4);
}
.nota::before {
  content: ""; position: absolute; top: -5px; left: 50%; width: 10px; height: 10px; border-radius: 50%;
  background: radial-gradient(circle at 35% 35%, #e6b866, #8a5a1a); box-shadow: 0 2px 3px rgba(0,0,0,.5);
  transform: translateX(-50%);
}
.nota .nota-num { display: block; font-size: 9.5px; letter-spacing: .16em; color: var(--paper-dim); margin-bottom: 5px; }
/* El texto estaba a 2.6:1. Se atenúa la ficha, no su contenido. */
.nota.vacia { background: rgba(232,226,212,.06); color: #8a8172; box-shadow: none; border: 1px dashed rgba(232,226,212,.2); }
.nota.vacia::before { background: rgba(232,226,212,.15); box-shadow: none; }
.nota.vacia .nota-num { color: #736c60; }
.nota.final { grid-column: 1 / -1; background: #f1e8d3; font-size: 12px; }
@media (max-width: 560px) { .corcho { grid-template-columns: repeat(2, minmax(0, 1fr)); padding: 12px; } .nota { font-size: 11px; } }

/* El 88-C vacío: una tira, no un corcho. Veintiocho marcas finas dicen
   «esto se colecciona» sin gastar dos pantallas en fichas en blanco. */
.hilo.hilo-tira { margin-bottom: 22px; }
.hilo-tira .tira {
  display: flex; gap: 5px; flex-wrap: wrap; align-items: center;
  padding: 12px 14px; border: 1px solid #3a2e21; border-radius: var(--r);
  background: linear-gradient(180deg, #2a2016, #211a12);
  box-shadow: inset 0 0 24px rgba(0,0,0,.45);
}
.hilo-tira .tira i {
  flex: 1 1 18px; height: 16px;
  border: 1px dashed rgba(232,226,212,.20); border-radius: 2px;
  background: rgba(232,226,212,.05);
}

/* El turno de noche antes de la primera técnica: sólo los nombres. */
.turno-tira { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.turno-tira span {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase;
  padding: 4px 8px; border-radius: 3px;
  color: var(--voz, var(--ink-dim)); border: 1px solid currentColor; opacity: .72;
}


/* La revelación usa la maquinaria de la introducción, con su rótulo. */
.intro.revelacion .intro-num { color: var(--jade); }

/* El aviso de logro: como la línea de una voz, en jade. */
.voz-linea.logro { border-left-color: var(--jade); }
.voz-linea.logro .voz-quien { color: var(--jade); }

/* Insignia de demo en la portada y aviso en el archivo. */
.btn-tienda {
  font-family: var(--mono); font-size: 11px; letter-spacing: .18em; text-transform: uppercase;
  color: var(--bg); background: var(--amber); border: 1px solid var(--amber);
  padding: 7px 14px; border-radius: 3px; text-decoration: none; white-space: nowrap;
  box-shadow: 2px 2px 0 var(--amber-dim); transition: transform .08s ease, box-shadow .08s ease;
}
.btn-tienda:hover { transform: translate(1px, 1px); box-shadow: 1px 1px 0 var(--amber-dim); }
.btn-tienda:active { transform: translate(2px, 2px); box-shadow: none; }
@media (max-width: 720px) { .btn-tienda { font-size: 10px; padding: 6px 9px; letter-spacing: .12em; } }

.demo-sello { font-family: var(--mono); font-size: 10.5px; letter-spacing: .24em; color: var(--amber); border: 1px solid var(--amber-dim); padding: 3px 8px; border-radius: 3px; margin-left: 10px; vertical-align: middle; }
.demo-aviso { margin: 18px 0 0; padding: 14px 16px; border: 1px dashed var(--amber-dim); border-radius: var(--r); color: var(--ink-dim); font-size: 13.5px; }

/* La licencia en Ajustes. */
.ajustes-voz.licencia .ok { color: var(--jade); }
.lic-fila { display: flex; gap: 8px; }
.lic-fila input { flex: 1; min-width: 0; padding: 9px 11px; border-radius: 8px; background: var(--panel); border: 1px solid var(--line); color: var(--ink); font-family: var(--mono); font-size: 12.5px; }
.lic-fila input:focus { outline: none; border-color: var(--amber-dim); }
.ajustes-voz.licencia a.btn { display: inline-block; text-decoration: none; }

/* ---------- consejos de SQL ----------
 *
 * Una tira bajo la barra de atajos, con la voz baja de ARCHIVO: rótulo,
 * una frase y el ejemplo, que se pega en el editor con un toque. */
.consejo {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 10px;
  padding: 9px 12px 9px 14px; border-top: 1px solid var(--line-soft);
  border-left: 3px solid var(--amber-dim); background: rgba(216,162,74,.06);
  font-size: 13px; line-height: 1.5; color: var(--ink-dim); animation: aparece .25s ease;
}
.consejo b { font-family: var(--mono); font-size: 10.5px; letter-spacing: .14em; color: var(--amber); }
.consejo-texto { flex: 1 1 28ch; color: var(--ink); }
.consejo-ej {
  flex: 1 1 100%; text-align: left; cursor: pointer; background: var(--panel-2);
  border: 1px dashed var(--line); border-radius: 6px; padding: 5px 9px; color: var(--ink-dim); font-size: 12px;
}
.consejo-ej code { font-family: var(--mono); white-space: pre-wrap; background: none; padding: 0; }
.consejo-ej:hover { border-color: var(--amber-dim); color: var(--ink); }
.consejo-x { margin-left: auto; background: none; border: 0; color: var(--ink-faint); cursor: pointer; font-size: 13px; padding: 0 2px; }
.consejo-x:hover { color: var(--ink); }

/* ---------- caso cerrado: el siguiente paso, bajo el veredicto ---------- */
.caso-cerrado {
  margin-top: 14px; padding-top: 14px; border-top: 1px dashed var(--line);
  display: flex; flex-direction: column; gap: 8px; animation: aparece .35s ease;
}
/* Los dos eventos que costaban algo y no se veían.
 *
 * Una pista baja el rango al resolver: aparecía de golpe, igual que cualquier
 * otro párrafo, y no se leía como un precio pagado. Y la evidencia fijada
 * aterriza en el tablero, que en pantalla ancha está en otra columna: sin un
 * destello no se ve de dónde salió lo que acaba de llegar.
 *
 * Ninguna de las dos mueve nada de sitio ni retrasa al jugador: se despliegan
 * donde ya estaban, en menos de un segundo, y desaparecen. */
@keyframes pista-abre {
  from { opacity: 0; transform: translateY(-6px); clip-path: inset(0 0 100% 0); }
  to   { opacity: 1; transform: none;             clip-path: inset(0 0 0 0); }
}
.hint.nueva { animation: pista-abre .42s cubic-bezier(.2, .9, .3, 1) both; }

@keyframes evid-fijar {
  0%   { box-shadow: 0 0 0 2px var(--amber); }
  70%  { box-shadow: 0 0 0 2px var(--amber); }
  100% { box-shadow: 0 0 0 0 transparent; }
}
.evid.nueva { animation: evid-fijar .9s ease-out both; }

/* Ni con el ahorro de batería ni con el sistema pidiendo menos movimiento. */
html.ahorro .hint.nueva, html.ahorro .evid.nueva { animation: none; }
@media (prefers-reduced-motion: reduce) {
  .hint.nueva, .evid.nueva { animation: none; }
}

/* El expediente del jugador, dentro del manual. Una lista sobria: la técnica,
   el veredicto y las cifras que lo sostienen. El color sólo marca el estado,
   y «en prueba» va en gris a propósito — no es ni bueno ni malo, es que aún
   no se sabe. */
/* Las pestañas del modal. Tres pisos de información que antes venían
   apilados: el manual, el expediente y los ajustes. */
.modal-tabs { display: flex; gap: 2px; margin: 0 0 18px; border-bottom: 1px solid var(--line); }
.modal-tabs button {
  appearance: none; background: none; border: 0; border-bottom: 2px solid transparent;
  padding: 9px 14px; margin-bottom: -1px; cursor: pointer;
  font-family: var(--mono); font-size: 11.5px; letter-spacing: .16em; text-transform: uppercase;
  color: var(--ink-faint);
}
.modal-tabs button:hover { color: var(--ink-dim); }
.modal-tabs button[aria-selected="true"] { color: var(--amber); border-bottom-color: var(--amber); }
.modal-tabs button:focus-visible { outline: 2px solid var(--amber); outline-offset: 2px; }
.modal-panel[hidden] { display: none !important; }

.expediente { margin: 0 0 22px; padding: 16px 18px; border: 1px solid var(--line); border-radius: var(--r); background: var(--panel); }
.expediente h3 { margin: 0 0 6px; font-family: var(--display); font-size: 20px; letter-spacing: .01em; }
.expediente-nota { margin: 0 0 14px; font-size: 13px; color: var(--ink-faint); max-width: 62ch; }
/* ---------- logros ---------- */
.logros-cuenta { margin: 0 0 12px; font-family: var(--mono); font-size: 11px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--amber); }
.logros-lista { display: grid; gap: 2px; }
.logro-fila {
  display: grid; grid-template-columns: 18px minmax(0, 13rem) minmax(0, 1fr); align-items: baseline;
  gap: 4px 12px; padding: 9px 10px; border-radius: var(--r); border-left: 2px solid var(--line);
}
.logro-fila.ganado { border-left-color: var(--amber); background: rgba(226,177,90,.05); }
.logro-marca { color: var(--ink-faint); font-size: 11px; }
.logro-fila.ganado .logro-marca { color: var(--amber); }
.logro-nombre { font-family: var(--serif); font-size: 15px; color: var(--ink-dim); }
.logro-fila.ganado .logro-nombre { color: var(--ink); font-weight: 600; }
.logro-nota { font-size: 13px; color: var(--ink-faint); line-height: 1.45; }
@media (max-width: 560px) {
  .logro-fila { grid-template-columns: 18px minmax(0, 1fr); }
  .logro-nota { grid-column: 2; }
}

.expediente-vacio { margin: 0; padding: 14px 16px; font-family: var(--serif); font-style: italic;
  font-size: 14px; color: var(--ink-dim); border-left: 2px solid var(--line); background: var(--panel-2); border-radius: 0 var(--r) var(--r) 0; }
.expediente-lista { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.expediente-lista li { display: grid; grid-template-columns: 1fr auto auto; gap: 12px; align-items: baseline;
  padding: 6px 0; border-bottom: 1px solid var(--line-soft); }
.expediente-lista li:last-child { border-bottom: 0; }
.exp-tecnica { font-family: var(--mono); font-size: 12.5px; color: var(--ink); }
.exp-veredicto { font-family: var(--mono); font-size: 11px; letter-spacing: .14em; text-transform: uppercase; }
.exp-cifras { font-family: var(--mono); font-size: 11.5px; color: var(--ink-faint); font-variant-numeric: tabular-nums; }
.exp-firme    .exp-veredicto { color: var(--jade); }
.exp-flojo    .exp-veredicto { color: var(--red-claro); }
.exp-mezcla   .exp-veredicto { color: var(--amber); }
.exp-oxidado  .exp-veredicto { color: var(--violet); }
.exp-en-prueba .exp-veredicto { color: var(--ink-faint); }

.cerrado-marca {
  margin: 2px 0 14px; font-family: var(--mono); font-size: 12px; letter-spacing: .08em;
  color: var(--ink-dim); font-variant-numeric: tabular-nums;
}

.cerrado-rotulo { margin: 0 0 2px; font-family: var(--mono); font-size: 10.5px; letter-spacing: .16em; text-transform: uppercase; color: var(--jade); }
.caso-cerrado .btn { display: block; text-decoration: none; text-align: center; }
.caso-cerrado .cerrado-siguiente { display: flex; flex-direction: column; align-items: center; gap: 3px; padding: 11px 14px; }
.cerrado-siguiente span { font-family: var(--mono); font-size: 10.5px; letter-spacing: .14em; text-transform: uppercase; opacity: .75; }
.cerrado-siguiente b { font-family: var(--serif); font-size: 15px; font-weight: 500; }
.cerrado-fin { margin: 0; font-size: 13px; color: var(--ink-faint); font-style: italic; }
.cerrado-vuelve { margin: 4px 0 0; font-size: 13px; color: var(--ink-dim); }
.cerrado-vuelve a { color: var(--amber); white-space: nowrap; }

/* ---------- réplicas del coach y acciones de una voz ---------- */
.coach-replica {
  margin: 10px 0 2px; padding: 8px 0 0; border-top: 1px dashed var(--line);
  color: var(--ink);
}
.coach-replica .coach-voz { display: block; margin-bottom: 3px; }
.coach-replica p { margin: 0; font-family: var(--serif); font-size: 14px; line-height: 1.45; color: var(--ink); }
.coach-replica.entra { animation: aparece .3s ease; }
.voz-acciones { display: flex; gap: 8px; margin-top: 10px; }
.voz-acciones .btn { padding: 7px 12px; font-size: 13px; }
.cerrado-teaser { margin: 0; font-family: var(--serif); font-style: italic; font-size: 13.5px; line-height: 1.45; color: var(--ink-dim); }

/* ---------- pestañas, no barras ----------
 *
 * Las voces, los consejos y las pistas llevaban una barra de color a la
 * izquierda. Es el rasgo más reconocible de las interfaces hechas en serie;
 * aquí todo son carpetas, y una carpeta se distingue por su pestaña. La voz
 * va en una pestaña que asoma por el borde superior, con su color de fondo y
 * tinta oscura, como el rótulo de un archivador. */
.coach, .voz-linea {
  border-left: 1px solid var(--line); border-radius: 4px 10px 10px 10px;
  padding-left: 14px; padding-top: 16px; overflow: visible;
}
.coach-cab, .voz-cab { position: static; }
.coach-voz, .voz-linea .voz-quien {
  position: absolute; top: -11px; left: 12px; z-index: 1;
  background: var(--voz, var(--amber)); color: #0c0e12;
  padding: 4px 9px 3px; border-radius: 3px 3px 0 0; font-weight: 700; letter-spacing: .18em;
  box-shadow: 0 -2px 0 rgba(0,0,0,.25) inset;
}
.coach-replica .coach-voz { position: static; display: inline-block; margin-bottom: 4px; padding: 2px 7px 1px; border-radius: 3px; font-size: 9.5px; }
.voz-linea.logro { border-left-color: var(--line); --voz: var(--jade); }
.consejo, .olfato, .error .fix.archivo, .solution-body blockquote {
  border-left: 0; border-radius: 8px; background: rgba(255,255,255,.025);
  border: 1px solid var(--line-soft); padding-left: 14px;
}
.consejo { border-radius: 0; border-width: 1px 0 0; }
.consejo b, .olfato b, .error .fix.archivo b {
  background: var(--amber); color: #0c0e12; padding: 2px 7px 1px; border-radius: 3px;
  font-weight: 700; letter-spacing: .16em; font-size: 9.5px;
}
.hint { border-left: 1px solid var(--line); border-radius: var(--r); border-top: 3px solid var(--accent); }
.patron { border-left: 1px solid var(--line-soft); border-top: 3px solid var(--accent); }
.patron.cerrado { border-top-color: var(--line); border-left-color: var(--line-soft); }
.intro-viñeta.con-voz { border-left: 0; padding-left: 0; }
.intro-viñeta.con-voz .v-nombre {
  background: var(--voz, var(--amber)); color: #0c0e12; padding: 3px 9px 2px; border-radius: 3px;
  display: inline-block; margin-bottom: 8px; letter-spacing: .18em; font-weight: 700;
}

/* ---------- el expediente del día ---------- */
.diario { margin: 18px 0 6px; }
.diario-carpeta {
  position: relative; width: 100%; text-align: left; cursor: pointer;
  display: grid; grid-template-columns: 1fr auto; gap: 14px 22px; align-items: center;
  padding: 26px 18px 16px 18px; border-radius: 4px 10px 10px 10px;
  background: linear-gradient(180deg, rgba(216,162,74,.10), rgba(216,162,74,.03)), var(--panel);
  border: 1px solid var(--amber-dim); color: var(--ink);
  transition: transform .12s, border-color .12s;
}
.diario-carpeta:hover { transform: translateY(-1px); border-color: var(--amber); }
.diario-carpeta .pestana { color: var(--amber); background: var(--panel); border-color: var(--amber-dim); }
.diario-carpeta.estado-resuelto { border-color: var(--jade); }
.diario-carpeta.estado-resuelto .pestana { color: var(--jade); border-color: var(--jade); }
.diario-texto h3 { font-family: var(--serif); font-size: 19px; font-weight: 600; margin: 4px 0 2px; }
.diario-texto .lema { margin: 0 0 6px; font-family: var(--serif); font-style: italic; color: var(--ink-dim); font-size: 14px; }
.frios { margin-top: 12px; }
.frios-cabecera { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 8px; }
.frios-titulo { font-family: var(--mono); font-size: 11px; letter-spacing: .16em; text-transform: uppercase; color: var(--ink-dim); }
.frios-quedan { font-family: var(--mono); font-size: 11px; color: var(--ink-faint); }
.frios-fichas { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 8px; margin-bottom: 8px; }
.frio {
  display: grid; grid-template-columns: 1fr auto; gap: 2px 10px; align-items: baseline; text-align: left;
  padding: 10px 12px; background: var(--panel); border: 1px dashed var(--line); border-radius: var(--r);
  color: var(--ink); cursor: pointer; transition: border-color .15s ease, transform .15s ease;
}
.frio:hover { border-color: var(--amber-dim); transform: translateY(-1px); }
.frio-fecha { font-family: var(--mono); font-size: 11px; color: var(--ink-faint); }
.frio .dificultad { font-size: 10px; justify-self: end; }
.frio-titulo { font-family: var(--serif); font-size: 15px; }
.frio-ir { font-family: var(--mono); font-size: 11px; color: var(--amber); justify-self: end; }
.frio.estado-en_curso { border-style: solid; }
.diario-nota { margin: 0; font-size: 12.5px; color: var(--ink-faint); line-height: 1.5; max-width: 60ch; }
.diario-lado { display: flex; flex-direction: column; align-items: flex-end; gap: 4px; }
.diario-racha { font-family: var(--mono); font-size: 12px; letter-spacing: .08em; color: var(--amber); }
.diario-total { font-family: var(--mono); font-size: 10.5px; color: var(--ink-faint); margin-bottom: 6px; }
.diario-lado .btn { pointer-events: none; }
@media (max-width: 640px) {
  .diario-carpeta { grid-template-columns: 1fr; }
  .diario-lado { flex-direction: row; align-items: center; flex-wrap: wrap; justify-content: space-between; }
}

/* ---------- identidad: cartel, periódico, máquina de escribir ----------
 *
 * Titulares condensados en mayúsculas (cartel de comisaría), cuerpo de
 * periódico, rótulos y datos a máquina. Bordes rectos, grano de papel sobre
 * todo, botones con sombra dura de imprenta y nada de cristal esmerilado. */
.brand-text strong { font-family: var(--display); font-weight: 700; font-size: 21px; letter-spacing: .03em; text-transform: uppercase; }
.activo h2, .cajon h2, .cel-caja h2, .modal-head h2, .hilo-cab h2, .diario-texto h3, .archivo-cerrado h2 {
  font-family: var(--display); font-weight: 800; text-transform: uppercase; letter-spacing: .015em; line-height: .96; text-wrap: balance;
}
.activo h2 { font-size: clamp(36px, 4.8vw, 58px); font-weight: 900; }
.cajon h2 { font-size: 30px; }
.cel-caja h2 { font-size: 34px; }
.diario-texto h3 { font-size: 26px; }
.titulo-nombre { font-family: var(--display); font-weight: 900; text-transform: uppercase; letter-spacing: 0; line-height: .86; font-size: clamp(66px, 13.5vw, 156px); }
.titulo-nombre em { font-style: normal; color: var(--amber); }
.titulo-nombre span { font-family: var(--mono); font-weight: 700; letter-spacing: .12em; font-size: .17em; }
.cel-sello-texto { font-family: var(--display); font-weight: 900; letter-spacing: .04em; }
.dossier h2 { font-family: var(--serif); font-weight: 600; font-size: 27px; letter-spacing: -.005em; }
.carpeta h3 { font-family: var(--serif); font-weight: 600; }

/* Rótulos a máquina: menos aire entre letras que un tablero de mandos. */
.zona-rotulo, .ficha-sobre, .pestana, .sello, .coach-voz, .voz-quien, .voz-nombre, .cerrado-rotulo, .solution h3, .hint h4,
.hechos-cuenta, .results-bar, .run-meta, .coach-paso, .voz-sobre, .cajon-num, .activo-sobre, .hero-stat span, .stat, .consejo b, .olfato b, .error .fix.archivo b,
.cerrado-siguiente span, .diario-racha, .diario-total, .intro-num, .cel-etiqueta, .estado-sello, .nav-locked, .case-nav {
  letter-spacing: .07em;
}
.pestana, .sello { font-weight: 700; }

/* Botones: etiqueta a máquina, sombra dura. */
.btn { font-family: var(--mono); font-weight: 700; text-transform: uppercase; letter-spacing: .05em; font-size: 12px; border-radius: 3px; }
.btn-primary { background: var(--amber); color: #16110a; border: 1px solid #0b0906; box-shadow: 2px 2px 0 #060504; }
/* Naranja cableado: en las temporadas 2 y 3 `--amber` es jade o violeta, y
   el botón más pulsado del juego parpadeaba a naranja al pasar el ratón. */
.btn-primary:hover { filter: none; background: #eebd66; }
@supports (background: color-mix(in srgb, red 50%, white)) {
  .btn-primary:hover { background: color-mix(in srgb, var(--amber) 86%, #fff); }
}
.btn-primary:active { transform: translate(1px, 1px); box-shadow: 1px 1px 0 #060504; }
.btn-ghost { border: 1px solid var(--line); background: transparent; }
.btn-ghost:hover { border-color: var(--amber-dim); background: rgba(226,177,90,.06); }
@supports (background: color-mix(in srgb, red 50%, white)) {
  .btn-ghost:hover { background: color-mix(in srgb, var(--amber) 8%, transparent); }
}
.btn-primary:disabled, .btn-primary[disabled] { box-shadow: none; opacity: .45; }

/* Sin cristal: los paneles flotantes son opacos, como una ficha sobre otra. */
.coach, .voz-linea, .tabbar, .topbar, .consejo, .modal, .toast { backdrop-filter: none; -webkit-backdrop-filter: none; }
.coach, .voz-linea { background: #1a1713; box-shadow: 4px 4px 0 #070605, 0 18px 40px rgba(0,0,0,.5); }
.accuse, .hint, .solution, .patron, .ajustes-voz, .diario-carpeta, .cel-caja { border-radius: var(--r); }

/* La consola escribe a máquina. */
.editor .cm-scroller, .editor .cm-content { font-family: var(--mono) !important; font-size: 14px; line-height: 1.5; }
.results table { font-family: var(--mono); font-size: 13px; }

/* Grano de papel sobre todo, muy leve. */
body::after {
  content: ""; position: fixed; inset: 0; pointer-events: none; z-index: 2000; opacity: .07;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 .9 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E");
  background-size: 180px 180px; mix-blend-mode: overlay;
}
html.ahorro body::after { display: none; }

/* ---------- la placa: el turno de noche como mapa de técnicas ---------- */
.turno-nota { margin: 4px 0 10px; font-size: 12.5px; line-height: 1.5; color: var(--ink-dim); }
.voces-ficha { gap: 9px; }
.voz-fila { display: block; }
.voz-cab-fila { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.voz-nombre { font-family: var(--mono); font-size: 10.5px; font-weight: 700; color: var(--voz, var(--amber)); }
.voz-fila em { font-style: normal; font-family: var(--mono); font-size: 10px; letter-spacing: .04em; color: var(--ink-faint); text-align: right; }
.voz-fila.afilada em { color: var(--voz); }
.voz-tecnicas { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }
.voz-tecnicas span {
  font-family: var(--mono); font-size: 10px; padding: 1px 6px; border-radius: 2px;
  border: 1px dashed var(--line); color: var(--ink-faint);
}
.voz-tecnicas span.on { border-style: solid; border-color: var(--voz); color: var(--voz); background: color-mix(in srgb, var(--voz) 14%, transparent); }

/* ---------- escala de lectura ----------
 *
 * En un portátil de 13 pulgadas los rótulos de 10 px y el cuerpo de 14 se
 * leen con esfuerzo, y la máquina de escribir tiene la x baja: todo sube un
 * punto o dos. El móvil sube menos: allí el sitio manda. */
.brand-text span { font-size: 12px; }
/* `.accuse h3` está fuera de esta lista a propósito: 600 líneas antes se
   declara como título serif de 18 px y esta capa lo devolvía a 12, más
   pequeño que las etiquetas del propio panel que encabeza. */
.zona-rotulo, .ficha-sobre, .cerrado-rotulo, .solution h3, .hint h4, .activo-sobre, .cajon-num, .intro-num, .cel-etiqueta, .hechos-cuenta { font-size: 12px; }
.pestana, .sello { font-size: 11.5px; }
.coach-voz, .voz-linea .voz-quien { font-size: 11px; }
.coach-texto, .voz-texto { font-size: 16.5px; }
.coach-replica p { font-size: 15.5px; }
.coach-acciones .btn, .voz-acciones .btn { font-size: 12.5px; }
.turno-nota { font-size: 14px; }
.voz-nombre { font-size: 12px; }
.voz-fila em { font-size: 11.5px; }
.voz-tecnicas span { font-size: 11.5px; padding: 2px 7px; }
.hero-stat b { font-size: 24px; }
.hero-stat span { font-size: 12px; }
.rango-cab strong { font-size: 24px; }
.rango-cab span { font-size: 14px; }
.tokenbar button { font-size: 12.5px; height: 29px; padding: 0 11px; }
.tokenbar { max-height: calc(8px + 29px * 2 + 6px + 8px); }
.btn { font-size: 13px; }
.btn-quiet { font-size: 12.5px; }
.editor .cm-scroller, .editor .cm-content { font-size: 15px; }
.results table { font-size: 14px; }
.results-bar, .run-meta, .history summary, .stat, .case-nav { font-size: 12.5px; }
.results-empty { font-size: 15px; }
.dossier h2 { font-size: 29px; }
.dossier-tagline { font-size: 16.5px; }
.dossier-body { font-size: 16.5px; }
.objective p { font-size: 17px; }
.hint-body { font-size: 15.5px; }
.solution-body { font-size: 15.5px; }
.epilogue { font-size: 15.5px; }
.field label { font-size: 13.5px; }
.field input { font-size: 15.5px; }
.prueba-nota { font-size: 13.5px; }
.verdict { font-size: 15px; }
.consejo { font-size: 14px; }
.consejo-ej { font-size: 13px; }
.olfato { font-size: 14.5px; }
.error pre { font-size: 13.5px; }
.error strong { font-size: 14px; }
.error .fix.archivo span, .error .fix { font-size: 14px; }
.evid code { font-size: 14px; }
.evid .de { font-size: 11.5px; }
.evid .usos button { font-size: 12px; }
.col .cname { font-size: 13.5px; }
.col .ctype { font-size: 11.5px; }
.col .ccomment { font-size: 12.5px; }
.carpeta h3 { font-size: 18px; }
.carpeta .lema { font-size: 14px; }
.chip { font-size: 11.5px; }
.diario-nota { font-size: 14px; }
.diario-racha { font-size: 13px; }
.diario-total { font-size: 12px; }
.cerrado-teaser, .cerrado-fin { font-size: 14.5px; }
.cerrado-siguiente b { font-size: 17px; }
.ajustes-nota { font-size: 13.5px; }
.ajuste { font-size: 14px; }
.vacio-chip { font-size: 13px; }
@media (max-width: 860px) {
  .tokenbar button { font-size: 12px; height: 28px; }
  .tokenbar { max-height: calc(8px + 28px * 2 + 6px + 8px); }
  .dossier-body { font-size: 16px; }
  .editor .cm-scroller, .editor .cm-content { font-size: 14.5px; }
}

/* ---------- consecuencias, progreso y ajustes nuevos ---------- */
.consecuencia { margin: 12px 0 14px; padding: 10px 14px; border: 1px solid var(--line-soft); border-radius: 6px; font-family: var(--serif); font-size: 15px; line-height: 1.5; color: var(--ink-dim); }
.consecuencia b { font-family: var(--mono); font-size: 9.5px; letter-spacing: .16em; background: #c9a227; color: #0c0e12; padding: 2px 7px 1px; border-radius: 3px; margin-right: 8px; font-weight: 700; }
.ajuste-progreso { align-items: flex-start; }
.ajuste-botones { display: flex; gap: 8px; flex-wrap: wrap; }
#prog-pegar { display: grid; gap: 8px; margin: 6px 0 4px; }
#prog-texto { width: 100%; font-family: var(--mono); font-size: 12px; background: var(--bg); color: var(--ink); border: 1px solid var(--line); border-radius: 6px; padding: 8px; resize: vertical; }

/* ---------- aviso de copyright ---------- */
.titulo-cargando {
  margin: 18px 0 0; font-family: var(--mono); font-size: 12px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--ink-faint);
}
.titulo-btn[disabled] { opacity: .45; cursor: default; }

.titulo-copyright {
  position: absolute; left: 24px; bottom: calc(14px + var(--safe-b)); margin: 0; z-index: 3;
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .06em; color: var(--ink-faint); opacity: .85;
}
@media (max-width: 640px) { .titulo-copyright { left: 16px; bottom: calc(52px + var(--safe-b)); } }
.modal-pie { margin: 18px 0 0; padding-top: 12px; border-top: 1px solid var(--line-soft); font-size: 11.5px; line-height: 1.5; color: var(--ink-faint); }

/* La vitrina de la demo: carpetas selladas que llevan a la tienda. Son
   enlaces, no botones deshabilitados: se pueden pulsar. */
.carpeta.vitrina { cursor: pointer; text-decoration: none; }
.carpeta.vitrina:hover { border-color: var(--amber-dim); }
.carpeta.vitrina .sello { color: var(--amber-dim); }
a.titulo-btn { text-decoration: none; display: inline-block; }
/* La marca de la barra es el camino de vuelta a la portada. */
a.brand { color: inherit; text-decoration: none; border-radius: 4px; }
a.brand:hover .brand-mark { border-color: var(--amber); }
a.brand:focus-visible { outline: 2px solid var(--paper); outline-offset: 3px; }
/* Los enlaces a la web (sólo en el gancho): discretos, debajo del menú. */
.titulo-sitio { display: flex; flex-wrap: wrap; gap: 8px 18px; margin: 18px 0 0; font-family: var(--mono); font-size: 12px; letter-spacing: .06em; }
.titulo-sitio a { color: var(--ink-dim); text-decoration: none; border-bottom: 1px solid var(--line); padding-bottom: 2px; }
.titulo-sitio a:hover, .titulo-sitio a:focus-visible { color: var(--amber); border-color: var(--amber); }
