/* Catalogo de C&M — hoja de estilo
   ================================
   EL REDISENO, FASE 1 (24-09-2026): fondo negro, letras de GPC y las
   fichas con sus efectos suaves. Lo aprobo el dueno sobre el plan dibujado
   (bitacora/plan/, decisiones.md del 24-09): de ahi se porta el CSS, no se
   reinventa. Lo que manda, y por que:

   1. NEGRO PURO. Lo pidio el: la version con azules hondos le parecio
      plana. Las superficies son casi negras (--papel, --papel-alto) para
      que la ficha se despegue del fondo sin parecer una caja.

   2. EL AZUL ES EL DE GPC, #1155f4 tal cual (23-09-2026): las dos empresas
      se tienen que ver hermanas. Da 3,6:1 sobre negro, asi que solo va en
      titulos grandes y trazos (WCAG pide 3:1 ahi). El texto azul pequeno va
      en --acento-tinta (#3b7bff, 5,5:1) y los rotulos finos en --acento-luz.

   3. LAS LETRAS SON LAS DE GPC, Barlow Condensed e IBM Plex Mono, incrus-
      tadas en letras.css (scripts/sacar_letras.py). Solo hay tres pesos: la
      condensada a 600 y 700 y la mono a 600. Pedir 900 da 700 y pedir 400 da
      600: NO se "arregla" anadiendo pesos, cada uno son 30 KB mas.

   4. EL MOVIMIENTO ES "MEDIO" (lo recomendado; el no dijo otra cosa): las
      fichas solo se mueven al pasar el dedo o el raton. Todo es CSS y todo se
      para con "reducir movimiento" (al final de la hoja). Sin JavaScript se
      ve todo, quieto pero entero.

   5. NO HAY PLATO BLANCO: las fotos salen de procesar_fotos.py con
      transparencia y la pieza va directa sobre el negro.

   6. NO HAY NADA DE COMERCIO (regla 5). Donde iria "comprar" va WhatsApp.
*/

:root{
  /* --- el azul de GPC. Cambiar SOLO aqui --- */
  --acento:#1155f4;        /*  3.6:1 sobre negro — trazos y titulos grandes */
  --acento-tinta:#3b7bff;  /*  5.5:1 sobre negro, 4.6:1 sobre --papel-alto  */
  --acento-luz:#8fb3ff;    /* 10.1:1 — rotulos finos                        */
  --acento-fondo:rgba(17,85,244,.16); /* relleno de lo elegido              */

  /* --- tinta y superficies: negro --- */
  --tinta:#eef2f8;         /* 18.7:1 sobre --fondo                          */
  --tinta-suave:#cfd6e2;   /* 14.4:1                                        */
  --tinta-3:#9aa3b2;       /*  8.3:1 sobre --fondo, 7.0:1 sobre --papel-alto */
  --fondo:#000;
  --papel:#0e1016;         /* la ficha: grafito, apenas despegada del negro */
  --papel-bajo:#07080b;    /* el pie de la ficha, el degradado              */
  --papel-alto:#141824;    /* la ficha al pasar por encima                  */
  --chapa:rgba(0,0,0,.78); /* cabecera: negro que deja ver lo que pasa     */
  --linea:#1b1f29;
  --linea-suave:#13161e;
  --verde:#25d366;         /* el de WhatsApp, que la gente reconoce       */
  --verde-tinta:#7ef0a8;   /* 14.9:1 — para texto verde sobre negro       */
  --rojo:#fa0006;          /* el de GPC: solo el sello de los juegos IZUMI */

  --ui: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --disp: "CM Condensada", "Arial Narrow", "Roboto Condensed", sans-serif-condensed, var(--ui);
  --mono: "CM Mono", ui-monospace, "SF Mono", "Cascadia Mono", "Roboto Mono", Menlo, Consolas, monospace;

  /* la curva de todo lo que se mueve: sale rapido y frena suave */
  --suave:cubic-bezier(.2,.7,.1,1);

  color-scheme: dark;
}

*{ box-sizing:border-box; }

html{ -webkit-text-size-adjust:100%; }

body{
  margin:0;
  background:var(--fondo);
  color:var(--tinta);
  font:400 16px/1.5 var(--ui);
}
:focus-visible{ outline:2px solid var(--acento-tinta); outline-offset:3px; }

/* ===================== CABECERA ===================== */

.tope{
  position:sticky; top:0; z-index:40;
  background:var(--chapa);
  /* Negro que deja ver, borroso, lo que pasa por debajo: asi la cabecera
     se lee como un cristal encima del catalogo y no como un tapon. */
  -webkit-backdrop-filter:blur(14px); backdrop-filter:blur(14px);
  border-bottom:1px solid var(--linea);
  padding:10px 16px 12px;
}
.topeFila{
  display:flex; align-items:center; justify-content:space-between;
  gap:12px; margin-bottom:10px;
}
.marca{ display:flex; align-items:center; gap:10px; min-width:0; }
.marcaSigla{
  font:900 20px/1 var(--disp); letter-spacing:.02em;
  background:var(--tinta); color:var(--fondo);
  padding:7px 9px; border-radius:5px; flex:none;
}
.marcaTexto{ display:flex; flex-direction:column; min-width:0; }
.marcaTexto b{
  font:700 14px/1.15 var(--disp); letter-spacing:.04em;
  text-transform:uppercase; color:var(--tinta);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.marcaTexto i{
  font:400 10px/1.4 var(--mono); font-style:normal;
  letter-spacing:.1em; color:var(--tinta-3);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
/* En el telefono el nombre largo y el RIF no caben, y salian cortados con
   puntos suspensivos, que es peor que no ponerlos: "GRUPO C&M PART…" no
   dice nada. El RIF se va al pie, donde tiene que estar de todas formas, y
   el nombre se encoge hasta caber entero. */
@media (max-width:519px){
  .marcaTexto i{ display:none; }
  .marcaTexto b{ font-size:13px; white-space:normal; line-height:1.1; }
  .marcaSigla{ font-size:17px; padding:6px 8px; }
  .topeWaNumero{ font-size:12px; }
}

/* El WhatsApp de la cabecera: es la unica forma de pedir, asi que esta
   siempre a la vista y cumple los 44px de zona de toque. */
.topeWa{
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:1px; flex:none; min-height:44px; padding:5px 12px;
  border:1px solid var(--verde); border-radius:8px;
  text-decoration:none; background:rgba(37,211,102,.08);
}
.topeWaEtiqueta{
  display:flex; align-items:center; gap:5px;
  font:600 9px/1 var(--mono); letter-spacing:.14em; color:var(--verde-tinta);
}
.topeWaEtiqueta::before{ width:6px; height:6px; }
.topeWaNumero{
  font:700 13px/1.2 var(--disp); letter-spacing:.02em; color:var(--tinta);
  white-space:nowrap;
}

.busca{ position:relative; display:block; }
.buscaLupa{
  position:absolute; left:15px; top:50%; width:17px; height:17px;
  margin-top:-8px; pointer-events:none;
  border:2px solid var(--acento); border-radius:50%;
}
.buscaLupa::after{
  content:""; position:absolute; right:-6px; bottom:-5px;
  width:8px; height:2px; background:var(--acento);
  transform:rotate(45deg); border-radius:2px;
}
#busca{
  width:100%; min-height:50px; padding:12px 46px 12px 44px;
  background:var(--papel); color:var(--tinta);
  border:1px solid var(--linea); border-radius:10px;
  font:400 16px/1.3 var(--ui); /* 16px o iOS hace zoom al enfocar */
}
#busca::placeholder{ color:var(--tinta-3); }
/* Chrome le pone su propia X a los <input type="search">, encima de la
   nuestra: salian dos botones de borrar pegados, uno al lado del otro. La
   nuestra se queda porque es la que respeta los 44 px de zona de toque y la
   que sabe vaciar tambien el filtro; la del navegador se va. */
#busca::-webkit-search-cancel-button,
#busca::-webkit-search-decoration{ -webkit-appearance:none; appearance:none; }
#busca:focus{ outline:2px solid var(--acento); outline-offset:1px; }
.buscaLimpia{
  position:absolute; right:6px; top:50%; transform:translateY(-50%);
  width:38px; height:38px; border:0; border-radius:8px;
  background:transparent; color:var(--tinta-suave);
  font:400 24px/1 var(--ui); cursor:pointer;
}
.buscaLimpia:hover{ background:var(--papel-alto); color:var(--tinta); }

/* Cinta de aviso del numero de pruebas. Va en rojo y arriba del todo a
   proposito: es lo unico de esta pagina que, si se olvida, manda a los
   clientes a un telefono que no atiende. */
.avisoPruebas{
  margin:0; padding:11px 16px;
  background:#2b0d0f; border-bottom:1px solid #7d2c31;
  color:#ff9ba0; font:700 13px/1.45 var(--ui);
}
.avisoPruebas b{ color:#ffd2d4; }

/* ===================== LA PORTADA: SHOWROOM ===================== */

/* Fase 2 del rediseno, portada del plan (bitacora/plan/, clases .escenario y
   .diapo). La pieza como un coche en una presentacion: sola, sobre negro,
   bajo un foco, flotando sobre su reflejo, y detras el nombre de la familia
   enorme y en azul. Cada cinco segundos entra la siguiente.

   QUIETA SIN JAVASCRIPT. Todo lo que se mueve cuelga de .vivo, que la pone
   app.js solo si no se pidio "reducir movimiento". Sin JS se ve la primera
   pieza entera, con su foco y su reflejo, y nada flota ni late.

   LAS MEDIDAS VAN EN cqw (el ancho del escenario, no el de la pantalla): el
   reflejo tiene que empezar justo donde acaba la pieza, y la pieza mide un
   tanto por ciento del escenario. Con vw el reflejo se despegaba en el
   telefono, donde el escenario no ocupa toda la pantalla. */
.portada{ padding:14px 16px 0; }
.portada[hidden]{ display:none !important; }   /* la trampa de [hidden] */
.escenario{
  --lado:min(46cqw, 380px);
  position:relative; height:600px; overflow:hidden; isolation:isolate;
  container-type:inline-size;
  background:var(--fondo); border:1px solid var(--linea); border-radius:18px;
}
/* el foco: un cono de luz azul que cae desde arriba */
.escenario::before{
  content:""; position:absolute; inset:-20% 10% 30%; z-index:0;
  background:conic-gradient(from 180deg at 50% 0%, transparent 160deg,
    rgba(17,85,244,.38) 175deg, rgba(143,179,255,.28) 180deg,
    rgba(17,85,244,.38) 185deg, transparent 200deg);
  filter:blur(12px);
}
/* el suelo: una reticula que se pierde al fondo */
.escenario::after{
  content:""; position:absolute; left:0; right:0; bottom:0; height:34%; z-index:0;
  background:linear-gradient(transparent, rgba(17,85,244,.10)),
    repeating-linear-gradient(90deg, rgba(59,123,255,.12) 0 1px, transparent 1px 60px);
  transform:perspective(500px) rotateX(62deg); transform-origin:bottom;
  -webkit-mask-image:linear-gradient(transparent, #000 40%);
          mask-image:linear-gradient(transparent, #000 40%);
}
.anillo{
  position:absolute; left:50%; bottom:17%; z-index:1;
  width:min(52cqw, 480px); aspect-ratio:5/1; transform:translateX(-50%);
  border-radius:50%; border:1px solid rgba(59,123,255,.55);
  box-shadow:0 0 30px rgba(17,85,244,.45), inset 0 0 30px rgba(17,85,244,.3);
}
.anillo.b{ width:min(70cqw, 640px); border-color:rgba(59,123,255,.2); }

.escMarca{
  position:absolute; top:22px; left:24px; z-index:3; margin:0;
  font:600 11px/1.3 var(--mono); letter-spacing:.16em; color:var(--tinta-3);
  text-transform:uppercase;
}
.escMarca b{
  display:block; margin-top:4px; color:#fff;
  font:700 20px/1 var(--disp); letter-spacing:.04em;
}

.diapo{ position:absolute; inset:0; z-index:1; opacity:0; transition:opacity .9s ease; }
.diapo.on{ opacity:1; z-index:2; }
.palabra{
  position:absolute; left:50%; top:11%; margin:0; transform:translateX(-50%);
  white-space:nowrap; text-transform:uppercase; letter-spacing:-.01em;
  font:700 clamp(84px, 21cqw, 250px)/.8 var(--disp);
  background:linear-gradient(180deg, var(--acento) 0%, rgba(17,85,244,.15) 85%);
  -webkit-background-clip:text; background-clip:text; color:transparent;
  transition:transform 1.2s var(--suave), letter-spacing 1.2s;
}
.diapo:not(.on) .palabra{ transform:translateX(-50%) scale(1.1); letter-spacing:.06em; }
.pieza, .reflejo{ position:absolute; left:50%; width:var(--lado); }
.pieza{ top:48%; z-index:2; transform:translate(-50%, -50%); }
.reflejo{
  top:calc(48% + var(--lado) / 2); z-index:1;
  transform:translateX(-50%) scaleY(-1); opacity:.18; filter:blur(1.5px);
  -webkit-mask-image:linear-gradient(to top, #000, transparent 45%);
          mask-image:linear-gradient(to top, #000, transparent 45%);
}
.pieza img, .reflejo img{ display:block; width:100%; height:auto; object-fit:contain; }
.pieza img{
  filter:drop-shadow(0 40px 40px rgba(0,0,0,.9)) drop-shadow(0 0 40px rgba(17,85,244,.25));
}
/* con JavaScript, la pieza abre el visor como la foto de una ficha */
.pieza.seAbre{ cursor:zoom-in; border-radius:12px; }

.datosEsc{ position:absolute; left:24px; bottom:26px; z-index:3; max-width:340px; }
.datosEsc .cod{
  margin:0; font:600 14px/1 var(--mono); letter-spacing:.04em;
  color:var(--acento-tinta);
}
.datosEsc h2{
  margin:8px 0 10px; font:700 30px/1 var(--disp); text-transform:uppercase;
  color:#fff;
}
.chips{ display:flex; flex-wrap:wrap; gap:6px; margin:0; }
.chip{
  padding:6px 9px; border-radius:999px; font:600 12px/1 var(--mono);
  border:1px solid rgba(59,123,255,.45); color:var(--acento-luz);
  background:rgba(17,85,244,.12);
}
.diapo .datosEsc > *{ transition:transform .8s var(--suave), opacity .8s; }
.diapo:not(.on) .datosEsc > *{ transform:translateY(20px); opacity:0; }

/* Los mandos: una raya por pieza, la de ahora se va llenando. Cada boton
   mide 44 px de alto aunque la raya sea de 4: el dedo necesita sitio. */
.escPuntos{ position:absolute; right:18px; bottom:14px; z-index:3; display:flex; gap:4px; }
.escPuntos[hidden]{ display:none !important; }  /* la trampa de [hidden] */
.escPuntos button{
  width:50px; height:44px; padding:0; border:0; background:none; cursor:pointer;
  position:relative;
}
.escPuntos button::before, .escPuntos button::after{
  content:""; position:absolute; left:2px; right:2px; top:20px; height:4px;
  border-radius:3px; background:#222733;
}
.escPuntos button::after{ background:var(--acento-tinta); transform:scaleX(0); transform-origin:left; }
.escPuntos button.on::after{ transform:scaleX(1); }

/* --- lo que se mueve: solo con .vivo (JS y sin "reducir movimiento") --- */
.vivo.escenario::before{ animation:respira 6s ease-in-out infinite; }
.vivo .anillo{ animation:pulso 3s ease-in-out infinite; }
.vivo .anillo.b{ animation-delay:1.5s; }
.vivo .pieza{ animation:flota 6s ease-in-out infinite; }
.vivo .reflejo{ animation:flota-r 6s ease-in-out infinite; }
.vivo .escPuntos button.on::after{ transform:scaleX(0); animation:carga 5s linear forwards; }
/* parada (raton encima o foco dentro): la raya se queda donde iba */
.vivo.parada .escPuntos button.on::after{ animation-play-state:paused; }

@keyframes respira{ 0%,100%{ opacity:.75; } 50%{ opacity:1; } }
@keyframes pulso{
  0%,100%{ transform:translateX(-50%) scale(1); opacity:.9; }
  50%{ transform:translateX(-50%) scale(1.06); opacity:.5; }
}
@keyframes flota{
  0%,100%{ transform:translate(-50%,-50%) translateY(0) rotate(-1deg); }
  50%{ transform:translate(-50%,-50%) translateY(-16px) rotate(1deg); }
}
@keyframes flota-r{
  0%,100%{ transform:translateX(-50%) scaleY(-1) translateY(0); }
  50%{ transform:translateX(-50%) scaleY(-1) translateY(16px); }
}
@keyframes carga{ from{ transform:scaleX(0); } to{ transform:scaleX(1); } }

@media (max-width:559px){
  .escenario{ --lado:min(70cqw, 300px); height:540px; border-radius:14px; }
  .pieza{ top:43%; }
  .reflejo{ top:calc(43% + var(--lado) / 2); }
  .escMarca{ top:16px; left:16px; }
  .datosEsc{ left:16px; right:16px; bottom:52px; }
  .datosEsc h2{ font-size:26px; }
  .escPuntos{ right:auto; left:10px; bottom:4px; }
}

/* ===================== EL INDICE: EL MOTOR ===================== */

.indice{ padding:26px 16px 8px; }
.indiceEncima{
  margin:0 0 6px; font:400 11px/1 var(--mono);
  letter-spacing:.18em; color:var(--tinta-3);
}
.indiceTitulo{
  margin:0 0 16px; font:700 46px/.9 var(--disp);
  text-transform:uppercase; color:var(--tinta);
}
.indiceTitulo b{ color:var(--acento); }

.indiceMotores{ display:flex; flex-wrap:wrap; gap:8px; }
.motor{
  display:inline-flex; align-items:baseline; gap:7px;
  min-height:44px; padding:9px 14px;
  background:var(--papel); border:1px solid var(--linea); border-radius:9px;
  color:var(--tinta); cursor:pointer;
  font:700 17px/1.2 var(--disp); letter-spacing:.03em;
}
.motor:hover{ background:var(--papel-alto); border-color:var(--acento); }
.motor b{ font:400 12px/1 var(--mono); color:var(--tinta-3); font-weight:400; }
.motor[aria-pressed="true"]{
  background:var(--acento-fondo); border-color:var(--acento);
  color:var(--acento-tinta);
}
.motor[aria-pressed="true"] b{ color:var(--acento-tinta); }

.verMotores{
  display:inline-flex; align-items:center; min-height:44px; padding:9px 14px;
  background:transparent; color:var(--tinta-suave);
  border:1px dashed var(--linea); border-radius:9px; cursor:pointer;
  font:700 12px/1 var(--mono); letter-spacing:.1em; text-transform:uppercase;
}
.verMotores:hover{ border-color:var(--acento); color:var(--acento-tinta); }

.indiceNota{
  margin:14px 0 0; max-width:62ch;
  font:400 14px/1.55 var(--ui); color:var(--tinta-suave);
}
.indiceNota b{ color:var(--acento-tinta); font-weight:700; }

/* ===================== FAMILIAS ===================== */

.bloque{ padding:26px 16px 8px; }
.bloqueTitulo{
  margin:0 0 12px; font:700 13px/1 var(--mono);
  letter-spacing:.16em; text-transform:uppercase; color:var(--tinta-3);
}
.familias{
  display:grid; gap:8px;
  grid-template-columns:repeat(auto-fill, minmax(150px, 1fr));
}
.familia{
  display:flex; align-items:center; justify-content:space-between; gap:8px;
  min-height:48px; padding:10px 12px; text-align:left;
  background:var(--papel); border:1px solid var(--linea); border-radius:9px;
  color:var(--tinta); cursor:pointer;
  font:700 13px/1.25 var(--disp); letter-spacing:.04em; text-transform:uppercase;
}
.familia:hover{ background:var(--papel-alto); border-color:var(--acento); }
.familia[aria-pressed="true"]{
  background:var(--acento-fondo); border-color:var(--acento);
  color:var(--acento-tinta);
}
.familia span{ font:400 12px/1 var(--mono); color:var(--tinta-3); flex:none; }
.familia[aria-pressed="true"] span{ color:var(--acento-tinta); }

.verTodas{
  display:block; width:100%; min-height:46px; margin-top:8px; padding:12px;
  background:transparent; color:var(--tinta-suave);
  border:1px dashed var(--linea); border-radius:9px; cursor:pointer;
  font:700 12px/1 var(--mono); letter-spacing:.14em; text-transform:uppercase;
}
.verTodas:hover{ border-color:var(--acento); color:var(--acento-tinta); }

/* ===================== LAS FICHAS ===================== */

.resumenFila{
  display:flex; align-items:center; justify-content:space-between;
  gap:12px; flex-wrap:wrap;
}
.quitaFiltro{
  min-height:38px; padding:8px 14px; margin-bottom:12px;
  background:var(--papel); color:var(--tinta-suave);
  border:1px solid var(--linea); border-radius:999px; cursor:pointer;
  font:600 12px/1 var(--mono); letter-spacing:.06em;
}
.quitaFiltro:hover{ border-color:var(--acento); color:var(--tinta); }

/* LOS TRAMOS: una familia, una fila.
   Las 223 fichas iban en una sola rejilla: en el telefono eran 110 renglones
   de dos y no se sabia donde acababan las bombas y empezaban los faros. Ahora
   cada familia es un tramo con su nombre, y en el telefono sus fichas van en
   una FILA QUE SE DESLIZA con el dedo, como en las apps de tiendas: se baja
   de familia en familia y se desliza dentro de la que interesa.

   En pantalla grande no hay dedo, y deslizar de lado con el raton es
   incomodo: alli la fila se abre en rejilla. Y en cualquier pantalla, al
   elegir UNA familia se abre entera en rejilla (clase .unaFamilia, la pone
   app.js): quien la eligio quiere verlas todas, no deslizar.

   Sin JavaScript se ve igual: el HTML ya viene partido en tramos. */
.tramo{ margin:0 0 22px; min-width:0; }
.tramo[hidden]{ display:none !important; }   /* la trampa de [hidden], ver .ficha */
.tramoCab{
  display:flex; align-items:baseline; justify-content:space-between;
  /* Con familias largas ("PISTONES Y PASADORES") y la pista de deslizar, a
     320 px no caben en un renglon y se salian de la pantalla: la cuenta
     baja a otro. */
  flex-wrap:wrap; gap:4px 12px;
  padding-top:14px; border-top:1px solid var(--linea);
}
.tramoTitulo{
  margin:0; font:700 25px/1 var(--disp); letter-spacing:.02em;
  text-transform:uppercase; color:var(--acento-tinta);
}
.tramoCuenta{
  flex:none; font:600 11px/1 var(--mono); letter-spacing:.12em;
  text-transform:uppercase; color:var(--tinta-3);
}

.riel{
  display:grid; gap:12px;
  grid-auto-flow:column; grid-auto-columns:minmax(150px, 44%);
  overflow-x:auto; overscroll-behavior-x:contain;
  scroll-snap-type:x mandatory; scroll-padding-inline:16px;
  /* Hasta el borde de la pantalla, para que la ficha que asoma diga "hay
     mas, desliza". El relleno de arriba es el sitio donde la pieza se
     levanta: con overflow-x, lo que sale por arriba se cortaria. */
  margin-inline:-16px; padding:14px 16px 16px;
  scrollbar-width:thin; scrollbar-color:var(--acento) transparent;
}
/* La pista de "desliza", solo donde hay algo que deslizar: tres o mas a la
   vista. Con dos, caben y la pista mentiria. */
.tramo:has(.ficha:not([hidden]) ~ .ficha:not([hidden]) ~ .ficha:not([hidden])) .tramoCuenta::after{
  content:" · desliza →"; color:var(--acento-luz);
}
@media (min-width:760px){
  .riel{
    grid-auto-flow:row; grid-auto-columns:auto;
    grid-template-columns:repeat(auto-fill, minmax(208px, 1fr));
    overflow:visible; margin-inline:0; padding:16px 0 6px; gap:14px;
  }
  .tramoCuenta::after{ content:none !important; }
}
.unaFamilia .riel{
  grid-auto-flow:row; grid-auto-columns:auto;
  grid-template-columns:repeat(auto-fill, minmax(150px, 1fr));
  overflow:visible; margin-inline:0; padding-inline:0;
}
.unaFamilia .tramoCuenta::after{ content:none !important; }
@media (min-width:760px){
  .unaFamilia .riel{ grid-template-columns:repeat(auto-fill, minmax(208px, 1fr)); }
}

/* OJO, ESTO NO ES DECORACION. `display:flex` de aqui abajo GANA a la regla
   del navegador que esconde lo que lleva el atributo `hidden`, asi que el
   filtro contaba bien -"80 piezas · motor 4HG1"- y no escondia nada: se
   seguian viendo las 316. Se vio filtrando por 4HG1 y mirando la pantalla;
   ninguna comprobacion de las que hay lo habria cazado. Cualquier regla que
   ponga `display` a una ficha tiene que repetir esta linea. */
.ficha[hidden]{ display:none !important; }

/* LA FICHA, con los efectos suaves del plan: al pasar por encima la ficha
   se levanta, se enciende el borde azul, la pieza se acerca girando un poco
   y una luz azul sigue al raton sobre ella (el foco, --mx/--my, lo mueve
   app.js). Solo con raton: en el telefono no hay "pasar por encima", y un
   efecto que se queda pegado tras tocar parece un fallo. */
.ficha{
  position:relative; display:flex; flex-direction:column; min-width:0;
  scroll-snap-align:start;
  background:linear-gradient(180deg, var(--papel), var(--papel-bajo));
  border:1px solid var(--linea); border-radius:14px; overflow:hidden;
  transition:transform .35s var(--suave), border-color .35s, box-shadow .35s;
}
@media (hover:hover){
  .ficha:hover{
    transform:translateY(-8px); border-color:rgba(59,123,255,.6);
    box-shadow:0 20px 40px -20px rgba(17,85,244,.7);
  }
  .ficha:hover .fFoto{ transform:translateY(-3px) scale(1.07) rotate(-2deg); }
  .ficha:hover .fPlato::before{ opacity:1; }
}
.ficha:focus-within{ border-color:rgba(59,123,255,.6); }

/* El plato. NO es blanco: las fotos de C&M son transparentes, asi que la
   pieza va directa sobre el negro, con un halo azul debajo que la separa
   del fondo. El ::before es el foco que sigue al raton. */
.fPlato{
  --mx:50%; --my:55%;
  position:relative; aspect-ratio:1/1; display:grid; place-items:center;
  background:radial-gradient(60% 60% at 50% 60%, rgba(17,85,244,.2), transparent 70%);
}
.fPlato::before{
  content:""; position:absolute; inset:0; pointer-events:none;
  background:radial-gradient(150px circle at var(--mx) var(--my),
             rgba(59,123,255,.3), transparent 65%);
  opacity:0; transition:opacity .3s;
}
.fFoto{
  position:relative; width:100%; height:100%; object-fit:contain; display:block;
  padding:10%;
  filter:drop-shadow(0 14px 14px rgba(0,0,0,.85));
  transition:transform .5s var(--suave);
}
/* Una ficha sin foto no necesita un cuadrado entero: dejaba un hueco del
   tamano de una pieza sin nada dentro. Se le da un tercio de alto, que basta
   para decir "no hay foto" sin gastar pantalla.

   Esto ya casi no se ve: los 93 productos viejos que no tenian foto se
   apartaron del catalogo el 22-09-2026 (datos/apartados.csv). Se deja porque
   sigue haciendo falta el dia que entre un producto NUEVO a la lista de la
   oficina y las fotos vayan por detras: mejor que salga con su trama de aviso
   a que desaparezca en silencio. */
.fPlato:has(.fSinFoto){ aspect-ratio:3/1; }
.fSinFoto{
  width:100%; height:100%; filter:none;
  /* Un producto sin foto NO se disimula: se dice. Un hueco gris hace pensar
     que la foto no cargo; esta trama dice "no hay foto todavia". */
  background:repeating-linear-gradient(45deg,
    transparent 0 9px, rgba(255,255,255,.035) 9px 18px);
}
.fSinFoto::after{
  content:"SIN FOTO"; position:absolute; inset:auto 0 12px;
  text-align:center; font:600 10px/1 var(--mono);
  letter-spacing:.16em; color:var(--tinta-3);
}

.fCuerpo{ padding:4px 13px 13px; display:flex; flex-direction:column; gap:6px; flex:1; }
.fCodigo{
  margin:0; font:600 12.5px/1.2 var(--mono); letter-spacing:.01em;
  color:var(--acento-tinta);
  /* Parte por los guiones y, solo si un trozo no cabe, por donde sea. Con
     break-all partia "PT-II599-M5136-IZ" en "…-I / Z" en la fila del
     telefono, y un codigo partido se copia mal. */
  overflow-wrap:anywhere;
}
.fOem{ margin:0; font:600 11.5px/1.3 var(--mono); color:var(--tinta-suave); }
.fOem span{
  font-size:9px; letter-spacing:.14em; color:var(--tinta-3); margin-right:5px;
}
.fDesc{
  margin:2px 0 0; font:600 16px/1.12 var(--disp); letter-spacing:.02em;
  text-transform:uppercase; color:var(--tinta);
  /* La descripcion de la oficina pasa a veces de 90 caracteres, y las
     fichas quedaban de alturas dispares. Se corta a cuatro renglones: lo
     que identifica la pieza esta siempre al principio, y el texto entero
     sigue en el atributo title y en el HTML para que Google lo lea. */
  display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:4;
  overflow:hidden;
  /* La oficina escribe la aplicacion pegada con barras -"4HG1/JAC/CANTER/
     DYNA"- y eso es UNA sola palabra para el navegador: se salia de la
     ficha por el lado derecho. Con esto parte donde haga falta. */
  overflow-wrap:anywhere;
}
/* La familia ya no va en la ficha: la dice el titulo del tramo. */
.fMotores{ margin:auto 0 0; padding-top:8px; display:flex; flex-wrap:wrap; gap:4px; }
.fMarca{
  font:700 11px/1 var(--disp); letter-spacing:.1em; text-transform:uppercase;
  color:var(--tinta-suave); border:1px solid var(--linea);
  border-radius:4px; padding:3px 6px;
}
.fMotor{
  font:600 11px/1 var(--mono); letter-spacing:.04em;
  color:var(--acento-luz); background:var(--acento-fondo);
  border-radius:4px; padding:4px 6px;
}
/* EL BOTON DE CONSULTAR, y el punto verde que late.
   Sigue DELIBERADAMENTE apagado: son 223 fichas, y con el verde a tope la
   pantalla se volvia una pared verde donde la pieza pasaba a segundo plano.
   Lo que dice "aqui se pregunta" es el punto: verde siempre, y latiendo al
   pasar por la ficha. Lo unico que late SIEMPRE es el WhatsApp de la
   cabecera, que es uno solo (movimiento "medio"). */
.fWa{
  display:flex; align-items:center; justify-content:center; gap:9px;
  min-height:44px; margin-top:10px; border-radius:999px;
  background:transparent; border:1px solid var(--linea);
  color:var(--tinta-suave); text-decoration:none;
  font:700 13px/1 var(--disp); letter-spacing:.14em; text-transform:uppercase;
  transition:background .25s, border-color .25s, color .25s;
}
.fWa::before, .topeWaEtiqueta::before, .visorWa::before{
  content:""; width:8px; height:8px; border-radius:50%; flex:none;
  background:var(--verde);
}
.fWa:hover, .fWa:focus-visible{
  background:rgba(37,211,102,.12); border-color:var(--verde);
  color:var(--verde-tinta);
}
.ficha:hover .fWa::before, .fWa:focus-visible::before,
.topeWaEtiqueta::before, .visorWa::before{
  animation:latido 2.2s infinite;
}
@keyframes latido{
  0%  { box-shadow:0 0 0 0 rgba(37,211,102,.6); }
  70% { box-shadow:0 0 0 9px rgba(37,211,102,0); }
  100%{ box-shadow:0 0 0 0 rgba(37,211,102,0); }
}

/* El aviso de "esto es lo que mas se parece". En ambar y no en rojo: no es
   un error, es una respuesta con una advertencia. */
.aprox{
  margin:0 0 12px; padding:10px 13px; border-radius:9px;
  background:var(--acento-fondo); border:1px solid var(--acento);
  color:var(--acento-tinta); font:400 13px/1.5 var(--ui);
}
.aprox b{ font-weight:700; }
.aprox[hidden]{ display:none !important; }

.vacio{
  margin:28px auto; max-width:46ch; text-align:center;
  font:400 15px/1.6 var(--ui); color:var(--tinta-suave);
}

/* ===================== PIE ===================== */

.pie{
  margin-top:40px; padding:24px 16px 34px;
  background:var(--chapa); border-top:1px solid var(--linea);
}
.pieEmpresa{
  margin:0 0 4px; font:700 15px/1.2 var(--disp);
  letter-spacing:.05em; text-transform:uppercase; color:var(--tinta);
}
.pieDato{ margin:0 0 12px; font:400 13px/1.5 var(--mono); color:var(--tinta-suave); }
.pieLegal{ margin:0; max-width:64ch; font:400 12px/1.6 var(--ui); color:var(--tinta-3); }


/* ===================== LA FOTO, EN GRANDE ===================== */

/* Esto es lo que el catalogo descargable de GPC NO podia tener. Alli el
   archivo se abria con el Quick Look de iOS, que no ejecuta JavaScript, asi
   que la foto era lo que se veia en la ficha y punto. Este catalogo es EN
   LINEA: se puede tocar la pieza, verla a pantalla completa, acercarla y
   pasar a las otras vistas.

   El limite honesto: las fotos se publican a 900x900, que es como salen de
   procesar_fotos.py. Abiertas a pantalla completa en un telefono ya se ven a
   tamano real; de ahi en adelante el zoom agranda pixeles. Por eso el tope
   son 4 aumentos y no mas: pasado eso no se ve mas detalle, se ve mas borroso.
   Para acercar de verdad habria que volver a sacar las fotos de los
   originales a 1600 px, y los originales no estan en el repo (regla 4). */

/* La foto de la ficha, cuando se le puede hacer zoom. La clase la pone
   app.js: sin JavaScript no hay visor, asi que no se anuncia lo que no se
   puede hacer. */
.fPlato.seAbre{ cursor:zoom-in; }
.fPlato.seAbre:focus-visible{ outline:2px solid var(--acento); outline-offset:-2px; }
/* La lupa de la esquina. Aparece siempre en el telefono -donde no hay "pasar
   por encima" que valga- y al apuntar con el raton en el escritorio. */
.fLupa{
  position:absolute; right:7px; bottom:7px; z-index:2;
  display:flex; align-items:center; gap:5px;
  padding:4px 7px; border-radius:6px;
  background:rgba(0,0,0,.62); border:1px solid var(--linea);
  font:400 10px/1 var(--mono); letter-spacing:.08em; color:var(--tinta-suave);
  pointer-events:none;
}
.fLupa::before{
  content:""; width:9px; height:9px; border-radius:50%;
  border:1.5px solid var(--acento-tinta); flex:none;
}
@media (hover:hover){
  .fLupa{ opacity:0; transition:opacity .14s; }
  .fPlato.seAbre:hover .fLupa, .fPlato.seAbre:focus-visible .fLupa{ opacity:1; }
}

/* LA MISMA TRAMPA DE .ficha[hidden], otra vez: `display:flex` aqui abajo gana
   a la regla del navegador que esconde lo que lleva `hidden`. Sin esta linea
   el visor sale abierto y tapa el catalogo entero nada mas cargar. */
.visor[hidden]{ display:none !important; }

.visor{
  position:fixed; inset:0; z-index:100;
  display:flex; align-items:center; justify-content:center;
  /* OPACO DEL TODO, no un negro al 94%. Con transparencia se leia el
     catalogo por debajo -el titulo "¿Que motor tienes?", la cinta roja del
     aviso- y se cruzaba con el codigo y la descripcion del visor: ilegible
     y con pinta de roto. El texto blanco sobre negro sigue marcandose aunque
     le eches un 94% de negro encima. Se vio en una captura, no midiendo. */
  background:var(--fondo);
  /* En iOS la barra de abajo se come 34 px: sin esto, el boton de WhatsApp
     del visor queda debajo del indicador y no se puede tocar. */
  padding:env(safe-area-inset-top) env(safe-area-inset-right)
          env(safe-area-inset-bottom) env(safe-area-inset-left);
}
.visorCaja{
  display:flex; flex-direction:column;
  width:100%; height:100%; max-width:1100px;
}

.visorTope{
  display:flex; align-items:flex-start; justify-content:space-between;
  gap:12px; padding:12px 14px 10px; flex:none;
  background:var(--chapa); border-bottom:1px solid var(--linea);
}
.visorQue{ min-width:0; }
.visorCodigo{
  margin:0; font:700 15px/1.2 var(--mono); color:var(--acento-tinta);
  overflow-wrap:anywhere;
}
.visorDesc{
  margin:4px 0 0; font:400 13px/1.45 var(--ui); color:var(--tinta-suave);
  display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:2;
  overflow:hidden;
}
.visorCerrar{
  flex:none; width:44px; height:44px; border-radius:9px;
  background:var(--papel); border:1px solid var(--linea);
  color:var(--tinta); font:400 26px/1 var(--ui); cursor:pointer;
}
.visorCerrar:hover{ background:var(--papel-alto); border-color:var(--acento); }

/* La escena. `touch-action:none` es obligatorio: sin eso el navegador se
   queda los dedos para hacer zoom a la PAGINA y el de la foto no llega. */
.visorEscena{
  position:relative; flex:1; min-height:0; overflow:hidden;
  /* FLEX Y NO GRID, y no es indiferente. Con `display:grid` la fila la
     medía el contenido, asi que el `max-height:100%` de la foto se quedaba
     sin nada contra que calcularse y el navegador lo ignoraba: en el
     escritorio la foto salia a sus 900 px de alto dentro de una escena de
     688 y se le comia el borde de abajo la barra de miniaturas. Con flex,
     la altura de la escena es firme y el max-height si cuenta. */
  display:flex; align-items:center; justify-content:center;
  touch-action:none; user-select:none; -webkit-user-select:none;
  background-image:
    linear-gradient(rgba(255,255,255,.022) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.022) 1px, transparent 1px);
  background-size:72px 72px;
}
.visorFoto{
  max-width:100%; max-height:100%;
  object-fit:contain; display:block;
  transform-origin:0 0;      /* el zoom lo calcula app.js a mano */
  will-change:transform;
  -webkit-user-drag:none;
}
.visorEscena.acercado{ cursor:grab; }
.visorEscena.arrastrando{ cursor:grabbing; }

.visorPasa{
  position:absolute; top:50%; transform:translateY(-50%);
  width:46px; height:60px; border-radius:9px;
  background:rgba(10,11,13,.78); border:1px solid var(--linea);
  color:var(--tinta); font:400 30px/1 var(--ui); cursor:pointer;
}
.visorPasa[hidden]{ display:none !important; }
.visorPasa:hover{ background:var(--papel-alto); border-color:var(--acento); }
.visorAntes{ left:8px; }
.visorDespues{ right:8px; }

/* La pista de como se usa. Se ve al abrir y se apaga sola: si se queda fija
   estorba justo encima de la pieza, que es lo que se vino a mirar. */
.visorPista{
  position:absolute; left:50%; bottom:10px; transform:translateX(-50%);
  /* SIN nowrap y con tope de ancho. Con `white-space:nowrap` el mensaje se
     salia por los dos lados en un telefono de 390 px y se leia "tos ·
     flechas para pasar · rueda o doble clic para ace". Se vio en la captura
     del sitio ya publicado, no en local. */
  max-width:calc(100% - 24px); text-align:center;
  margin:0; padding:7px 12px; border-radius:16px;
  background:rgba(10,11,13,.85); border:1px solid var(--linea);
  font:400 11px/1 var(--mono); letter-spacing:.06em; color:var(--tinta-suave);
  opacity:0; transition:opacity .3s; pointer-events:none;
}
.visorPista.seVe{ opacity:1; }

.visorPie{
  flex:none; padding:10px 14px 14px;
  background:var(--chapa); border-top:1px solid var(--linea);
}

.visorMiniaturas{
  display:flex; gap:7px; overflow-x:auto; padding-bottom:8px;
  scrollbar-width:thin;
}
.visorMiniaturas:empty{ display:none; }
.visorMini{
  flex:none; width:54px; height:54px; padding:3px; cursor:pointer;
  background:var(--papel); border:1px solid var(--linea); border-radius:8px;
}
.visorMini img{ width:100%; height:100%; object-fit:contain; display:block; }
.visorMini[aria-current="true"]{ border-color:var(--acento); background:var(--acento-fondo); }

.visorMandos{
  display:flex; align-items:center; justify-content:space-between;
  gap:10px; flex-wrap:wrap;
}
.visorLupa{
  display:flex; align-items:center; gap:2px;
  background:var(--papel); border:1px solid var(--linea); border-radius:9px;
}
.visorZoomBoton{
  width:44px; height:44px; border:0; border-radius:9px; cursor:pointer;
  background:transparent; color:var(--tinta); font:400 21px/1 var(--ui);
}
.visorZoomBoton:hover:not(:disabled){ background:var(--papel-alto); color:var(--acento-tinta); }
.visorZoomBoton:disabled{ color:var(--tinta-3); cursor:default; }
.visorZoomCifra{
  min-width:52px; text-align:center;
  font:400 12px/1 var(--mono); color:var(--tinta-suave);
}
.visorWa{
  display:flex; align-items:center; justify-content:center; gap:8px;
  flex:1; min-width:180px; min-height:46px; padding:10px 16px;
  border-radius:9px; text-decoration:none;
  background:rgba(37,211,102,.12); border:1px solid var(--verde);
  color:var(--verde-tinta);
  font:700 12px/1 var(--disp); letter-spacing:.09em; text-transform:uppercase;
}
.visorWa:hover{ background:rgba(37,211,102,.2); }

/* Mientras el visor esta abierto, el catalogo de detras no se mueve. Si no,
   al arrastrar la foto ampliada se va desplazando la pagina de abajo y al
   cerrar has perdido el sitio donde estabas. */
body.visorAbierto{ overflow:hidden; }

@media (min-width:760px){
  .visorTope{ padding:16px 18px 12px; }
  .visorPie{ padding:12px 18px 18px; }
  .visorCodigo{ font-size:17px; }
  .visorWa{ flex:none; min-width:260px; }
}

/* ===================== PANTALLAS GRANDES ===================== */

@media (min-width:760px){
  .tope{ padding:12px 28px 14px; }
  .portada, .indice, .bloque{ padding-left:28px; padding-right:28px; }
  .indiceTitulo{ font-size:64px; }
  .pie{ padding:28px; }
}
@media (min-width:1200px){
  .tope, main, .pie > *{ max-width:1320px; margin-inline:auto; }
  .topeFila, .topeBusca{ max-width:1320px; margin-inline:auto; }
}

/* "REDUCIR MOVIMIENTO": se para TODO. Quitar las transiciones no basta:
   la ficha seguiria saltando 8 px de golpe al pasar el raton, que es peor
   que deslizarse. Lo que se mueve se deja quieto en su sitio. */
@media (prefers-reduced-motion:reduce){
  *, *::before, *::after{ transition:none !important; animation:none !important; }
  .ficha:hover, .ficha:hover .fFoto{ transform:none !important; }
  .riel{ scroll-behavior:auto; }
}
