/* app.css — Estilos propios del portal B2B de Grupo VEX. Se carga DESPUÉS del kit, así que
   acá va sólo lo que el kit no trae: las pantallas de ingreso, el grid del catálogo, la
   matriz de color por talle (la pieza central del portal), el carrito y la cuenta corriente.
   Todo lo demás (shell, topbar, sidebar, tablas, tarjetas, KPI, paneles, gráficos) es del kit
   y se reskinea solo con clientes/tifox/marca/tokens.css.

   Regla que no se rompe: NINGÚN color literal acá. Sólo var(--…) del contrato. Un hex escrito
   a mano rompe el reskin del cliente y no se nota hasta que lo usa otro. */

/* ---------- Ingreso ---------- */
/* Dos puertas y una sola pantalla de fondo: el mayorista entra con un código de seis cifras
   que le llega por mail, y el equipo con usuario y clave. */
.login {
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: 24px;
  background: var(--fondo);
}
.login__caja {
  width: 100%;
  max-width: 420px;
  background: var(--superficie);
  border: 1px solid var(--borde);
  border-radius: var(--radio-lg);
  box-shadow: var(--sombra);
  padding: 34px 30px;
}
.login__logo { display: block; height: 40px; margin: 0 auto 26px; }
.login__titulo {
  font-family: var(--fuente-titulo);
  font-size: 19px;
  font-weight: 600;
  text-align: center;
  margin: 0 0 6px;
}
.login__bajada {
  text-align: center;
  color: var(--tinta-suave);
  font-size: 13.5px;
  margin: 0 0 22px;
}
.login__pie {
  margin-top: 20px;
  padding-top: 16px;
  border-top: 1px solid var(--borde-suave);
  text-align: center;
  font-size: 12.5px;
  color: var(--tinta-tenue);
}
.login__pie a { color: var(--marca); }

/* Los seis dígitos del código: campo ancho, monoespaciado y separado, para que se lea igual
   que llegó en el mail y se note si falta una cifra. */
.codigo-input {
  width: 100%;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 27px;
  letter-spacing: .34em;
  text-align: center;
  padding: 12px 8px 12px 20px;   /* el padding izquierdo compensa el tracking de la última cifra */
  border: 1px solid var(--borde);
  border-radius: var(--radio-sm);
  background: var(--superficie);
  color: var(--tinta);
}
.codigo-input:focus-visible { outline: 2px solid var(--foco); outline-offset: 2px; }

/* ---------- Catálogo: el grid de productos ---------- */
.catalogo-grid {
  display: grid;
  /* minmax(0, …) y no 1fr pelado: una columna nace con min-width auto y un nombre largo de
     producto la estiraría por encima de su parte. */
  grid-template-columns: repeat(auto-fill, minmax(min(226px, 100%), 1fr));
  gap: 16px;
}
.prod {
  background: var(--superficie);
  border: 1px solid var(--borde);
  border-radius: var(--radio);
  overflow: hidden;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  transition: border-color 140ms ease, box-shadow 140ms ease;
}
.prod:hover, .prod:focus-visible { border-color: var(--marca); box-shadow: var(--sombra-sm); }
.prod:focus-visible { outline: 2px solid var(--foco); outline-offset: 2px; }
.prod__foto {
  aspect-ratio: 1 / 1;
  background: var(--superficie-alt);
  display: grid;
  place-items: center;
  overflow: hidden;
  /* Las etiquetas se apoyan acá arriba: `relative` sobre el marco de la foto y no sobre la tarjeta
     entera, para que queden pegadas a la imagen y no floten sobre el nombre. */
  position: relative;
}
/* Las etiquetas manuales del catálogo, arriba a la izquierda de la foto. Van sobre la imagen y no
   en el cuerpo de la tarjeta porque son lo que tiene que llamar la atención mientras se scrollea
   una grilla de doscientas medias; abajo del nombre ya no las mira nadie. Columna y no fila: con
   dos etiquetas largas en línea, la segunda se sale de la tarjeta en un teléfono. */
.prod__tags {
  position: absolute;
  top: 8px;
  left: 8px;
  right: 8px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  pointer-events: none;
}
.prod__tag { box-shadow: var(--sombra-sm); }
.prod__foto img { width: 100%; height: 100%; object-fit: contain; }
/* El placeholder digno: el isotipo apagado, no un cuadro gris con una cruz. Elite Sport y
   Compressport entran al portal SIN una sola foto, así que esto se ve en la mitad del
   catálogo y tiene que verse a propósito, no como un error de carga. */
.prod__sinfoto {
  width: 46%;
  opacity: .16;
  filter: grayscale(1);
}
.prod__cuerpo { padding: 12px 13px 14px; display: flex; flex-direction: column; gap: 4px; flex: 1; }
.prod__marca {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--tinta-tenue);
}
.prod__nombre {
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.35;
  color: var(--tinta);
  /* Dos líneas y corta: con una sola, la mitad de los nombres del catálogo quedan mutilados
     ("Media sin pie, pantorrillera modelo…"), y sin tope las tarjetas quedan de alturas
     distintas y el grid se desarma. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.prod__pie { margin-top: auto; padding-top: 8px; display: flex; align-items: baseline; gap: 8px; }
.prod__precio { font-family: var(--fuente-titulo); font-size: 16px; font-weight: 600; color: var(--tinta); }
.prod__desde { font-size: 11.5px; color: var(--tinta-tenue); }
.prod__variantes { font-size: 11.5px; color: var(--tinta-tenue); }
/* El botón de carga rápida de la tarjeta. Se dibuja SIEMPRE, no al pasar el mouse: en un teléfono
   el hover no existe, y una acción que sólo aparece con el mouse encima es una acción que la mitad
   de los comercios no encuentra. Con el mouse (o con el foco del teclado) se realza, que es lo que
   dice que la tarjeta entera es lo que se toca. Va en un span y no en un button: el clic lo maneja
   la tarjeta, que ya es role="button", y un botón adentro de otro es un foco de más en cada
   tabulación de una grilla de sesenta productos. */
.prod__accion { margin-top: 8px; }
.prod__accion .btn { width: 100%; justify-content: center; pointer-events: none; }
.prod:hover .prod__accion .btn,
.prod:focus-visible .prod__accion .btn { border-color: var(--marca); color: var(--marca); }
/* El producto que existe pero no se puede pedir (sin precio o sin código de barras): se
   muestra apagado y lo dice. Esconderlo haría que el cliente lo pida por WhatsApp igual. */
.prod--consultar .prod__foto { opacity: .55; }
.prod--consultar .prod__precio { color: var(--tinta-tenue); font-size: 13.5px; font-weight: 600; }

/* Chips de marca y de rubro arriba del grid. */
.chips { display: flex; flex-wrap: wrap; gap: 7px; }
.chip-f {
  font-size: 12.5px;
  font-weight: 600;
  padding: 6px 13px;
  border-radius: 999px;
  border: 1px solid var(--borde);
  background: var(--superficie);
  color: var(--tinta-suave);
  cursor: pointer;
}
.chip-f:hover { border-color: var(--marca); color: var(--marca); }
.chip-f.is-on { background: var(--marca); border-color: var(--marca); color: var(--marca-contenido); }
.chip-f:focus-visible { outline: 2px solid var(--foco); outline-offset: 2px; }

/* ---------- La ficha: matriz de color por talle ---------- */
/* El corazón del portal. Filas por color, columnas por talle, y en cada celda la cantidad.
   Hay artículos de una variante y uno de 54, así que la matriz scrollea de costado con la
   columna del color quieta: sin eso, al llegar al talle 12 ya no se sabe qué color se está
   cargando. Es la misma razón por la que una planilla inmoviliza la primera columna. */
.matriz-wrap { overflow-x: auto; border: 1px solid var(--borde); border-radius: var(--radio); background: var(--superficie); }
.matriz { border-collapse: separate; border-spacing: 0; width: max-content; min-width: 100%; font-size: 13px; }
.matriz th, .matriz td { padding: 8px 10px; border-bottom: 1px solid var(--borde-suave); text-align: center; }
.matriz thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--superficie-alt);
  border-bottom: 1px solid var(--borde);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--tinta-tenue);
  white-space: nowrap;
}
.matriz__color {
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--superficie);
  text-align: left;
  font-weight: 600;
  color: var(--tinta);
  white-space: nowrap;
  border-right: 1px solid var(--borde);
}
.matriz thead .matriz__color { z-index: 3; background: var(--superficie-alt); }
.matriz tbody tr:hover .matriz__color,
.matriz tbody tr:hover td { background: var(--superficie-alt); }
.matriz__total { font-weight: 600; color: var(--tinta); background: var(--superficie-alt); }
.matriz tfoot td { border-top: 1px solid var(--borde); border-bottom: 0; font-weight: 600; background: var(--superficie-alt); }

/* La celda: el stepper arriba y el stock abajo, en chico. */
.celda { display: flex; flex-direction: column; align-items: center; gap: 3px; min-width: 74px; }
.celda__cant {
  width: 62px;
  height: 34px;
  text-align: center;
  font-variant-numeric: tabular-nums;
  font-size: 14px;
  border: 1px solid var(--borde);
  border-radius: var(--radio-sm);
  background: var(--superficie);
  color: var(--tinta);
}
.celda__cant:focus-visible { outline: 2px solid var(--foco); outline-offset: 1px; }
.celda__cant.is-cargada { border-color: var(--marca); font-weight: 600; }
.celda__stock { font-size: 10.5px; color: var(--tinta-tenue); line-height: 1.2; }
.celda__stock--hay { color: var(--ok); }
.celda__stock--poco { color: var(--atencion); }
.celda__stock--sin { color: var(--error); }
/* La leyenda del semáforo, arriba de la matriz. Los tres colores de las celdas no son
   decorativos ni aleatorios (lo primero que se dijo al mirar la pantalla fue que "iban
   cambiando"): son un estado con nombre, y el nombre tiene que estar escrito en algún lado. */
.leyenda-stock {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 16px;
  align-items: center;
  font-size: 12px;
  color: var(--tinta-suave);
  margin: 0;
}
.leyenda-stock__item { display: inline-flex; align-items: center; gap: 6px; }
.leyenda-stock__punto {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  flex: none;
  background: var(--ok);
}
.leyenda-stock__punto--poco { background: var(--atencion); }
.leyenda-stock__punto--sin { background: var(--error); }
/* La variante que no se puede pedir (sin precio o sin código de barras): la celda no acepta
   nada y lo dice. No viaja al servidor, y el servidor la rechaza igual. */
.celda--consultar { color: var(--tinta-tenue); font-size: 11.5px; }
/* Los atajos de bulto. La docena va en toda celda (son doce por definición y el servidor la
   acepta para todo el catálogo); la caja, sólo donde sabemos cuántas unidades trae. Un toque
   suma el múltiplo y la línea guarda con qué unidad se vendió. */
.celda__atajos { display: flex; gap: 3px; }
.celda__atajo {
  font-size: 10.5px;
  font-weight: 600;
  padding: 1px 6px;
  border-radius: 999px;
  border: 1px solid var(--borde);
  background: var(--superficie);
  color: var(--tinta-suave);
  cursor: pointer;
  line-height: 1.6;
}
.celda__atajo:hover { border-color: var(--marca); color: var(--marca); }

/* El pie fijo de la ficha: unidades y total, siempre a la vista mientras se carga la matriz. */
.ficha-pie {
  position: sticky;
  bottom: 0;
  z-index: 4;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  background: var(--superficie);
  border: 1px solid var(--borde);
  border-radius: var(--radio);
  box-shadow: var(--sombra);
  padding: 13px 18px;
  margin-top: 16px;
}
.ficha-pie__cifras { display: flex; gap: 22px; align-items: baseline; }
.ficha-pie__dato { display: flex; flex-direction: column; gap: 1px; }
.ficha-pie__rotulo { font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--tinta-tenue); }
.ficha-pie__valor { font-family: var(--fuente-titulo); font-size: 19px; font-weight: 600; color: var(--tinta); }

/* La hora de lectura del stock: va UNA vez arriba de la matriz, no en cada celda. El dato es
   una foto, no una promesa, y decirlo una vez alcanza. */
.stock-leido { font-size: 12.5px; color: var(--tinta-tenue); }

/* ---------- Carrito y checkout ---------- */
.carrito-linea { display: grid; grid-template-columns: 56px minmax(0, 1fr) auto; gap: 12px; align-items: center; padding: 11px 0; border-bottom: 1px solid var(--borde-suave); }
.carrito-linea__foto { width: 56px; height: 56px; border-radius: var(--radio-sm); background: var(--superficie-alt); object-fit: contain; }
.carrito-linea__nombre { font-size: 13.5px; font-weight: 600; color: var(--tinta); }
.carrito-linea__det { font-size: 12px; color: var(--tinta-tenue); }
.carrito-linea--sin-precio { background: var(--error-bg); border-radius: var(--radio-sm); padding-inline: 10px; }

/* El desglose: lista, descuento, neto, IVA y total. La fila del IVA no se dibuja cuando el
   cliente tiene el flag sin IVA, en vez de mostrar un cero que no significa nada. */
.desglose { display: grid; gap: 7px; font-size: 13.5px; }
.desglose__fila { display: flex; justify-content: space-between; gap: 20px; color: var(--tinta-suave); }
.desglose__fila--desc { color: var(--ok); }
.desglose__fila--total {
  border-top: 1px solid var(--borde);
  padding-top: 9px;
  margin-top: 3px;
  font-family: var(--fuente-titulo);
  font-size: 17px;
  font-weight: 600;
  color: var(--tinta);
}
.desglose .num { font-variant-numeric: tabular-nums; }

/* El margen sugerido: lo que el revendedor gana si vende al precio de lista al público. Es el
   dato que hace que la tercera lista del ERP valga la pena mostrarla. */
.margen {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  font-size: 12.5px;
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--ok-bg);
  color: var(--ok);
  font-weight: 600;
}

/* ---------- Cuenta corriente ---------- */
/* El movimiento que suma y el que resta se distinguen por el signo y por el color, no sólo
   por la columna: la misma tabla se lee en un teléfono con las columnas apiladas. */
.mov--cargo .num { color: var(--tinta); }
.mov--abono .num { color: var(--ok); }
.mov--anulado { opacity: .5; text-decoration: line-through; }
/* La factura abierta que el FIFO dejó parcialmente cubierta. */
.mov__barra { height: 4px; border-radius: 999px; background: var(--borde-suave); overflow: hidden; margin-top: 4px; }
.mov__barra > i { display: block; height: 100%; background: var(--ok); }

/* ---------- Panel de avisos ---------- */
/* La vista previa se arma sobre una tabla de 600px, que es lo que entienden Gmail y Outlook.
   Por eso el panel que la muestra va con .sheet--ancho: achicarla mostraría un mail que no es
   el que va a recibir la persona, y la vista previa existe justamente para eso. */
.previa-mail { background: var(--superficie-alt); border: 1px solid var(--borde); border-radius: var(--radio); padding: 18px; overflow-x: auto; }
.previa-mail__marco { width: 600px; max-width: 100%; margin: 0 auto; background: #fff; }

/* ---------- CRM ---------- */
/* La oportunidad cerrada se ve cerrada: apagada, y con su pill de ganada o perdida al lado. Se
   muestra sólo si se la pide (la casilla "Incluir las cerradas") y nunca igual que lo que sigue
   vivo, porque mezclada con lo abierto la suma del embudo promete plata que ya se decidió. */
.fila--cerrada { opacity: .6; }

/* La línea de una lista que abre su detalle, para las listas que no son <table> (el seguimiento
   de la ficha). El .is-clickable del kit sólo pinta el cursor adentro de una tabla, y una línea
   que se abre y no lo parece no se abre nunca. Los márgenes negativos compensan el padding, así
   la fila resaltada no corre el texto de lugar al pasar el mouse. */
.linea-clic {
  cursor: pointer;
  border-radius: var(--radio-sm);
  padding: 6px 8px;
  margin: -6px -8px;
  transition: background-color 140ms ease;
}
.linea-clic:hover { background: var(--superficie-alt); }
.linea-clic:focus-visible { outline: 2px solid var(--foco); outline-offset: 2px; }

/* ---------- Modal de confirmación y toast ---------- */
/* El kit trae el velo (.modal-back) y no la tarjeta, así que la tarjeta va acá, con sus mismos
   tokens. El z-index queda ARRIBA del velo del kit (300): el modal se abre ENCIMA del panel
   lateral, porque desde un panel abierto se confirma una baja y el diálogo tiene que ganarle.
   Sin estas reglas el diálogo se dibuja en el flujo, al pie de la página, y se lee como un
   pedazo de formulario suelto en vez de como una confirmación. */
.modal { position: fixed; inset: 0; z-index: 310; display: none; place-items: center; padding: 20px; }
.modal.is-open { display: grid; }
.modal__card {
  background: var(--elevado); border: 1px solid var(--borde); border-radius: var(--radio-lg);
  box-shadow: var(--sombra-lg); padding: 22px 24px; width: 100%; max-width: 440px;
}
.modal__title { font-family: var(--fuente-titulo); font-size: 17px; font-weight: 600; margin: 0 0 8px; color: var(--tinta); }
.modal__txt { font-size: 13.5px; line-height: 1.55; color: var(--tinta-suave); margin: 0 0 18px; }
.modal__acciones { display: flex; gap: 8px; justify-content: flex-end; flex-wrap: wrap; margin-top: 18px; }

.toast {
  position: fixed; left: 50%; bottom: 26px; transform: translateX(-50%) translateY(20px);
  background: var(--tinta); color: var(--marca-contenido); font-size: 13.5px; font-weight: 600;
  padding: 11px 18px; border-radius: var(--radio); box-shadow: var(--sombra-lg);
  opacity: 0; pointer-events: none; transition: opacity .2s, transform .2s; z-index: 320; max-width: 90vw;
}
.toast.is-on { opacity: 1; transform: translateX(-50%) translateY(0); }
.toast--error { background: var(--error); }
.toast--ok { background: var(--ok); }

/* ---------- Utilidades que el kit no trae ---------- */
.pila { display: flex; flex-direction: column; gap: 4px; }
.pila--md { gap: 10px; }
.ancho-completo { width: 100%; }
.nowrap { white-space: nowrap; }
.txt-sm { font-size: 12.5px; }
.txt-tenue { color: var(--tinta-tenue); }
/* El contador de "cuántos de cuántos" del patrón 10, con el quitar filtros al lado. Va acá y
   no en la barra de filtros para que la barra no cambie de alto al aparecer el botón, que
   correría la tabla justo cuando se la está leyendo. */
.cuantos { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; font-size: 13px; color: var(--tinta-suave); }

/* El selector de roles: casillas con la descripción de cada uno debajo, y el resumen en vivo de
   qué queda habilitado. Es lo que un desplegable no puede hacer (un <option> no tiene dos
   líneas), y era justo donde hacía falta: la pantalla donde se decide qué puede tocar alguien.
   Mismo componente que en Bulk Pack, para que las dos apps se elijan igual. */
.rolpick { display: flex; flex-direction: column; border: 1.5px solid var(--borde); border-radius: var(--radio-sm); overflow: hidden; }
.rolpick__opt {
  display: grid; grid-template-columns: auto 1fr; gap: 10px; align-items: start;
  padding: 10px 12px; border-bottom: 1px solid var(--borde-suave); cursor: pointer;
}
.rolpick__opt:last-child { border-bottom: 0; }
.rolpick__opt:hover { background: var(--superficie-alt); }
.rolpick__opt input { margin-top: 2px; width: 16px; height: 16px; accent-color: var(--marca); }
.rolpick__opt:has(input:checked) { background: var(--marca-suave); }
.rolpick__txt b { display: block; font-size: 13.5px; font-weight: 700; color: var(--tinta); }
.rolpick__txt small { display: block; font-size: 12.5px; color: var(--tinta-suave); margin-top: 1px; }
.rolpick__sum { margin-top: 8px; display: flex; flex-direction: column; gap: 5px; }
.rolpick__puede { font-size: 12.5px; color: var(--tinta-suave); }
/* El aviso de una combinación que cambia algo que no se ve (el vendedor que suma otro rol y deja
   de ver sólo su cartera) va en tono de atención, no de error: no está mal, hay que saberlo. */
.rolpick__aviso {
  font-size: 12.5px; color: var(--atencion); background: var(--atencion-bg);
  border-radius: var(--radio-sm); padding: 6px 9px;
}

/* La salida del recorte de las cuentas de prueba, en la barra de filtros de los tableros y de
   la cobranza. Va tenue y al final de la barra a propósito: es una salida de escape para mirar
   algo que normalmente no se cuenta, no un filtro de todos los días. */
.filtro-prueba {
  display: inline-flex; align-items: center; gap: 7px; cursor: pointer;
  font-size: 12.5px; color: var(--tinta-tenue); margin-left: auto;
  border: 1px solid var(--borde); border-radius: var(--radio-sm); padding: 5px 9px;
}
.filtro-prueba input { width: 14px; height: 14px; cursor: pointer; }
.filtro-prueba:has(input:checked) { color: var(--tinta); border-color: var(--marca); }

@media (max-width: 720px) {
  /* En teléfono la barra ya viene envuelta: el margen automático la empujaría sola a una fila. */
  .filtro-prueba { margin-left: 0; }
  .login__caja { padding: 26px 20px; }
  .ficha-pie { flex-direction: column; align-items: stretch; }
  .ficha-pie__cifras { justify-content: space-between; }
  /* En teléfono los inputs bajan de 16px y iOS hace zoom solo al enfocarlos, lo que deja la
     matriz corrida de costado sin que nadie la haya movido. */
  .celda__cant { font-size: 16px; }
}

/* --- La galería de la ficha de producto ----------------------------------------------------
   Con una sola foto la ficha sigue mostrando el marco cuadrado de siempre; con varias, la grande
   arriba y las miniaturas debajo. Es lo que se pidió mirando una tienda: "que haya dos, tres fotos
   del producto, como en la página web de una marca".

   El ancho lo fija la columna (150px, el mismo de la foto única) para que el bloque de datos de al
   lado no cambie de lugar según cuántas fotos tenga el artículo. */
.galeria { width: 150px; }
.galeria__grande { aspect-ratio: 1 / 1; }
.galeria__tiras {
  display: flex;
  gap: 6px;
  margin-top: 6px;
  overflow-x: auto;
  padding-bottom: 2px;
}
.galeria__tira {
  flex: none;
  width: 42px;
  height: 42px;
  padding: 0;
  border: 1px solid var(--borde);
  border-radius: var(--radio-sm);
  background: var(--superficie-alt);
  cursor: pointer;
  overflow: hidden;
}
.galeria__tira img { width: 100%; height: 100%; object-fit: contain; display: block; }
.galeria__tira.is-on { border-color: var(--marca); }
.galeria__tira:focus-visible { outline: 2px solid var(--foco); outline-offset: 2px; }

/* --- El visor de fotos -----------------------------------------------------------------------
   La foto en grande, arriba de todo: del panel (210), del modal (310) y abajo del toast (320),
   que es avisar y tiene que verse aunque haya una foto abierta. El fondo es el mismo velo de los
   otros pisos, más oscuro, porque acá lo que importa es la imagen y no lo que hay atrás.

   El marco de la foto en la ficha y en el panel se vuelve botón: cursor de lupa y el mismo foco
   visible que el resto. En un teléfono las flechas se apoyan sobre la foto, que ocupa casi todo el
   ancho, y son grandes a propósito: es lo que se toca con el pulgar. */
.galeria__grande.is-abrible, .prod__foto.is-abrible { cursor: zoom-in; border: 0; padding: 0; width: 100%; }
.galeria__grande.is-abrible:focus-visible, .prod__foto.is-abrible:focus-visible { outline: 2px solid var(--foco); outline-offset: 2px; }
.visor { position: fixed; inset: 0; z-index: 315; display: none; place-items: center; padding: 16px; }
.visor.is-open { display: grid; }
.visor__fondo { position: absolute; inset: 0; background: rgba(20, 20, 20, .82); }
/* El marco es FIJO (casi toda la pantalla) y la foto se acomoda adentro: así una foto chica o
   una vertical no achica el popup hasta que las flechas se pisan con la cruz. */
.visor__caja { position: relative; width: min(92vw, 960px); height: min(92vh, 760px); }
.visor__img {
  display: block; width: 100%; height: 100%; object-fit: contain;
  background: var(--elevado); border-radius: var(--radio-lg); box-shadow: var(--sombra-lg);
}
.visor__x, .visor__flecha {
  position: absolute; border: 0; cursor: pointer; display: grid; place-items: center;
  background: var(--elevado); color: var(--tinta); box-shadow: var(--sombra-lg); border-radius: 999px;
}
.visor__x { top: 10px; right: 10px; width: 36px; height: 36px; font-size: 14px; }
.visor__flecha { top: 50%; transform: translateY(-50%); width: 44px; height: 44px; font-size: 30px; line-height: 0; padding-bottom: 4px; }
.visor__flecha--ant { left: 10px; }
.visor__flecha--sig { right: 10px; }
.visor__x:hover, .visor__flecha:hover { background: var(--superficie-alt); }
.visor__x:focus-visible, .visor__flecha:focus-visible { outline: 2px solid var(--foco); outline-offset: 2px; }
.visor__pie {
  position: absolute; bottom: 10px; left: 50%; transform: translateX(-50%);
  background: var(--elevado); color: var(--tinta-suave); font-size: 12.5px; padding: 4px 10px;
  border-radius: 999px; box-shadow: var(--sombra-sm); white-space: nowrap;
}

/* --- Los bloques administrables del inicio -------------------------------------------------
   Lo que Grupo VEX arma desde el back office y el mayorista ve al entrar: el banner con la foto,
   lo que se viene, la comunicación general. Son espacios con forma fija y no un constructor libre
   de páginas: por eso hay una clase por tipo de bloque y ninguna posición configurable.

   Dos columnas, como los "dos banners para comunicar novedades de la marca" del mockup de Cami
   (02/09): van debajo de los últimos pedidos, uno al lado del otro, y un tercero cae a la fila de
   abajo. El banner ya no ocupa el ancho completo: a 2:1 y a media columna, la foto se entrega a
   1200 × 600 px (ver plan-fase-1.md). */
.bloques {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
  align-items: start;
}
.bloque {
  border-radius: var(--radio);
  overflow: hidden;
}
.bloque--banner {
  position: relative;
  aspect-ratio: 2 / 1;
  min-height: 160px;
  display: grid;
  background: var(--superficie-alt);
}
@media (max-width: 640px) {
  .bloques { grid-template-columns: 1fr; }
  /* A una columna angosta el 2:1 no le alcanza al título de dos líneas más el botón, y el banner
     recortaba su propio botón. El alto lo fija el contenido, con un piso para que la foto se vea. */
  .bloque--banner { aspect-ratio: auto; min-height: 200px; }
}
/* La foto y el texto van apilados en la MISMA celda del grid, no con position absolute: así el
   alto lo fija el contenido más alto de los dos y un título largo nunca se sale de la foto. */
.bloque--banner > * { grid-area: 1 / 1; }
.bloque__foto { width: 100%; height: 100%; object-fit: cover; display: block; }
/* El velo detrás del texto. Sin él, un título claro sobre una foto clara no se lee, y el contraste
   de una foto que sube marketing no se puede garantizar de antemano. */
.bloque__sobre {
  position: relative;
  align-self: end;
  padding: 22px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  /* El velo va en rgb() con alfa y no en un token: es un negro neutro con transparencia, la misma
     familia que las sombras del contrato, y no un color de marca. El texto sí sale del token: es
     el mismo blanco que el kit ya usa sobre el color de marca. */
  background: linear-gradient(to top, rgb(0 0 0 / .72), rgb(0 0 0 / .35) 60%, transparent);
  color: var(--marca-contenido);
}
/* El color va EXPLÍCITO en el título y en la bajada, no heredado del envoltorio. El kit le pone
   color a los `h3` y a los `p` de sus bloques de texto, y esa regla le gana a la herencia del
   `.bloque__sobre`: el resultado era el título en tinta oscura sobre el velo negro, ilegible.
   Se vio mirando la pantalla con una foto cargada, que es lo único que lo muestra. */
.bloque__titulo {
  font-family: var(--fuente-titulo);
  font-size: 22px;
  font-weight: 600;
  margin: 0;
  color: var(--marca-contenido);
}
.bloque__bajada {
  font-size: 14px;
  margin: 0;
  max-width: 60ch;
  color: var(--marca-contenido);
}
.bloque__sobre .chip-marca {
  background: rgb(255 255 255 / .18);
  color: var(--marca-contenido);
  border-color: transparent;
}

/* --- Novedades ---------------------------------------------------------------------------- */
/* El cuerpo lo escribe una persona en un textarea, con sus renglones: se respetan tal cual y el
   texto va escapado, nunca interpretado como HTML. Un editor con formato es un constructor de
   páginas, que es lo que el alcance de la Fase 1 deja afuera. */
.novedad__cuerpo {
  white-space: pre-wrap;
  font-size: 14px;
  line-height: 1.65;
  color: var(--tinta-suave);
  max-width: 72ch;
}

/* --- El recorrido del pedido ---------------------------------------------------------------
   Tres pasos en línea, el hecho pintado y el actual marcado. "Sumar estados a los pedidos: ver si
   se aprobó, se envió" (Cami, 02/09). Son los tres estados que el pedido tiene de verdad. */
.pasos {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
}
.pasos__paso {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 10px 12px;
  border-radius: var(--radio);
  border: 1px solid var(--borde);
  background: var(--superficie);
}
.pasos__punto {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--borde);
  margin-bottom: 4px;
}
.pasos__paso.is-hecho .pasos__punto,
.pasos__paso.is-actual .pasos__punto { background: var(--ok); }
.pasos__paso.is-actual { border-color: var(--marca); }
.pasos__label { font-weight: 600; font-size: 13.5px; }
.pasos__paso:not(.is-hecho):not(.is-actual) .pasos__label { color: var(--tinta-tenue); }
.pasos__fecha { font-size: 12.5px; color: var(--tinta-tenue); }
@media (max-width: 640px) {
  .pasos { grid-template-columns: 1fr; }
}

/* --- El portal con el panel oscuro, y el inicio de Cami (02/09) ----------------------------
   El mockup del inicio trae la columna de secciones en azul profundo, los accesos rápidos como
   fichas cuadradas oscuras, el pedido nuevo grande arriba a la derecha y los logos de Tifox y Elite
   Sport en el encabezado. Todo va scopeado a `.app--portal`: el back office comparte esta hoja y
   sigue con el shell claro del kit. Ningún color literal: el azul profundo es `--marca-fuerte`, el
   blanco es `--marca-contenido`, y los tintes intermedios salen de `color-mix` sobre esos dos,
   igual que ya hace el kit para el contador del ítem activo. */
/* El modificador va en la nav (`sidebar--oscura`) y no en `.sidebar` a secas: el linter exige que
   todo bloque base de `.sidebar` traiga el anclaje del patrón 7, y ese anclaje ya lo pone el kit. */
.sidebar--oscura { background: var(--marca-fuerte); border-right-color: var(--marca-fuerte); }
.app--portal .side-link { color: color-mix(in srgb, var(--marca-contenido) 82%, transparent); }
.app--portal .side-link:hover {
  background: color-mix(in srgb, var(--marca-contenido) 10%, transparent);
  color: var(--marca-contenido);
}
.app--portal .side-link.is-active { background: var(--marca); color: var(--marca-contenido); }
/* El anillo de foco del kit es `--foco`, el azul de marca: sobre el panel azul profundo da 1,57:1 y
   el cursor del teclado desaparece. Sobre el panel oscuro el anillo va en blanco (17:1), que
   también cubre al ítem activo, cuyo fondo es del mismo color que `--foco`. */
.app--portal .side-link:focus-visible { outline-color: var(--marca-contenido); }
.app--portal .side-link__count {
  background: color-mix(in srgb, var(--marca-contenido) 18%, transparent);
  color: var(--marca-contenido);
}
/* La marca de agua: el isotipo, muy tenue, arriba a la derecha del contenido. Es el fondo de las
   pantallas del mockup y el de las páginas del manual. Va en un pseudoelemento absoluto para que
   no empuje nada ni reciba clics. */
.app--portal .main { position: relative; }
.app--portal .main::before {
  content: '';
  position: absolute;
  top: 30px;
  right: 0;
  width: 400px;
  height: 460px;
  /* La imagen se corre con la posición del fondo y no con un `right` negativo: un pseudoelemento
     que asoma por el borde derecho abre 60 px de scroll lateral en todas las pantallas. */
  background: url('/assets/isotipo.svg') no-repeat right -70px center / 460px auto;
  opacity: .05;
  pointer-events: none;
}
.app--portal .main > * { position: relative; }

/* El encabezado: el lockup completo de Grupo VEX y, a la derecha del rótulo, los logos de las
   marcas del grupo en monocromo. Son las marcas, no la identidad: el color y la tipografía siguen
   siendo los de Grupo VEX (ver marca.md, Sub-marcas). */
.app--portal .topbar__logo img { height: 30px; display: block; }
.topbar__marcas { display: flex; align-items: center; gap: 26px; margin-left: 26px; color: var(--tinta); }
.topbar__marcas img { height: 19px; display: block; }
@media (max-width: 1080px) { .topbar__marcas { display: none; } }

/* El inicio: dos columnas, la principal con las cifras, los últimos pedidos y los banners, y la
   lateral con el pedido nuevo, las cuatro fichas y el vendedor. En pantalla angosta la lateral
   pasa ARRIBA: el pedido nuevo es el gesto por el que se entra, y en un teléfono no puede quedar
   debajo de la lista. */
.inicio {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(280px, 1fr);
  gap: 18px;
  align-items: start;
}
.inicio .grid--kpi { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.inicio__lado { display: flex; flex-direction: column; gap: 12px; }
.accesos { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.acceso {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 108px;
  padding: 16px 12px;
  border-radius: var(--radio-lg);
  /* El volumen de las fichas del mockup (Nico, 08/09): un degradé corto del azul profundo hacia el
     azul medio arriba, un filo de luz en el borde superior y la sombra media del contrato. Todo
     sale de los dos tokens de marca con color-mix; nada literal. Al pasar el mouse la ficha sube un
     píxel y al apretarla baja, que es lo que hace que se lea como un botón y no como una tarjeta. */
  background: linear-gradient(180deg, color-mix(in srgb, var(--marca-fuerte) 72%, var(--marca)), var(--marca-fuerte) 85%);
  color: var(--marca-contenido);
  font-family: var(--fuente-titulo);
  font-weight: 600;
  font-size: 14px;
  line-height: 1.2;
  text-align: center;
  box-shadow: inset 0 1px 0 color-mix(in srgb, var(--marca-contenido) 22%, transparent), var(--sombra-lg);
  transition: background .15s, transform .15s, box-shadow .15s;
}
.acceso:hover, .acceso:focus-visible {
  background: linear-gradient(180deg, color-mix(in srgb, var(--marca) 80%, var(--marca-fuerte)), var(--marca) 85%);
  color: var(--marca-contenido);
  text-decoration: none;
  transform: translateY(-1px);
  box-shadow: inset 0 1px 0 color-mix(in srgb, var(--marca-contenido) 26%, transparent), var(--sombra-lg);
}
.acceso:active { transform: translateY(1px); box-shadow: inset 0 1px 0 color-mix(in srgb, var(--marca-contenido) 12%, transparent), var(--sombra-sm); }
.acceso:focus-visible { outline: 2px solid var(--foco); outline-offset: 2px; }
.acceso .ico svg { width: 26px; height: 26px; }
.acceso--principal { flex-direction: row; min-height: 72px; font-size: 18px; gap: 12px; }
.acceso small { font-family: var(--fuente); font-weight: 500; font-size: 12.5px; opacity: .85; }
/* La campanita con la publicación sin leer, en la ficha de Novedades. */
.acceso__aviso {
  position: absolute;
  top: 10px;
  right: 10px;
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  border-radius: 10px;
  background: var(--error);
  color: var(--marca-contenido);
  font-family: var(--fuente);
  font-style: normal;
  font-size: 12px;
  font-weight: 800;
  display: grid;
  place-items: center;
}
.vendedor__nombre { font-family: var(--fuente-titulo); font-size: 17px; font-weight: 600; color: var(--tinta); }
.vendedor__canales { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 4px; }
/* Las cifras, en un gris uniforme y apoyadas sobre la página como en el mockup (Nico, 08/09): el
   relleno es un tinte entre el fondo y el borde, sin borde de color a la izquierda salvo cuando la
   cifra es una señal (hay saldo, hay vencido), que es lo único que el gris no puede decir solo. Los
   pedidos y el vendedor llevan la misma sombra media, y las fichas y los banners la grande: son lo que
   se apoya más arriba. */
.inicio .kpi {
  background: color-mix(in srgb, var(--fondo) 55%, var(--borde));
  border-color: transparent;
}
.inicio .kpi--ok, .inicio .kpi--soft { border-left: 1px solid transparent; }
.inicio .kpi, .inicio .card, .destacados .bloque--banner, .bloques .bloque--banner {
  border-radius: var(--radio-lg);
  box-shadow: var(--sombra);
}
.bloques .bloque--banner, .destacados .bloque--banner { box-shadow: var(--sombra-lg); }
.vendedor__canales .btn { box-shadow: var(--sombra-sm); }
@media (prefers-reduced-motion: reduce) {
  .acceso, .destacado { transition: none; }
  .acceso:hover, .destacado:hover { transform: none; }
}
@media (max-width: 900px) {
  .inicio { grid-template-columns: 1fr; }
  .inicio__lado { order: -1; }
  .inicio .grid--kpi { grid-template-columns: 1fr; }
}

/* Los accesos grandes de Material de marca y de Novedades: las fichas oscuras del mockup
   ("Manual de marca", "Logos", "Material audiovisual", "Catálogo", y en Novedades las fotos de la
   fecha y el newsletter). Un banner ubicado ahí entra en la misma grilla con la misma altura. */
.destacados {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(210px, 100%), 1fr));
  gap: 14px;
}
.destacado {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 150px;
  padding: 20px 16px;
  border-radius: var(--radio-lg);
  /* El mismo volumen que las fichas del inicio (`.acceso`): son el mismo objeto en otra pantalla. */
  background: linear-gradient(180deg, color-mix(in srgb, var(--marca-fuerte) 72%, var(--marca)), var(--marca-fuerte) 85%);
  color: var(--marca-contenido);
  text-align: center;
  box-shadow: inset 0 1px 0 color-mix(in srgb, var(--marca-contenido) 22%, transparent), var(--sombra-lg);
  transition: background .15s, transform .15s, box-shadow .15s;
}
.destacado:hover, .destacado:focus-visible {
  background: linear-gradient(180deg, color-mix(in srgb, var(--marca) 80%, var(--marca-fuerte)), var(--marca) 85%);
  color: var(--marca-contenido);
  text-decoration: none;
  transform: translateY(-1px);
  box-shadow: inset 0 1px 0 color-mix(in srgb, var(--marca-contenido) 26%, transparent), var(--sombra-lg);
}
.destacado:active { transform: translateY(1px); box-shadow: var(--sombra-sm); }
.destacado:focus-visible { outline: 2px solid var(--foco); outline-offset: 2px; }
.destacado .ico svg { width: 28px; height: 28px; }
.destacado__titulo { font-family: var(--fuente-titulo); font-size: 19px; font-weight: 600; line-height: 1.2; }
.destacado__sub { font-size: 12.5px; opacity: .85; max-width: 32ch; }
.destacados .bloque--banner { aspect-ratio: auto; min-height: 150px; height: 100%; }

/* --- El calendario comercial de Material de marca ------------------------------------------
 * Una agenda: el día grande a la izquierda, el resto al lado, una línea fina entre fechas. */
.calendario { list-style: none; margin: 0; padding: 0; }
.calendario li + li { border-top: 1px solid var(--borde-suave); }
.calendario__fila { display: flex; gap: 14px; align-items: flex-start; padding: 12px 4px; color: inherit; }
.calendario__fila--link { border-radius: var(--radio); transition: background .15s; }
.calendario__fila--link:hover, .calendario__fila--link:focus-visible { background: var(--marca-suave); color: var(--marca-suave-contenido); text-decoration: none; }
.calendario__fila--link:focus-visible { outline: 2px solid var(--foco); outline-offset: -2px; }
.calendario__dia {
  flex: none; width: 52px; padding: 6px 0; text-align: center; border-radius: var(--radio);
  background: var(--marca-suave); color: var(--marca-suave-contenido); line-height: 1;
}
.calendario__dia b { display: block; font-family: var(--fuente-titulo); font-size: 22px; font-weight: 600; }
.calendario__dia small { display: block; font-size: 11px; text-transform: uppercase; letter-spacing: .06em; margin-top: 3px; }
.calendario__texto { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1; }
.calendario__titulo { font-weight: 600; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.calendario__ir { flex: none; align-self: center; color: var(--tinta-tenue); }
.mt24 { margin-top: 24px; }
/* La fila de una fecha que ya pasó: se ve apagada y rotulada, nunca igual que lo vigente. */
.tbl tr.is-muted td { color: var(--tinta-tenue); }

/* Los cinco KPI de Nico en una sola fila: cuatro columnas dejarían a la quinta sola abajo. En pantallas
 * medianas vuelve a la grilla del kit. */
.grid--kpi-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); }
@media (max-width: 1280px) { .grid--kpi-5 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 1080px) { .grid--kpi-5 { grid-template-columns: 1fr 1fr; } }
@media (max-width: 640px) { .grid--kpi-5 { grid-template-columns: 1fr; } }

/* La línea del carrito en el teléfono: los importes debajo del nombre, no al costado. A 375 px la
   columna de la derecha (precio, pill del bulto, aviso del próximo escalón) pisaba el nombre y el EAN. */
@media (max-width: 640px) {
  .carrito-linea { grid-template-columns: 56px minmax(0, 1fr); }
  .carrito-linea > .pila { grid-column: 2; text-align: left !important; align-items: flex-start; }
  .ficha-pie__bulto { display: block; font-size: 12px; }
}

/* --- Lo que pidió Tifox el 11/09 ---------------------------------------------------------- */

/* El PVP debajo del costo: chiquito y sin negrita, en lugar del "Ganás" de antes. */
.pvp { font-size: 12px; font-weight: 400; color: var(--tinta-tenue); }
.prod__pvp { margin-top: 4px; }

/* La cabecera de la ficha: la galería, los datos y, a la derecha, la descripción con la foto del
   producto en uso. En un teléfono las tres columnas se apilan. */
.ficha-cab { display: flex; gap: 16px; align-items: flex-start; flex-wrap: wrap; }
.ficha-cab__info { flex: 1 1 240px; min-width: min(240px, 100%); }
.ficha-lado { flex: 1 1 300px; max-width: 440px; min-width: min(260px, 100%); }
.ficha-lado__texto { margin: 10px 0 0; max-width: 60ch; }
.foto-uso {
  display: block; width: 100%; aspect-ratio: 4 / 3; overflow: hidden;
  border: 0; padding: 0; border-radius: var(--radio); background: var(--superficie-alt);
}
.foto-uso img { width: 100%; height: 100%; object-fit: cover; display: block; }
.foto-uso.is-abrible { cursor: zoom-in; }
.foto-uso:focus-visible { outline: 2px solid var(--foco); outline-offset: 2px; }

/* Las pestañas de Material de marca: el segmento del kit, a todo el ancho en un teléfono. */
.seg--tabs { flex-wrap: wrap; }
.seg--tabs .seg__btn { display: inline-flex; gap: 6px; align-items: baseline; }
.seccion-titulo { font-family: var(--fuente-titulo); font-size: 17px; font-weight: 600; margin: 0 0 12px; }
.destacado--claro {
  background: var(--marca-suave); color: var(--marca-suave-contenido); box-shadow: var(--sombra-sm);
}
.destacado--claro:hover, .destacado--claro:focus-visible { background: var(--marca-suave); color: var(--marca-suave-contenido); }
.mt16 { margin-top: 16px; }
