/* =====================================================================
   PORTAL B2B — SISTEMA DE DISEÑO
   ---------------------------------------------------------------------
   Identidad: azul profundo + azul océano + agua, sobre lienzo casi blanco.
   El azul construye jerarquía e identidad; NO baña toda la pantalla.

   Reglas que sigue esta hoja:
   - Un token por decisión. Nada de colores sueltos en las vistas.
   - Sombras teñidas de azul, nunca negras: una sombra negra sobre fondo
     frío se ve sucia. La elevación se percibe, no se anuncia.
   - Escala de espaciado de 4 px. Toda medida es múltiplo.
   - Transiciones de 120-240 ms. Por encima se siente lenta la aplicación.
   - Estado = color + icono + texto. Nunca solo color.
   ===================================================================== */

:root{
  /* ---------- Marca: azules ---------- */
  --primary-darker:#062338;   /* azul profundo, casi tinta */
  --primary-dark:#0A3D5C;     /* azul océano oscuro */
  /* Azul mas vivo que el anterior (#0E5C87) sin irse a un tono infantil:
     mantiene 7:1 sobre blanco, asi que sigue siendo legible para todos. */
  --primary:#0B62A8;          /* azul océano — color de acción */
  --primary-hover:#09538F;
  --primary-active:#074478;
  --primary-light:#2F94D6;    /* azul claro */
  --primary-soft:#E7F2FB;     /* azul muy claro, fondos */
  --primary-softer:#F3F9FD;

  /* Secundario: agua. Solo acentos y datos, nunca acciones. */
  /* Tonos ajustados para superar 4.5:1 sobre su propio fondo suave (WCAG AA). */
  --aqua:#0E8296;
  --aqua-light:#3FC6DA;
  --aqua-soft:#E2F6FA;

  /* ---------- Neutros ---------- */
  --bg:#F3F7FA;
  --surface:#FFFFFF;
  --surface-2:#F7FAFC;
  --surface-3:#EDF3F8;

  --text:#0F2233;
  --text-2:#3D5266;
  --text-3:#607386;
  --border:#DBE5EE;
  --border-2:#EBF1F6;
  --border-strong:#C3D3E0;

  /* ---------- Semánticos ---------- */
  --success:#0A8562; --success-soft:#E2F6EF; --success-border:#AEE0CE;
  --warning:#A66A05; --warning-soft:#FEF4E0; --warning-border:#F2DCAE;
  --danger:#C03A2B;  --danger-soft:#FDECE8;  --danger-border:#F3C6BE;
  --info:#0E5C87;    --info-soft:#E8F1F8;    --info-border:#C2DBEC;

  /* Alias heredados para no romper vistas antiguas. */
  --brand:var(--primary); --brand-2:var(--primary-light); --brand-soft:var(--primary-soft);
  --amber:var(--warning); --amber-soft:var(--warning-soft);
  --danger-soft2:var(--danger-soft); --blue:var(--primary); --blue-soft:var(--primary-soft);
  --ink:var(--text); --ink-2:var(--text-2); --ink-3:var(--text-3);
  --muted:var(--text-3); --line:var(--border); --line-2:var(--border-2);
  --canvas:var(--bg);
  --r-sm:10px; --r:14px; --r-lg:18px;
  /* Tres capas: un contorno finisimo que define el borde, una sombra corta
     que pega el elemento a la superficie y otra difusa que da altura. Una
     sola capa se ve plana o sucia. */
  --sh-1:0 0 0 1px rgba(11,98,168,.04), 0 1px 2px rgba(10,45,80,.06), 0 2px 6px rgba(10,45,80,.05);
  --sh-2:0 0 0 1px rgba(11,98,168,.05), 0 2px 5px rgba(10,45,80,.07), 0 8px 20px rgba(10,45,80,.07);
  --sh-3:0 0 0 1px rgba(11,98,168,.06), 0 6px 14px rgba(10,45,80,.10), 0 18px 40px rgba(10,45,80,.10);

  /* ---------- Radios ---------- */
  --r-xs:7px; --r-xl:24px; --r-full:999px;

  /* ---------- Elevación ---------- */
  --sh-0:0 1px 2px rgba(10,61,92,.05);
  --sh-4:0 0 0 1px rgba(11,98,168,.07), 0 10px 24px rgba(6,35,56,.14), 0 32px 68px rgba(6,35,56,.18);
  --ring:0 0 0 3px rgba(11,98,168,.20);
  --ring-danger:0 0 0 3px rgba(192,58,43,.20);

  /* ---------- Espaciado ---------- */
  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px;
  --sp-5:20px; --sp-6:24px; --sp-7:32px; --sp-8:40px; --sp-9:56px;

  /* ---------- Tipografía ---------- */
  --fs-caption:11.5px; --fs-sm:12.5px; --fs-base:14px; --fs-md:15px;
  --fs-lg:17px; --fs-xl:20px; --fs-2xl:25px; --fs-3xl:31px; --fs-4xl:38px;

  /* ---------- Movimiento ---------- */
  --t-rapido:120ms cubic-bezier(.4,0,.2,1);
  --t:170ms cubic-bezier(.4,0,.2,1);
  --t-lento:240ms cubic-bezier(.16,1,.3,1);

  --hdr-h:62px;
  --ancho:1400px;
}

/* Respeta a quien pidió menos movimiento en su sistema operativo. */
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;
    transition-duration:.01ms!important;scroll-behavior:auto!important}
}

/* =====================================================================
   BASE
   ===================================================================== */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0;background:var(--bg);color:var(--text);
  font-family:var(--f-texto);font-size:var(--fs-base);line-height:1.55;
  -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;
}
img,svg{max-width:100%}
button,input,select,textarea{font:inherit;color:inherit}
button{cursor:pointer;background:none;border:0;padding:0}
a{color:var(--primary);text-decoration:none}
a:hover{color:var(--primary-hover)}

h1,h2,h3,h4{margin:0;font-family:var(--f-display);color:var(--text);
  letter-spacing:-.017em;line-height:1.25;font-weight:700}
h1{font-size:var(--fs-2xl)}
h2{font-size:var(--fs-lg)}
h3{font-size:var(--fs-md)}
p{margin:0 0 var(--sp-3)}
p:last-child{margin-bottom:0}

.mono{font-family:var(--f-mono);font-variant-numeric:tabular-nums;letter-spacing:-.01em}
.muted{color:var(--text-3)}
.crecer{flex:1;min-width:0}
.der{margin-left:auto}
.sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0}
.oculto{display:none!important}

.mb-2{margin-bottom:var(--sp-2)}.mb-3{margin-bottom:var(--sp-3)}.mb-4{margin-bottom:var(--sp-5)}
.mt-2{margin-top:var(--sp-2)}.mt-3{margin-top:var(--sp-3)}.mt-4{margin-top:var(--sp-5)}
.fila{display:flex;align-items:center;gap:var(--sp-2)}
.fila-wrap{display:flex;align-items:center;gap:var(--sp-3);flex-wrap:wrap}
.pila{display:flex;flex-direction:column;gap:var(--sp-3)}
.divider{height:1px;background:var(--border-2);margin:var(--sp-4) 0}

/* Foco visible SIEMPRE. */
:focus-visible{outline:2px solid var(--primary-light);outline-offset:2px;border-radius:var(--r-xs)}

@keyframes entrar{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}

/* =====================================================================
   LAYOUT
   ===================================================================== */
.main{max-width:var(--ancho);margin:0 auto;padding:var(--sp-6) var(--sp-5) var(--sp-9);
  animation:entrar var(--t-lento) both}
@media(max-width:640px){.main{padding:var(--sp-4) var(--sp-3) var(--sp-8)}}

.pagina-head{display:flex;align-items:flex-end;gap:var(--sp-4);flex-wrap:wrap;
  margin-bottom:var(--sp-5)}
.pagina-head>*:first-child{flex:1;min-width:min(100%,240px)}
.pagina-sub{color:var(--text-3);font-size:var(--fs-sm);margin-top:3px;max-width:76ch}
.eyebrow{font-size:10.5px;font-weight:700;letter-spacing:.09em;text-transform:uppercase;
  color:var(--text-3)}

/* =====================================================================
   CABECERA / NAVEGACIÓN
   ===================================================================== */
.hdr{
  position:sticky;top:0;z-index:60;
  background:rgba(255,255,255,.88);backdrop-filter:saturate(180%) blur(12px);
  border-bottom:1px solid var(--border);
}
.hdr-in{max-width:var(--ancho);margin:0 auto;height:var(--hdr-h);
  padding:0 var(--sp-5);display:flex;align-items:center;gap:var(--sp-4)}
@media(max-width:640px){.hdr-in{padding:0 var(--sp-3);gap:var(--sp-2)}}

.brand{display:flex;align-items:center;gap:10px;color:var(--text);flex:0 0 auto}
.brand:hover{color:var(--text)}
.brand-mark{
  width:34px;height:34px;border-radius:10px;flex:0 0 auto;
  background:linear-gradient(140deg,var(--primary) 0%,var(--primary-dark) 70%);
  color:#fff;display:grid;place-items:center;
  font-family:var(--f-display);font-weight:800;font-size:16px;letter-spacing:-.03em;
  box-shadow:0 2px 6px rgba(10,61,92,.24);
}
.brand-txt{font-family:var(--f-display);font-weight:700;font-size:15px;
  letter-spacing:-.02em;line-height:1.15}
.brand-sub{font-size:10.5px;color:var(--text-3);line-height:1.15}
@media(max-width:520px){.brand-sub{display:none}}

.nav{display:flex;align-items:center;gap:2px;flex:1;min-width:0}
.nav>a{
  display:inline-flex;align-items:center;gap:7px;
  padding:8px 12px;border-radius:var(--r-sm);
  font-size:13.5px;font-weight:600;color:var(--text-2);
  white-space:nowrap;position:relative;
  transition:background var(--t-rapido),color var(--t-rapido);
}
.nav>a:hover{background:var(--surface-3);color:var(--primary-dark)}
.nav>a.on{color:var(--primary);background:var(--primary-soft)}
/* Subrayado del elemento activo: ancla la posición sin gritar. */
.nav>a.on::after{
  content:'';position:absolute;left:12px;right:12px;bottom:-11px;height:2px;
  background:var(--primary);border-radius:2px 2px 0 0;
}
.nav>a svg{opacity:.85}
.nav>a.on svg{opacity:1}

.usr{display:flex;align-items:center;gap:var(--sp-2);margin-left:auto;
  padding-left:var(--sp-4);border-left:1px solid var(--border-2)}
.usr-nom{font-size:13px;font-weight:650;line-height:1.2;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:170px}
.usr-rol{font-size:10.5px;color:var(--text-3);line-height:1.2;
  text-transform:uppercase;letter-spacing:.06em;font-weight:600}

.icon-btn{
  width:34px;height:34px;border-radius:var(--r-sm);display:grid;place-items:center;
  color:var(--text-2);border:1px solid transparent;flex:0 0 auto;
  transition:background var(--t-rapido),color var(--t-rapido),border-color var(--t-rapido);
}
.icon-btn:hover{background:var(--surface-3);color:var(--primary-dark);border-color:var(--border-2)}

/* Contador del carrito en la cabecera */
.nav-carrito{position:relative}
.badge-num{
  position:absolute;top:-4px;right:-5px;min-width:17px;height:17px;padding:0 4px;
  border-radius:var(--r-full);background:var(--aqua);color:#fff;
  font-size:10px;font-weight:800;display:grid;place-items:center;
  border:2px solid var(--surface);font-variant-numeric:tabular-nums;
}
@keyframes latido{0%{transform:scale(1)}40%{transform:scale(1.3)}100%{transform:scale(1)}}
.badge-num.pulso{animation:latido 340ms cubic-bezier(.34,1.4,.64,1)}

.burger{display:none}
@media(max-width:1080px){
  .burger{display:grid}
  .nav{
    position:fixed;inset:var(--hdr-h) 0 auto 0;
    flex-direction:column;align-items:stretch;gap:2px;
    background:var(--surface);border-bottom:1px solid var(--border);
    padding:var(--sp-3);box-shadow:var(--sh-3);
    max-height:calc(100dvh - var(--hdr-h));overflow-y:auto;
    transform:translateY(-10px);opacity:0;
    /* `opacity:0` NO saca al panel del hit-testing: sigue siendo un rectangulo
       fijo sobre media pantalla. `pointer-events:none` se hereda, pero un
       descendiente puede volver a ponerlo en `auto` y reactivar la captura de
       toques de todo su subarbol. `visibility:hidden` no se puede revertir asi
       desde un hijo salvo que se pida explicitamente, y ademas saca los
       enlaces del orden de tabulacion. Es el unico cierre real. */
    pointer-events:none;visibility:hidden;
    transition:transform var(--t),opacity var(--t),visibility 0s linear var(--t);
  }
  .nav.abierto{
    transform:none;opacity:1;pointer-events:auto;visibility:visible;
    transition:transform var(--t),opacity var(--t),visibility 0s;
  }
  .nav>a{padding:11px 12px;font-size:14.5px}
  .nav>a.on::after{display:none}
  .usr{margin-left:0;padding-left:0;border-left:0;
    border-top:1px solid var(--border-2);margin-top:var(--sp-2);padding-top:var(--sp-3)}
  .usr-nom{max-width:none}
}

/* =====================================================================
   BOTONES
   ===================================================================== */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:7px;
  padding:9px 15px;min-height:38px;
  border-radius:var(--r-sm);border:1px solid transparent;
  font-size:13.5px;font-weight:650;letter-spacing:-.005em;white-space:nowrap;
  transition:background var(--t-rapido),border-color var(--t-rapido),
             box-shadow var(--t-rapido),transform 90ms ease,color var(--t-rapido);
}
.btn:active:not(:disabled){transform:translateY(1px)}
.btn:disabled{opacity:.5;cursor:not-allowed}

.btn-primario{background:var(--primary);color:#fff;box-shadow:var(--sh-1)}
.btn-primario:hover:not(:disabled){background:var(--primary-hover);box-shadow:var(--sh-2)}

.btn-sec{background:var(--surface);color:var(--text-2);border-color:var(--border);box-shadow:var(--sh-0)}
.btn-sec:hover:not(:disabled){border-color:var(--border-strong);color:var(--primary-dark);
  background:var(--surface-2)}

.btn-fantasma{background:transparent;color:var(--text-2)}
.btn-fantasma:hover:not(:disabled){background:var(--surface-3);color:var(--primary-dark)}

.btn-peligro{background:var(--danger);color:#fff}
.btn-peligro:hover:not(:disabled){background:#9C3227}

/* ---------------------------------------------------------------------
   BOTONES POR SIGNIFICADO
   El color dice QUE hace el boton, no cual es mas bonito:

     azul (primario) accion principal de la pantalla
     verde (exito)   confirmar, pagar, cerrar un proceso a favor del usuario
     ambar (alerta)  sigue adelante pero con una consecuencia que mirar
     rojo (peligro)  cancelar, borrar, algo que cuesta deshacer

   Existen como CLASES y no como estilos en linea a proposito: cuando el verde
   se escribia a mano en cada pantalla, tres botones de pagar acababan con tres
   verdes distintos y ninguno se podia cambiar de una vez.

   El color nunca va solo: estos botones llevan siempre texto que dice la
   accion, porque alrededor del 8% de los hombres no distingue rojo de verde.
   --------------------------------------------------------------------- */
.btn-exito{background:var(--success);color:#fff;box-shadow:var(--sh-1)}
.btn-exito:hover:not(:disabled){background:#095F46;box-shadow:var(--sh-2)}
.btn-exito:active:not(:disabled){background:#074B37}

.btn-alerta{background:var(--warning);color:#fff;box-shadow:var(--sh-1)}
.btn-alerta:hover:not(:disabled){background:#7F4F05}
.btn-alerta:active:not(:disabled){background:#6A4204}

/* Barra de progreso. Va aqui y no en linea por lo mismo que los botones:
   repetida en cada pantalla acaba con un azul distinto en cada una. */
.barra-prog{height:8px;border-radius:4px;background:var(--surface-3);overflow:hidden}
.barra-prog>span{display:block;height:100%;background:var(--primary);
  transition:width var(--t)}

.btn-sm{padding:6px 11px;min-height:32px;font-size:12.5px;gap:5px;border-radius:var(--r-xs)}
.btn-lg{padding:12px 22px;min-height:46px;font-size:15px}
.btn-bloque{width:100%}

/* Estado ocupado: el botón informa por sí mismo, sin bloquear la pantalla. */
.btn[data-cargando]{color:transparent!important;position:relative;pointer-events:none}
.btn[data-cargando]>*{visibility:hidden}
.btn[data-cargando]::after{
  content:'';position:absolute;width:15px;height:15px;border-radius:50%;
  border:2px solid #fff;border-top-color:transparent;
  animation:girar .6s linear infinite;visibility:visible;
}
.btn-sec[data-cargando]::after,.btn-fantasma[data-cargando]::after{
  border-color:var(--text-2);border-top-color:transparent}
@keyframes girar{to{transform:rotate(360deg)}}

/* =====================================================================
   TARJETAS
   ===================================================================== */
.card{
  background:var(--surface);border:1px solid var(--border);
  border-radius:var(--r-lg);box-shadow:var(--sh-1);
  /* `overflow:hidden` recorta al borde redondeado: lo necesitan las tarjetas
     con imagen, que si no se salen por las esquinas. Pero recorta TAMBIÉN
     cualquier panel `position:absolute` que salga de la tarjeta — por eso el
     desplegable de categorías aparecía cortado.
     Se conserva el recorte solo donde hace falta (`.card-recorta`) y la
     tarjeta normal deja salir lo que la desborda. */
  min-width:0;
}
/* Tarjetas cuyo contenido debe quedarse dentro del borde: imágenes a sangre,
   cabeceras de color, barras de progreso. */
.card-recorta,
.card:has(> img:first-child),
.card:has(> .card-img){overflow:hidden}
.card-pad{padding:var(--sp-5)}
@media(max-width:640px){.card-pad{padding:var(--sp-4)}}
.card-head{display:flex;align-items:center;gap:var(--sp-3);
  padding:var(--sp-4) var(--sp-5);border-bottom:1px solid var(--border-2);
  background:var(--surface)}

/* =====================================================================
   KPI
   ===================================================================== */
.kpis{display:grid;gap:var(--sp-3);
  grid-template-columns:repeat(auto-fit,minmax(min(100%,208px),1fr))}

.kpi{
  position:relative;overflow:hidden;
  background:var(--surface);border:1px solid var(--border);
  border-radius:var(--r-lg);padding:var(--sp-4) var(--sp-5);
  box-shadow:var(--sh-1);min-width:0;
  transition:box-shadow var(--t),border-color var(--t);
}
.kpi:hover{box-shadow:var(--sh-2);border-color:var(--border-strong)}
/* Filo de color a la izquierda: identifica el bloque sin llenarlo de color. */
.kpi::before{content:'';position:absolute;left:0;top:0;bottom:0;width:3px;
  background:var(--primary-light);opacity:.85}
.kpi.acento-aqua::before{background:var(--aqua)}
.kpi.acento-ok::before{background:var(--success)}
.kpi.acento-alerta::before{background:var(--warning)}
.kpi.acento-peligro::before{background:var(--danger)}

.kpi-top{display:flex;align-items:center;gap:var(--sp-2);margin-bottom:var(--sp-2)}
.kpi-ico{
  width:30px;height:30px;border-radius:var(--r-sm);flex:0 0 auto;
  display:grid;place-items:center;background:var(--primary-soft);color:var(--primary);
}
.kpi.acento-aqua .kpi-ico{background:var(--aqua-soft);color:var(--aqua)}
.kpi.acento-ok .kpi-ico{background:var(--success-soft);color:var(--success)}
.kpi.acento-alerta .kpi-ico{background:var(--warning-soft);color:var(--warning)}
.kpi.acento-peligro .kpi-ico{background:var(--danger-soft);color:var(--danger)}

.kpi-val{
  font-family:var(--f-display);font-size:var(--fs-2xl);font-weight:750;
  letter-spacing:-.028em;line-height:1.1;color:var(--text);
  font-variant-numeric:tabular-nums;overflow-wrap:anywhere;
}
.kpi-sub{font-size:var(--fs-sm);color:var(--text-3);margin-top:4px;line-height:1.35}
.kpi-delta{display:inline-flex;align-items:center;gap:3px;font-size:var(--fs-sm);
  font-weight:650;margin-top:5px}
.kpi-delta.sube{color:var(--success)}
.kpi-delta.baja{color:var(--danger)}
.kpi-delta.plano{color:var(--text-3)}

/* Barra de progreso fina, para cupo de crédito y similares. */
.barra{height:6px;border-radius:var(--r-full);background:var(--surface-3);
  overflow:hidden;margin-top:var(--sp-3)}
.barra>span{display:block;height:100%;border-radius:var(--r-full);
  background:var(--primary);transition:width var(--t-lento)}
.barra.alerta>span{background:var(--warning)}
.barra.peligro>span{background:var(--danger)}
.cupo-barra{height:6px;border-radius:var(--r-full);background:var(--surface-3);overflow:hidden}
.cupo-barra>span{display:block;height:100%;background:var(--primary)}
.cupo.excede .cupo-barra>span{background:var(--danger)}

/* =====================================================================
   FORMULARIOS
   ===================================================================== */
.campo{display:block;margin-bottom:var(--sp-4)}
.lbl{display:block;font-size:var(--fs-sm);font-weight:650;color:var(--text-2);
  margin-bottom:6px}
.lbl-ayuda{font-weight:400;color:var(--text-3);margin-left:5px}

.inp{
  width:100%;padding:9px 12px;min-height:40px;
  background:var(--surface);color:var(--text);
  border:1px solid var(--border);border-radius:var(--r-sm);
  font-size:var(--fs-base);
  transition:border-color var(--t-rapido),box-shadow var(--t-rapido),background var(--t-rapido);
}
.inp::placeholder{color:var(--text-3);opacity:.8}
.inp:hover:not(:focus):not(:disabled){border-color:var(--border-strong)}
.inp:focus{outline:none;border-color:var(--primary);box-shadow:var(--ring)}
.inp:disabled{background:var(--surface-2);color:var(--text-3);cursor:not-allowed}
.inp-error{border-color:var(--danger)}
.inp-error:focus{border-color:var(--danger);box-shadow:var(--ring-danger)}
textarea.inp{min-height:auto;resize:vertical;line-height:1.5}
select.inp{
  appearance:none;padding-right:34px;cursor:pointer;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23607386' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 11px center;
}
input[type=file].inp{padding:8px 12px;cursor:pointer}
.campo-error{display:flex;align-items:flex-start;gap:5px;
  color:var(--danger);font-size:var(--fs-sm);margin-top:5px;font-weight:550}
.campo-error svg{flex:0 0 auto;margin-top:1px}

.rejilla-campos{display:grid;gap:var(--sp-3);
  grid-template-columns:repeat(auto-fit,minmax(min(100%,200px),1fr))}

.buscador{position:relative;display:flex;align-items:center}
.buscador>svg{position:absolute;left:12px;color:var(--text-3);pointer-events:none}
.buscador .inp{padding-left:38px}

/* Interruptor accesible para "activo / inactivo". */
.switch{display:inline-flex;align-items:center;gap:9px;cursor:pointer;font-size:var(--fs-base)}
.switch input{position:absolute;opacity:0;width:0;height:0}
.switch .pista{width:38px;height:22px;border-radius:var(--r-full);background:var(--border-strong);
  position:relative;transition:background var(--t);flex:0 0 auto}
.switch .pista::after{content:'';position:absolute;top:2px;left:2px;width:18px;height:18px;
  border-radius:50%;background:#fff;box-shadow:var(--sh-1);transition:transform var(--t)}
.switch input:checked + .pista{background:var(--primary)}
.switch input:checked + .pista::after{transform:translateX(16px)}
.switch input:focus-visible + .pista{box-shadow:var(--ring)}

/* =====================================================================
   CHIPS Y ETIQUETAS
   ===================================================================== */
.chips{display:flex;gap:7px;flex-wrap:wrap}
.chip{
  padding:6px 12px;border-radius:var(--r-full);
  border:1px solid var(--border);background:var(--surface);
  font-size:12.5px;font-weight:600;color:var(--text-2);
  transition:all var(--t-rapido);white-space:nowrap;
}
.chip:hover{border-color:var(--primary-light);color:var(--primary)}
.chip.on{background:var(--primary);border-color:var(--primary);color:#fff}

.tag{
  display:inline-flex;align-items:center;gap:4px;
  padding:3px 8px;border-radius:var(--r-xs);
  font-size:11.5px;font-weight:650;
  border:1px solid transparent;white-space:nowrap;
}
.tag svg{flex:0 0 auto}
.tag-neutro{background:var(--surface-3);color:var(--text-2);border-color:var(--border-2)}
.tag-brand{background:var(--primary-soft);color:var(--primary);border-color:var(--info-border)}
.tag-blue{background:var(--primary-soft);color:var(--primary);border-color:var(--info-border)}
.tag-aqua{background:var(--aqua-soft);color:var(--aqua);border-color:#BEE5EC}
.tag-ok{background:var(--success-soft);color:var(--success);border-color:var(--success-border)}
.tag-amber{background:var(--warning-soft);color:var(--warning);border-color:var(--warning-border)}
.tag-danger{background:var(--danger-soft);color:var(--danger);border-color:var(--danger-border)}

/* =====================================================================
   AVISOS
   ===================================================================== */
.aviso{
  display:flex;align-items:flex-start;gap:10px;
  padding:12px 14px;border-radius:var(--r);
  font-size:13.5px;line-height:1.5;border:1px solid;
}
.aviso svg{flex:0 0 auto;margin-top:1px}
.aviso-info{background:var(--info-soft);color:var(--primary-dark);border-color:var(--info-border)}
.aviso-ok{background:var(--success-soft);color:var(--success);border-color:var(--success-border)}
.aviso-amber{background:var(--warning-soft);color:var(--warning);border-color:var(--warning-border)}
.aviso-error{background:var(--danger-soft);color:var(--danger);border-color:var(--danger-border)}
/* Aviso pulsable: enlaza con la acción que lo resuelve. */
button.aviso{width:100%;text-align:left;cursor:pointer;transition:filter var(--t-rapido)}
button.aviso:hover{filter:brightness(.975)}

/* =====================================================================
   TABLAS
   ===================================================================== */
.tabla-scroll{overflow-x:auto;-webkit-overflow-scrolling:touch}
.tabla{width:100%;border-collapse:collapse;font-size:13.5px}
.tabla th{
  text-align:left;padding:11px var(--sp-4);
  font-size:10.5px;font-weight:700;letter-spacing:.075em;text-transform:uppercase;
  color:var(--text-3);background:var(--surface-2);
  border-bottom:1px solid var(--border);white-space:nowrap;
}
.tabla td{padding:11px var(--sp-4);border-bottom:1px solid var(--border-2);vertical-align:middle}
.tabla tbody tr{transition:background var(--t-rapido)}
.tabla tbody tr:hover{background:var(--primary-softer)}
.tabla tbody tr:last-child td{border-bottom:0}
.td-num{text-align:right;font-family:var(--f-mono);font-variant-numeric:tabular-nums;
  white-space:nowrap}
.td-nom{max-width:280px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* En móvil la tabla se convierte en fichas apiladas. Un scroll horizontal
   infinito no es "responsive": es una tabla escondida. */
@media(max-width:720px){
  /* Las vistas fijan un min-width en linea para que la tabla no se comprima
     en escritorio. En modo ficha ese ancho minimo sobra y provocaria scroll
     horizontal, justo lo que se quiere evitar. */
  .tabla.apilable{min-width:0!important}
  .tabla-scroll:has(.tabla.apilable){overflow-x:visible}
  .tabla.apilable thead{display:none}
  .tabla.apilable,.tabla.apilable tbody,.tabla.apilable tr,.tabla.apilable td{display:block;width:auto}
  .tabla.apilable tr{
    border:1px solid var(--border);border-radius:var(--r);
    padding:var(--sp-3);margin-bottom:var(--sp-3);background:var(--surface);
    box-shadow:var(--sh-0);
  }
  .tabla.apilable tr:hover{background:var(--surface)}
  .tabla.apilable td{
    border:0;padding:5px 0;display:flex;align-items:center;gap:var(--sp-3);
    justify-content:space-between;text-align:right;
  }
  /* La etiqueta viene de data-col, que ponen las vistas. */
  .tabla.apilable td::before{
    content:attr(data-col);flex:0 0 auto;text-align:left;
    font-size:10.5px;font-weight:700;letter-spacing:.07em;text-transform:uppercase;
    color:var(--text-3);
  }
  .tabla.apilable td:empty{display:none}
  .tabla.apilable .td-nom{max-width:none;white-space:normal;text-align:right}
  .tabla.apilable tr td:first-child{
    border-bottom:1px solid var(--border-2);padding-bottom:var(--sp-2);margin-bottom:var(--sp-2)}
}

/* =====================================================================
   PAGINACIÓN
   ===================================================================== */
.paginacion{display:flex;gap:5px;align-items:center;justify-content:center;
  flex-wrap:wrap;margin-top:var(--sp-5)}
.paginacion button{
  min-width:36px;height:36px;padding:0 11px;border-radius:var(--r-sm);
  border:1px solid var(--border);background:var(--surface);
  font-size:13px;font-weight:600;color:var(--text-2);
  transition:all var(--t-rapido);
}
.paginacion button:hover:not(:disabled){border-color:var(--primary-light);color:var(--primary)}
.paginacion button.on{background:var(--primary);border-color:var(--primary);color:#fff}
.paginacion button:disabled{opacity:.4;cursor:not-allowed}

/* =====================================================================
   PRODUCTOS
   ===================================================================== */
.rejilla-prod{
  display:grid;gap:var(--sp-4);
  /* min() evita que la tarjeta desborde su columna en pantallas estrechas. */
  grid-template-columns:repeat(auto-fill,minmax(min(100%,236px),1fr));
}
/* En telefono la prioridad es recorrer muchos productos rapido, asi que
   se fuerzan DOS columnas en vez de dejarlo al auto-fill, que a 360 px caia
   a una sola. Por debajo de 320 px se vuelve a una para no ilegibilizarlo. */
@media(max-width:560px){
  .rejilla-prod{gap:var(--sp-2);grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media(max-width:319px){
  .rejilla-prod{grid-template-columns:1fr}
}

/* Tarjeta compacta en telefono: menos aire, misma legibilidad. */
@media(max-width:560px){
  .prod-cuerpo{padding:10px 11px;gap:2px}
  .prod-nom{font-size:12.5px;min-height:2.6em;-webkit-line-clamp:2}
  .prod-sku{font-size:9.5px}
  .prod-precio{font-size:16.5px;padding-top:6px}
  .prod-iva{font-size:9.5px}
  .prod-meta{gap:3px;font-size:10px}
  .prod-meta .tag{padding:2px 5px;font-size:9.5px}
  .prod-pie{padding:0 11px 11px;gap:6px}
  .prod-marca{font-size:8.5px;padding:2px 5px;left:6px;top:6px}
  .prod-fav{width:26px;height:26px;right:6px;top:6px}
}

.prod{
  display:flex;flex-direction:column;min-width:0;
  background:var(--surface);border:1px solid var(--border);
  border-radius:var(--r-lg);overflow:hidden;box-shadow:var(--sh-0);
  transition:box-shadow var(--t),transform var(--t),border-color var(--t);
}
.prod:hover{box-shadow:var(--sh-3);transform:translateY(-2px);border-color:var(--border-strong)}

.prod-img{
  position:relative;aspect-ratio:4/3;background:var(--surface-2);
  display:grid;place-items:center;overflow:hidden;
  border-bottom:1px solid var(--border-2);
}
/* contain, no cover: un producto recortado no se reconoce. */
.prod-img img{width:100%;height:100%;object-fit:contain;padding:12px;
  transition:transform var(--t-lento)}
.prod:hover .prod-img img{transform:scale(1.04)}
.prod-img .ph{color:var(--border-strong);display:grid;place-items:center}

.prod-marca{
  position:absolute;left:8px;top:8px;
  background:rgba(6,35,56,.82);color:#fff;
  font-size:9.5px;font-weight:800;letter-spacing:.06em;
  padding:3px 7px;border-radius:var(--r-xs);
}
.prod-fav{
  position:absolute;right:8px;top:8px;width:30px;height:30px;border-radius:50%;
  background:rgba(255,255,255,.94);
  display:grid;place-items:center;color:var(--text-3);
  box-shadow:var(--sh-1);transition:color var(--t-rapido),transform var(--t-rapido);
}
.prod-fav:hover{transform:scale(1.08)}
.prod-fav.on{color:var(--warning)}
.prod-fav.on svg{fill:currentColor}

.prod-cuerpo{padding:var(--sp-3) var(--sp-4);display:flex;flex-direction:column;
  gap:3px;flex:1;min-width:0}
.prod-sku{font-size:10.5px;color:var(--text-3);letter-spacing:.02em;font-weight:600}
.prod-nom{
  font-size:13.5px;font-weight:650;line-height:1.35;color:var(--text);
  font-family:var(--f-texto);letter-spacing:-.006em;
  /* Dos líneas máximo: mantiene todas las tarjetas a la misma altura. */
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;
  overflow:hidden;min-height:2.7em;
}
.prod-meta{display:flex;gap:5px;flex-wrap:wrap;align-items:center;
  font-size:11px;color:var(--text-3);margin-top:2px}
.prod-precio{
  font-family:var(--f-display);font-size:var(--fs-xl);font-weight:750;
  letter-spacing:-.025em;color:var(--primary-dark);margin-top:auto;padding-top:var(--sp-2);
  font-variant-numeric:tabular-nums;
}
.prod-iva{font-size:10.5px;color:var(--text-3);margin-top:-2px}
.prod-pie{display:flex;gap:7px;align-items:center;padding:0 var(--sp-4) var(--sp-4)}
.prod-pie .btn{flex:1;min-width:0}
@media(max-width:420px){
  .prod-pie{flex-direction:column;align-items:stretch}
  .prod-pie .stepper{width:100%;justify-content:space-between}
  .prod-pie .stepper input{flex:1 1 0;width:auto;min-width:0}
}

.stepper{
  display:inline-flex;align-items:center;flex:0 0 auto;
  border:1px solid var(--border);border-radius:var(--r-sm);
  background:var(--surface);overflow:hidden;height:38px;
}
.stepper button{
  width:30px;height:100%;display:grid;place-items:center;color:var(--text-2);
  transition:background var(--t-rapido),color var(--t-rapido);
}
.stepper button:hover{background:var(--surface-3);color:var(--primary)}
/* min-width:0 es obligatorio: los controles de formulario tienen un ancho
   intrinseco (unos 20 caracteres) y dentro de un flex NO se encogen por
   debajo de el salvo que se anule. Sin esto, el campo desborda su stepper
   en pantallas estrechas. */
.stepper input{
  width:42px;min-width:0;height:100%;text-align:center;border:0;background:transparent;
  font-family:var(--f-mono);font-size:13px;font-weight:650;
  font-variant-numeric:tabular-nums;-moz-appearance:textfield;
}
.stepper input::-webkit-outer-spin-button,
.stepper input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.stepper input:focus{outline:none;background:var(--primary-softer)}

.btn-agregar.en-carrito{background:var(--success)}
.btn-agregar.en-carrito:hover:not(:disabled){background:#0A6B4F}
.disp{font-weight:650;color:var(--success)}
.disp.agotado{color:var(--danger)}

/* =====================================================================
   CARRITO
   ===================================================================== */
.tienda{display:grid;gap:var(--sp-5);grid-template-columns:1fr 336px;align-items:start}
@media(max-width:1100px){.tienda{grid-template-columns:1fr}}
.carrito-wrap{position:sticky;top:calc(var(--hdr-h) + var(--sp-5))}
@media(max-width:1100px){
  .carrito-wrap{position:sticky;top:auto;bottom:0;z-index:40;margin:0 calc(-1 * var(--sp-3))}
  .carrito{border-radius:var(--r-lg) var(--r-lg) 0 0;box-shadow:var(--sh-4)}
}
.carrito{display:flex;flex-direction:column;max-height:calc(100dvh - var(--hdr-h) - var(--sp-8))}
.carrito-tog{
  display:flex;align-items:center;gap:10px;width:100%;
  padding:var(--sp-4);border-bottom:1px solid var(--border-2);
  font-weight:650;font-size:14px;color:var(--text);
}
.carrito-cuerpo{overflow-y:auto;padding:var(--sp-4);display:flex;flex-direction:column;gap:var(--sp-3)}
.carrito-items{display:flex;flex-direction:column;gap:var(--sp-2)}
.carrito-item{
  display:flex;gap:10px;align-items:center;padding:9px;border-radius:var(--r-sm);
  background:var(--surface-2);border:1px solid var(--border-2);
  animation:entrar var(--t) both;
}
.carrito-item-nom{font-size:12.5px;font-weight:600;line-height:1.35;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.totales{display:flex;flex-direction:column;gap:6px;padding-top:var(--sp-3);
  border-top:1px solid var(--border-2)}
.totales-fila{display:flex;justify-content:space-between;align-items:baseline;
  font-size:13px;color:var(--text-2);gap:var(--sp-3)}
.totales-fila.grande{font-size:var(--fs-lg);font-weight:750;color:var(--text);
  font-family:var(--f-display);letter-spacing:-.02em}
.totales-fila .num{font-family:var(--f-mono);font-variant-numeric:tabular-nums}

/* =====================================================================
   ESTADOS: VACÍO Y CARGA
   ===================================================================== */
.vacio{
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  text-align:center;padding:var(--sp-9) var(--sp-5);color:var(--text-3);
  grid-column:1/-1;
}
.vacio-ico{
  width:60px;height:60px;border-radius:var(--r-lg);margin-bottom:var(--sp-4);
  background:var(--primary-soft);color:var(--primary-light);
  display:grid;place-items:center;
}
.vacio-titulo{font-family:var(--f-display);font-size:var(--fs-lg);font-weight:700;
  color:var(--text);margin-bottom:5px;letter-spacing:-.018em}
.vacio p{max-width:44ch;font-size:13.5px;line-height:1.55}

/* Esqueletos: el brillo recorre de izquierda a derecha, sin parpadeo. */
@keyframes brillo{to{background-position-x:-200%}}
.sk{
  background:linear-gradient(90deg,var(--surface-3) 25%,#F4F8FB 37%,var(--surface-3) 63%);
  background-size:200% 100%;animation:brillo 1.4s ease-in-out infinite;
  border-radius:var(--r-sm);
}
.sk-linea{height:12px;margin-bottom:9px}
.sk-linea:last-child{margin-bottom:0}
.sk-prod{height:314px;border-radius:var(--r-lg)}
.sk-kpi{height:104px;border-radius:var(--r-lg)}

/* =====================================================================
   MODALES
   ===================================================================== */
@keyframes fondoEntra{from{opacity:0}to{opacity:1}}
@keyframes modalEntra{from{opacity:0;transform:translateY(14px) scale(.985)}
  to{opacity:1;transform:none}}
body.modal-abierto{overflow:hidden}
.modal-fondo{
  position:fixed;inset:0;z-index:100;
  /* Por encima de la cabecera (60) y del carrito adherido en móvil (40). */
  background:rgba(6,35,56,.42);backdrop-filter:blur(3px);
  display:flex;align-items:center;justify-content:center;padding:var(--sp-4);
  animation:fondoEntra var(--t) both;overflow-y:auto;
}
.modal{
  background:var(--surface);border-radius:var(--r-lg);box-shadow:var(--sh-4);
  width:100%;max-width:520px;max-height:calc(100dvh - var(--sp-7));
  display:flex;flex-direction:column;animation:modalEntra var(--t-lento) both;
}
.modal-head{display:flex;align-items:center;gap:var(--sp-3);
  padding:var(--sp-4) var(--sp-5);border-bottom:1px solid var(--border-2)}
.modal-cuerpo{padding:var(--sp-5);overflow-y:auto;display:flex;
  flex-direction:column;gap:var(--sp-4)}
.modal-pie{display:flex;gap:var(--sp-2);justify-content:flex-end;
  padding:var(--sp-4) var(--sp-5);border-top:1px solid var(--border-2);
  background:var(--surface-2);flex-wrap:wrap}
@media(max-width:520px){
  .modal-fondo{align-items:flex-end;padding:0}
  .modal{max-width:none;border-radius:var(--r-lg) var(--r-lg) 0 0;
    max-height:calc(100dvh - var(--sp-8))}
  .modal-pie .btn{flex:1}
}

/* =====================================================================
   NOTIFICACIONES
   ===================================================================== */
.toasts{position:fixed;right:var(--sp-4);bottom:var(--sp-4);z-index:200;
  display:flex;flex-direction:column;gap:var(--sp-2);pointer-events:none;
  max-width:min(94vw,384px)}
@media(max-width:520px){.toasts{left:var(--sp-3);right:var(--sp-3);bottom:var(--sp-3);max-width:none}}

@keyframes toastEntra{from{opacity:0;transform:translateX(22px) scale(.97)}to{opacity:1;transform:none}}
@keyframes toastSale{to{opacity:0;transform:translateX(22px) scale(.97)}}
.toast{
  display:flex;align-items:flex-start;gap:10px;
  padding:12px 14px;border-radius:var(--r);
  background:var(--surface);border:1px solid var(--border);
  box-shadow:var(--sh-3);font-size:13.5px;line-height:1.45;
  pointer-events:auto;animation:toastEntra var(--t-lento) both;
  border-left:3px solid var(--primary);
}
.toast.saliendo{animation:toastSale var(--t) both}
.toast.ok{border-left-color:var(--success)}
.toast.err{border-left-color:var(--danger)}
.toast.warn{border-left-color:var(--warning)}
.toast-ico{width:20px;height:20px;border-radius:50%;flex:0 0 auto;display:grid;
  place-items:center;background:var(--primary-soft);color:var(--primary);margin-top:1px}
.toast.ok .toast-ico{background:var(--success-soft);color:var(--success)}
.toast.err .toast-ico{background:var(--danger-soft);color:var(--danger)}
.toast.warn .toast-ico{background:var(--warning-soft);color:var(--warning)}
.toast-titulo{font-weight:650;color:var(--text)}
.toast-texto{color:var(--text-3);font-size:12.5px;margin-top:1px}

/* =====================================================================
   LOGIN
   ===================================================================== */
.login{
  min-height:100dvh;display:grid;place-items:center;padding:var(--sp-5);
  background:
    radial-gradient(1100px 520px at 12% -8%, rgba(46,143,192,.16), transparent 60%),
    radial-gradient(900px 460px at 96% 108%, rgba(20,151,174,.14), transparent 60%),
    var(--bg);
}
.login-card{
  width:100%;max-width:404px;background:var(--surface);
  border:1px solid var(--border);border-radius:var(--r-xl);
  padding:var(--sp-7);box-shadow:var(--sh-3);
}
@media(max-width:480px){.login-card{padding:var(--sp-5)}}
.login-marca{display:flex;flex-direction:column;align-items:center;gap:var(--sp-3);
  margin-bottom:var(--sp-6);text-align:center}
/* En el login hay espacio: el logo se muestra grande y legible. */
.login-logo{height:68px;width:auto;max-width:88px;object-fit:contain}

/* =====================================================================
   CATÁLOGO PÚBLICO
   ===================================================================== */
.hdr-publico{
  position:sticky;top:0;z-index:60;
  background:rgba(255,255,255,.9);backdrop-filter:saturate(180%) blur(12px);
  border-bottom:1px solid var(--border);
}
.hdr-publico-in{max-width:var(--ancho);margin:0 auto;padding:11px var(--sp-5);
  display:flex;align-items:center;gap:var(--sp-4)}
@media(max-width:640px){.hdr-publico-in{padding:10px var(--sp-3)}}

/* El logo se limita por ALTURA y conserva su proporción. Nunca se estira. */
/* El logo de El Carpintero lleva texto pequeno dentro del archivo: por debajo
   de ~44 px deja de leerse. Se muestra a 44 px y se acompana de un rotulo de
   texto, que es lo que realmente identifica a la empresa en la cabecera. */
.logo-publico{height:44px;width:auto;max-width:56px;object-fit:contain;display:block}
.marca-rotulo{display:flex;flex-direction:column;min-width:0}
.marca-rotulo b{font-family:var(--f-display);font-size:15px;font-weight:700;
  letter-spacing:-.02em;line-height:1.15;color:var(--text)}
.marca-rotulo span{font-size:10.5px;color:var(--text-3);line-height:1.2}
@media(max-width:560px){.marca-rotulo span{display:none}}
@media(max-width:400px){.marca-rotulo b{font-size:13.5px}}

/* --- Hero --- */
/* El relleno lo pone `.hero-contenido`, no el marco. Antes lo ponían LOS DOS
   (40px + 40px arriba y abajo): 160px de aire que empujaban los productos
   fuera de la primera pantalla. En móvil había que bajar dos pantallas enteras
   para ver un producto. */
.hero{
  position:relative;overflow:hidden;
  border-radius:var(--r-xl);
  margin-bottom:var(--sp-6);
  background:linear-gradient(135deg,var(--primary-darker) 0%,var(--primary-dark) 52%,var(--primary) 100%);
  color:#fff;
}
/* Textura de agua muy tenue: profundidad sin ruido visual. */
.hero::after{
  content:'';position:absolute;inset:0;pointer-events:none;
  background:
    radial-gradient(600px 300px at 88% -20%, rgba(76,191,209,.28), transparent 62%),
    radial-gradient(420px 260px at 8% 118%, rgba(46,143,192,.26), transparent 60%);
}
.hero>*{position:relative;z-index:1}
.hero h1{color:#fff;font-size:clamp(24px,4vw,var(--fs-4xl));max-width:19ch;
  letter-spacing:-.03em;margin-bottom:var(--sp-3)}
.hero p{color:rgba(255,255,255,.82);max-width:56ch;font-size:var(--fs-md);line-height:1.6}
.hero-datos{display:flex;gap:var(--sp-7);flex-wrap:wrap;margin-top:var(--sp-5);
  padding-top:var(--sp-5);border-top:1px solid rgba(255,255,255,.16)}
.hero-dato-val{font-family:var(--f-display);font-size:var(--fs-2xl);font-weight:750;
  letter-spacing:-.03em;line-height:1.1}
.hero-dato-txt{font-size:var(--fs-sm);color:rgba(255,255,255,.7);margin-top:2px}
@media(max-width:640px){
  .hero{padding:var(--sp-6) var(--sp-5)}
  .hero-datos{gap:var(--sp-5)}
}

/* EL HERO EN DOS COLUMNAS, A PARTIR DE 900 px.
 *
 * Medido antes de tocarlo: en un portatil de 1440x780 el hero ocupaba 402 px
 * y el primer producto aparecia en y=702, con lo cual no cabia ni una tarjeta
 * entera en la primera pantalla. En el telefono era peor: 377 px de hero mas
 * 201 px de franja de confianza, y el primer producto en y=877, fuera de una
 * pantalla de 844.
 *
 * Y la altura no estaba comprada con contenido: `.hero-contenido` tiene
 * `max-width:660px` dentro de un hero de ~1.360, asi que la mitad derecha era
 * degradado vacio mientras las cifras se apilaban DEBAJO del texto, empujando
 * todo hacia abajo.
 *
 * Poniendolas al lado se gana el alto de las cifras mas su separador, y de
 * paso se llena el hueco. No se quita ni una palabra: es la misma informacion
 * ocupando el espacio que ya estaba pagado. */
/* `.hero .hero-contenido` y no `.hero-contenido` a secas: la regla base vive
   MAS ABAJO en este archivo (donde se define el relleno del hero con imagen) y
   con la misma especificidad gana la ultima. Sin esto, el `max-width:660px`
   de alli seguia mandando: la columna de texto se quedaba en 408 px, el
   titular caia a tres lineas igual que antes y el hero subia de 402 a 431 px
   en vez de bajar. Medido, no supuesto. */
@media(min-width:900px){
  .hero .hero-contenido,.hero.con-imagen .hero-contenido{
    display:grid;grid-template-columns:minmax(0,1fr) auto;
    align-items:center;column-gap:var(--sp-8);
    max-width:none;padding:var(--sp-6) var(--sp-7);
  }
  .hero .hero-contenido>.hero-etiqueta,
  .hero .hero-contenido>h1,
  .hero .hero-contenido>p,
  .hero .hero-contenido>.hero-cta{grid-column:1}

  /* EL TITULAR A DOS LINEAS, NO A TRES.
     Era el bloque mas alto del hero: `max-width:19ch` al tamaño maximo
     forzaba tres renglones de ~57 px. Dandole sitio para 2 lineas se
     recupera un renglon entero sin tocar ni una palabra del texto. */
  .hero h1{max-width:30ch;margin-bottom:var(--sp-2);
    font-size:clamp(26px,2.9vw,38px);line-height:1.14}
  .hero p{max-width:60ch;font-size:var(--fs-base);line-height:1.5}

  .hero-datos{
    grid-column:2;grid-row:1/-1;
    /* En columna y con una linea a la izquierda en vez de encima: la misma
       separacion visual sin gastar alto propio, porque vive en el hueco que
       ya habia a la derecha. Apretado, para que esta columna no se convierta
       en la mas alta y acabe empujando ella el hero -que fue justo lo que
       paso al primer intento: de 402 px subio a 485-. */
    flex-direction:column;gap:var(--sp-3);
    margin-top:0;padding-top:0;padding-left:var(--sp-7);
    border-top:0;border-left:1px solid rgba(255,255,255,.16);
  }
  .hero-dato-val{font-size:var(--fs-xl)}
}

/* En el telefono las cifras no caben al lado, pero si en una sola linea. Eran
   tres bloques apilados con un separador encima; ahora reparten el ancho. */
@media(max-width:640px){
  .hero h1{font-size:clamp(22px,6.2vw,30px);max-width:none}
  .hero p{font-size:var(--fs-sm);line-height:1.5}
  .hero-datos{
    display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
    gap:var(--sp-3);margin-top:var(--sp-4);padding-top:var(--sp-4);
  }
  .hero-dato-val{font-size:var(--fs-xl)}
  .hero-dato-txt{font-size:11.5px;line-height:1.25}
}

/* --- Sección con título --- */
.seccion{margin-bottom:var(--sp-7)}
.seccion-head{display:flex;align-items:flex-end;gap:var(--sp-4);
  margin-bottom:var(--sp-4);flex-wrap:wrap}
.seccion-head>div:first-child{flex:1;min-width:min(100%,220px)}
.seccion-head h2{font-size:var(--fs-xl);letter-spacing:-.024em}
.seccion-head p{color:var(--text-3);font-size:var(--fs-sm);margin:2px 0 0}

/* --- Marcas --- */
.marcas-grid{display:grid;gap:var(--sp-4);
  grid-template-columns:repeat(auto-fit,minmax(min(100%,258px),1fr))}
.marca-card{
  display:flex;flex-direction:column;min-width:0;
  background:var(--surface);border:1px solid var(--border);
  border-radius:var(--r-lg);overflow:hidden;box-shadow:var(--sh-1);
  transition:box-shadow var(--t),transform var(--t),border-color var(--t);
  text-align:left;
}
.marca-card:hover{box-shadow:var(--sh-3);transform:translateY(-2px);
  border-color:var(--primary-light)}
/* Zona del logo: fondo claro y neutro, con aire alrededor (área de seguridad).
   Altura fija y object-fit:contain: el logo nunca se deforma ni se recorta. */
/* Fondo BLANCO, no degradado: los tres logos vienen con fondo blanco opaco,
   y cualquier tinte deja ver el rectangulo del archivo recortado. */
.marca-logo{
  height:104px;display:grid;place-items:center;padding:var(--sp-5) var(--sp-6);
  background:#fff;border-bottom:1px solid var(--border-2);
}
/* Cada logo se escala segun su forma, no todos por igual:
   - ALPSMT es apaisado (978x370): manda el ancho.
   - El Carpintero es casi cuadrado (451x386) y lleva texto fino: necesita altura.
   - ISA-H es vertical (142x352) y de baja resolucion: se limita para no pixelarlo. */
.marca-logo img{max-height:52px;width:auto;max-width:80%;object-fit:contain;display:block}
.marca-logo.cuadrado img{max-height:70px;max-width:60%}
.marca-logo.vertical img{max-height:68px;max-width:44%}
.marca-cuerpo{padding:var(--sp-4) var(--sp-5) var(--sp-5);display:flex;
  flex-direction:column;gap:6px;flex:1}
.marca-nom{font-family:var(--f-display);font-size:var(--fs-md);font-weight:700;
  letter-spacing:-.015em}
.marca-desc{font-size:12.5px;color:var(--text-3);line-height:1.5;flex:1}
.marca-cta{display:inline-flex;align-items:center;gap:5px;
  font-size:12.5px;font-weight:650;color:var(--primary);margin-top:var(--sp-2)}
.marca-card:hover .marca-cta svg{transform:translateX(3px)}
.marca-cta svg{transition:transform var(--t-rapido)}
.marca-card.on{border-color:var(--primary);box-shadow:var(--ring),var(--sh-2)}

/* Filtro compacto de marcas (fila de chips con logo) */
.marcas{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.marca-chip{
  border:1px solid var(--border);background:var(--surface);border-radius:var(--r-sm);
  padding:7px 13px;min-height:44px;display:flex;align-items:center;justify-content:center;
  font-size:13px;font-weight:650;color:var(--text-2);transition:all var(--t-rapido);
}
.marca-chip img{height:22px;width:auto;max-width:92px;object-fit:contain;display:block}
.marca-chip:hover{border-color:var(--primary-light)}
.marca-chip.on{border-color:var(--primary);box-shadow:var(--ring)}

/* --- Banners: franja contenida. Nunca a pantalla completa. --- */
.banners-wrap{position:relative;margin-bottom:var(--sp-6)}
.banners{
  display:flex;gap:var(--sp-3);overflow-x:auto;scroll-snap-type:x mandatory;
  scrollbar-width:none;border-radius:var(--r-lg);
}
.banners::-webkit-scrollbar{display:none}
.banner{
  flex:0 0 100%;scroll-snap-align:center;position:relative;min-width:0;
  border-radius:var(--r-lg);overflow:hidden;border:1px solid var(--border);
  background:var(--surface-2);
  aspect-ratio:5/1;max-height:190px;
}
.banner img{width:100%;height:100%;object-fit:cover;display:block}
/* Velo inferior solo si el banner lleva texto: garantiza contraste legible. */
.banner-txt{
  position:absolute;inset:auto 0 0 0;padding:var(--sp-5);
  background:linear-gradient(to top,rgba(6,35,56,.78),rgba(6,35,56,0));
  color:#fff;
}
.banner-titulo{font-family:var(--f-display);font-size:var(--fs-lg);font-weight:700;
  letter-spacing:-.02em}
.banner-puntos{display:flex;gap:6px;justify-content:center;margin-top:var(--sp-3)}
.banner-punto{width:7px;height:7px;border-radius:50%;background:var(--border-strong);
  transition:all var(--t);padding:0}
.banner-punto.on{background:var(--primary);width:20px;border-radius:var(--r-full)}
@media(max-width:760px){.banner{aspect-ratio:2.6/1;max-height:158px}
  .banner-txt{padding:var(--sp-4)}}

.pie-publico{border-top:1px solid var(--border);background:var(--surface);
  padding:var(--sp-7) var(--sp-5);margin-top:var(--sp-8)}
.pie-publico-in{max-width:var(--ancho);margin:0 auto;display:flex;
  align-items:center;justify-content:space-between;gap:var(--sp-5);flex-wrap:wrap}
.pie-logos{display:flex;gap:var(--sp-6);align-items:center;flex-wrap:wrap}
.logo-pie{height:27px;width:auto;max-width:100px;object-fit:contain;
  opacity:.55;transition:opacity var(--t-rapido)}
.logo-pie:hover{opacity:1}

/* =====================================================================
   DIAGNÓSTICO
   ===================================================================== */
.rev{display:flex;gap:11px;align-items:flex-start;padding:13px var(--sp-5);
  border-bottom:1px solid var(--border-2);transition:background var(--t-rapido)}
.rev:last-child{border-bottom:0}
.rev:hover{background:var(--surface-2)}
.rev-punto{width:9px;height:9px;border-radius:50%;flex:0 0 auto;margin-top:6px}

/* =====================================================================
   HEREDADOS
   ===================================================================== */
.fila-pedido{display:flex;gap:var(--sp-3);align-items:center}
.org{color:var(--text-3)}
.ok{color:var(--success)}
.err{color:var(--danger)}
.w3{width:33%}
.num{font-family:var(--f-mono);font-variant-numeric:tabular-nums}

/* --- Grupo desplegable de la navegación --- */
.nav-grupo{position:relative}
.nav-grupo-titulo{display:none}
.nav-grupo-btn{
  display:inline-flex;align-items:center;gap:7px;padding:8px 12px;
  border-radius:var(--r-sm);font-size:13.5px;font-weight:600;color:var(--text-2);
  white-space:nowrap;transition:background var(--t-rapido),color var(--t-rapido);
}
.nav-grupo-btn:hover{background:var(--surface-3);color:var(--primary-dark)}
.nav-grupo-btn.on{color:var(--primary);background:var(--primary-soft)}
.nav-grupo-btn svg:last-child{opacity:.6;transition:transform var(--t-rapido)}
.nav-grupo.abierto .nav-grupo-btn svg:last-child{transform:rotate(180deg)}

.nav-grupo-menu{
  position:absolute;top:calc(100% + 9px);left:0;min-width:214px;z-index:70;
  background:var(--surface);border:1px solid var(--border);border-radius:var(--r);
  box-shadow:var(--sh-3);padding:6px;display:flex;flex-direction:column;gap:1px;
  opacity:0;transform:translateY(-6px);pointer-events:none;
  transition:opacity var(--t),transform var(--t);
}
.nav-grupo.abierto .nav-grupo-menu{opacity:1;transform:none;pointer-events:auto}
.nav-grupo-menu a{
  display:flex;align-items:center;gap:9px;padding:8px 10px;border-radius:var(--r-xs);
  font-size:13.5px;font-weight:600;color:var(--text-2);white-space:nowrap;
  transition:background var(--t-rapido),color var(--t-rapido);
}
.nav-grupo-menu a:hover{background:var(--surface-3);color:var(--primary-dark)}
.nav-grupo-menu a.on{color:var(--primary);background:var(--primary-soft)}

@media(max-width:1080px){
  /* En el menú móvil el grupo ya está abierto: no tiene sentido un desplegable.
     Se oculta el botón y se muestra el rótulo, pero el marcado es el MISMO que
     en escritorio: así no hay una rama de JS que dependa del ancho de pantalla
     en el momento del render. */
  .nav-grupo{display:flex;flex-direction:column;position:static;
    border-top:1px solid var(--border-2);margin-top:var(--sp-2);padding-top:var(--sp-1)}
  .nav-grupo-btn{display:none}
  .nav-grupo-titulo{display:block;padding:10px 12px 4px}
  /* Se nombra tambien `.abierto` para no perder por especificidad contra la
     regla de escritorio `.nav-grupo.abierto .nav-grupo-menu`. */
  .nav-grupo .nav-grupo-menu,
  .nav-grupo.abierto .nav-grupo-menu{
    position:static;opacity:1;transform:none;
    /* `inherit`, nunca `auto`: si el panel está cerrado el grupo tiene que
       estar cerrado con él. Un `auto` aquí convierte esta lista en una capa
       invisible que se come los toques de la vista que hay debajo. */
    pointer-events:inherit;
    box-shadow:none;border:0;padding:0;background:transparent;min-width:0;z-index:auto}
  .nav-grupo .nav-grupo-menu a{padding:11px 12px;font-size:14.5px}
}

/* --- Embudo de estados --- */
.embudo{display:flex;height:9px;border-radius:var(--r-full);overflow:hidden;
  background:var(--surface-3);gap:2px}
.embudo>span{display:block;height:100%;transition:width var(--t-lento);min-width:3px}
.embudo-leyenda{display:inline-flex;align-items:center;gap:6px;
  font-size:12.5px;color:var(--text-2);font-weight:550}
.embudo-leyenda i{width:9px;height:9px;border-radius:3px;flex:0 0 auto}
.embudo-leyenda b{font-family:var(--f-mono);font-variant-numeric:tabular-nums;
  color:var(--text);font-weight:700}

/* --- Fila de pedido pulsable (listas del dashboard) --- */
.fila-pedido{
  display:flex;align-items:center;gap:var(--sp-3);width:100%;text-align:left;
  padding:11px 12px;border-radius:var(--r-sm);border:1px solid transparent;
  transition:background var(--t-rapido),border-color var(--t-rapido);
}
.fila-pedido:hover{background:var(--surface-2);border-color:var(--border-2)}

/* --- Accesos rápidos --- */
.accesos{display:grid;gap:var(--sp-2);
  grid-template-columns:repeat(auto-fill,minmax(min(100%,152px),1fr))}
.acceso{
  display:flex;align-items:center;gap:9px;padding:11px 13px;
  border:1px solid var(--border);border-radius:var(--r-sm);background:var(--surface);
  font-size:13px;font-weight:600;color:var(--text-2);text-align:left;
  transition:all var(--t-rapido);
}
.acceso:hover{border-color:var(--primary-light);color:var(--primary);
  background:var(--primary-softer);transform:translateY(-1px)}
.acceso svg{color:var(--primary);opacity:.9;flex:0 0 auto}

/* --- Confirmación al agregar al carrito ---
   Un destello de 600 ms sobre la tarjeta. Es la señal más inmediata:
   ocurre donde el usuario tiene puesta la vista, no en una esquina. */
@keyframes destello{
  0%{box-shadow:0 0 0 0 rgba(11,122,90,.34);border-color:var(--success)}
  100%{box-shadow:0 0 0 9px rgba(11,122,90,0);border-color:var(--border)}
}
.prod.agregado{animation:destello 600ms ease-out}
.prod.agotado .prod-img img{opacity:.55;filter:saturate(.5)}

/* --- Etiqueta superior del hero --- */
.hero-etiqueta{
  display:inline-block;margin-bottom:var(--sp-4);
  padding:5px 12px;border-radius:var(--r-full);
  background:rgba(255,255,255,.14);border:1px solid rgba(255,255,255,.22);
  font-size:11.5px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;
  color:rgba(255,255,255,.92);
}

/* Contador dentro del chip de categoría: informa del tamaño sin otra columna. */
.chip-num{
  margin-left:6px;padding:1px 6px;border-radius:var(--r-full);
  background:var(--surface-3);color:var(--text-3);
  font-size:10.5px;font-weight:700;font-variant-numeric:tabular-nums;
}
.chip.on .chip-num{background:rgba(255,255,255,.22);color:#fff}
.chip-mas{border-style:dashed;color:var(--primary);border-color:var(--primary-light)}
.chip-mas:hover{background:var(--primary-soft)}

/* --- Login --- */
.login-pie{margin-top:var(--sp-6);padding-top:var(--sp-4);border-top:1px solid var(--border-2)}
.login-demo{display:flex;flex-direction:column;gap:3px}
.login-demo-fila{display:flex;justify-content:space-between;align-items:baseline;
  font-size:12.5px;gap:var(--sp-3)}
.login-demo-fila .mono{font-weight:650;color:var(--text-2)}
.login-publico{
  display:flex;align-items:center;justify-content:center;gap:7px;
  margin-top:var(--sp-4);padding:11px;border-radius:var(--r-sm);
  font-size:13px;font-weight:650;color:var(--primary);
  border:1px solid var(--border);background:var(--surface);
  transition:all var(--t-rapido);
}
.login-publico:hover{background:var(--primary-soft);border-color:var(--primary-light)}

/* =====================================================================
   HERO CON IMAGEN
   ===================================================================== */
.hero.con-imagen{padding:0;min-height:300px;display:grid}
.hero.con-imagen>*{grid-area:1/1}
.hero-fondo{width:100%;height:100%;object-fit:cover;display:block}
/* Velo obligatorio sobre la fotografía: sin él el texto blanco deja de leerse
   en cuanto la imagen tiene zonas claras. Opacidad suficiente, no decorativa. */
.hero-velo{
  background:linear-gradient(100deg,rgba(6,35,56,.92) 0%,rgba(6,35,56,.78) 46%,rgba(6,35,56,.42) 100%);
}
.hero-contenido{position:relative;z-index:2;padding:var(--sp-7) var(--sp-7);
  align-self:center;max-width:660px}
.hero.con-imagen .hero-contenido{padding:var(--sp-8) var(--sp-7)}
@media(max-width:640px){
  .hero.con-imagen{min-height:260px}
  .hero-contenido,.hero.con-imagen .hero-contenido{padding:var(--sp-6) var(--sp-5)}
  /* En móvil el velo se hace vertical: el texto queda abajo, sobre lo oscuro. */
  .hero-velo{background:linear-gradient(180deg,rgba(6,35,56,.72) 0%,rgba(6,35,56,.93) 72%)}
}
.hero-cta{background:#fff;color:var(--primary-dark);margin-top:var(--sp-5)}
.hero-cta:hover{background:#EDF3F8;color:var(--primary-darker)}

/* =====================================================================
   BANNERS
   ===================================================================== */
/* La proporción la fija el propio banner con aspect-ratio en línea, tomada
   de la imagen real. Aquí solo se acota el alto para que nunca domine. */
.banner{max-height:none}
.banner.formato-horizontal{max-height:210px}
.banner.formato-hero{max-height:300px}
.banner.formato-cuadrado{max-height:340px}
.banner.formato-vertical{max-height:420px}
/* object-fit:contain sobre fondo neutro: la pieza se ve ENTERA.
   Un cover recortaría el mensaje, que es justo lo que no se quiere. */
.banner img{object-fit:contain;background:var(--surface-2)}
.banner.formato-hero img{object-fit:cover}

.banner-sub{font-size:13px;color:rgba(255,255,255,.86);margin-top:3px;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.banner-cta{display:inline-flex;align-items:center;gap:5px;margin-top:9px;
  padding:6px 13px;border-radius:var(--r-full);background:#fff;color:var(--primary-dark);
  font-size:12.5px;font-weight:650}

.banners-vertical{display:grid;gap:var(--sp-3);margin-bottom:var(--sp-6);
  grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr))}

/* =====================================================================
   CARRUSEL DE PRODUCTOS
   ===================================================================== */
.carrusel-caja{position:relative;min-width:0}
.carrusel-pista{
  display:flex;gap:var(--sp-3);overflow-x:auto;scroll-snap-type:x proximity;
  padding-bottom:var(--sp-2);scrollbar-width:thin;
}
.carrusel-pista::-webkit-scrollbar{height:6px}
.carrusel-pista::-webkit-scrollbar-thumb{background:var(--border-strong);border-radius:99px}
.carrusel-pista>.prod{flex:0 0 216px;scroll-snap-align:start}
@media(max-width:520px){.carrusel-pista>.prod{flex:0 0 62%}}

.carrusel-flecha{
  width:32px;height:32px;border-radius:var(--r-sm);display:grid;place-items:center;
  border:1px solid var(--border);background:var(--surface);color:var(--text-2);
  transition:all var(--t-rapido);
}
.carrusel-flecha:hover{border-color:var(--primary-light);color:var(--primary)}
.carrusel-flecha.oculto{opacity:.3;pointer-events:none}

/* La tarjeta compacta del carrusel usa una imagen más baja: en una fila
   horizontal la altura es el recurso escaso. */
.prod-compacta .prod-img{aspect-ratio:1/1}
.prod-compacta .prod-nom{font-size:12.8px;min-height:2.6em}
.prod-compacta .prod-precio{font-size:var(--fs-lg)}

/* --- Selector de productos del carrusel --- */
.fila-elegido{display:flex;align-items:center;gap:9px;padding:8px 10px;
  border:1px solid var(--border-2);border-radius:var(--r-sm);background:var(--surface-2)}
.fila-elegido .icon-btn{width:28px;height:28px;flex:0 0 auto}
.fila-elegido .icon-btn:disabled{opacity:.3;cursor:not-allowed}

/* Vista previa del banner en el editor: usa la proporción real de la imagen. */
.banner-previa{aspect-ratio:4;background:var(--surface-2);border:1px solid var(--border);
  border-radius:var(--r);overflow:hidden;display:grid;place-items:center}
.banner-previa img{width:100%;height:100%;object-fit:contain;display:block}
.banner-previa .ph{color:var(--border-strong)}

/* =====================================================================
   FICHA DE PRODUCTO
   ===================================================================== */
.ficha{
  display:grid;gap:var(--sp-7);align-items:start;
  grid-template-columns:minmax(0,460px) minmax(0,1fr);
}
/* En móvil pasa a una sola columna: imagen, galería, y después la información.
   Es el orden natural del DOM, así que no hace falta reordenar nada. */
@media(max-width:900px){.ficha{grid-template-columns:1fr;gap:var(--sp-5)}}

.ficha-galeria{position:sticky;top:calc(var(--hdr-h) + var(--sp-5));min-width:0}
@media(max-width:900px){.ficha-galeria{position:static}}

.ficha-marco-caja{position:relative}
.ficha-marco{
  display:grid;place-items:center;width:100%;aspect-ratio:1;
  background:var(--surface);border:1px solid var(--border);
  border-radius:var(--r-lg);overflow:hidden;padding:0;cursor:zoom-in;
  transition:border-color var(--t-rapido),box-shadow var(--t-rapido);
}
.ficha-marco:hover{border-color:var(--border-strong);box-shadow:var(--sh-2)}
/* contain: un producto recortado deja de reconocerse. */
.ficha-img{width:100%;height:100%;object-fit:contain;padding:var(--sp-6);display:block;
  transition:opacity var(--t),transform var(--t-lento)}
.ficha-img.cambiando{opacity:.35}
.ficha-marco:hover .ficha-img{transform:scale(1.03)}
.ficha-marco .ph{color:var(--border-strong)}

.ficha-lupa{
  position:absolute;right:12px;bottom:12px;width:34px;height:34px;border-radius:var(--r-sm);
  background:rgba(255,255,255,.94);color:var(--text-2);display:grid;place-items:center;
  box-shadow:var(--sh-1);opacity:0;transition:opacity var(--t-rapido);
}
.ficha-marco:hover .ficha-lupa{opacity:1}

.ficha-flecha{
  position:absolute;top:50%;transform:translateY(-50%);
  width:38px;height:38px;border-radius:50%;display:grid;place-items:center;
  background:rgba(255,255,255,.94);border:1px solid var(--border);color:var(--text-2);
  box-shadow:var(--sh-2);transition:all var(--t-rapido);z-index:2;
}
.ficha-flecha:hover{color:var(--primary);border-color:var(--primary-light)}
.ficha-flecha.izq{left:10px}
.ficha-flecha.der{right:10px}

.ficha-contador{
  position:absolute;left:12px;bottom:12px;padding:3px 9px;border-radius:var(--r-full);
  background:rgba(6,35,56,.76);color:#fff;font-size:11.5px;font-weight:650;
  font-variant-numeric:tabular-nums;
}

.ficha-miniaturas{display:flex;gap:8px;margin-top:var(--sp-3);flex-wrap:wrap}
.ficha-mini{
  width:66px;height:66px;border-radius:var(--r-sm);overflow:hidden;padding:5px;
  border:1px solid var(--border);background:var(--surface);
  display:grid;place-items:center;transition:all var(--t-rapido);
}
.ficha-mini img{width:100%;height:100%;object-fit:contain}
.ficha-mini:hover{border-color:var(--primary-light)}
.ficha-mini.on{border-color:var(--primary);box-shadow:var(--ring)}

.ficha-info{min-width:0}
.ficha-nombre{font-size:clamp(20px,3vw,var(--fs-2xl));line-height:1.25;
  letter-spacing:-.025em;margin-bottom:6px}
.ficha-sku{font-size:12.5px;color:var(--text-3);margin-bottom:var(--sp-4)}
.ficha-desc{font-size:14.5px;line-height:1.65;color:var(--text-2);margin-bottom:var(--sp-4)}

.ficha-compra{
  background:var(--surface);border:1px solid var(--border);
  border-radius:var(--r-lg);padding:var(--sp-5);box-shadow:var(--sh-1);
  margin-bottom:var(--sp-5);
}
.ficha-precio{
  font-family:var(--f-display);font-size:var(--fs-3xl);font-weight:750;
  letter-spacing:-.03em;color:var(--primary-dark);line-height:1.1;
  font-variant-numeric:tabular-nums;
}
.ficha-iva{font-size:12.5px;color:var(--text-3);margin-top:4px}
.ficha-compra .stepper input{width:56px}
@media(max-width:420px){
  .ficha-compra .fila-wrap{flex-direction:column;align-items:stretch}
  .ficha-compra .stepper{width:100%;justify-content:space-between}
  .ficha-compra .stepper input{flex:1;min-width:0;width:auto}
}

.ficha-bloque{padding-top:var(--sp-5);margin-top:var(--sp-5);
  border-top:1px solid var(--border-2)}
.ficha-bloque:first-of-type{border-top:0;margin-top:0}

/* Lista de definición en dos columnas: etiqueta a la izquierda, valor a la
   derecha. En móvil se apila para no comprimir el valor. */
.ficha-caracteristicas{display:grid;grid-template-columns:auto 1fr;
  gap:2px var(--sp-4);margin:0;font-size:13.5px}
.ficha-caracteristicas dt{color:var(--text-3);padding:6px 0;white-space:nowrap}
.ficha-caracteristicas dd{margin:0;padding:6px 0;font-weight:600;
  border-bottom:1px solid var(--border-2)}
.ficha-caracteristicas dt{border-bottom:1px solid var(--border-2)}
.ficha-caracteristicas dt:last-of-type,
.ficha-caracteristicas dd:last-of-type{border-bottom:0}
@media(max-width:480px){
  .ficha-caracteristicas{grid-template-columns:1fr;gap:0}
  .ficha-caracteristicas dt{padding:8px 0 0;border-bottom:0;font-size:11.5px;
    text-transform:uppercase;letter-spacing:.05em;font-weight:700}
  .ficha-caracteristicas dd{padding:0 0 8px}
}

.enlace-prod{display:block;color:inherit;min-width:0}
.enlace-prod:hover{color:inherit}

/* --- Ampliación de imagen --- */
@keyframes zoomEntra{from{opacity:0;transform:scale(.97)}to{opacity:1;transform:none}}
.zoom-fondo{
  position:fixed;inset:0;z-index:220;background:rgba(6,35,56,.93);
  display:flex;align-items:center;justify-content:center;gap:var(--sp-4);
  padding:var(--sp-5);animation:fondoEntra var(--t) both;
}
.zoom-caja{max-width:min(1100px,92vw);max-height:88vh;display:flex;
  flex-direction:column;gap:var(--sp-3);animation:zoomEntra var(--t-lento) both}
.zoom-caja img{max-width:100%;max-height:78vh;object-fit:contain;display:block;
  border-radius:var(--r);background:#fff}
.zoom-pie{display:flex;justify-content:space-between;gap:var(--sp-4);
  color:rgba(255,255,255,.9);font-size:13px}
.zoom-pie .muted{color:rgba(255,255,255,.6);font-variant-numeric:tabular-nums}
.zoom-cerrar,.zoom-flecha{
  width:42px;height:42px;border-radius:50%;display:grid;place-items:center;
  background:rgba(255,255,255,.14);color:#fff;flex:0 0 auto;
  transition:background var(--t-rapido);
}
.zoom-cerrar:hover,.zoom-flecha:hover{background:rgba(255,255,255,.26)}
.zoom-cerrar{position:absolute;top:var(--sp-4);right:var(--sp-4);z-index:2}
@media(max-width:640px){
  .zoom-flecha{position:absolute;bottom:var(--sp-5);z-index:2}
  .zoom-flecha.izq{left:var(--sp-5)}
  .zoom-flecha.der{right:var(--sp-5)}
  .zoom-caja img{max-height:66vh}
}

/* =====================================================================
   PIE DE PÁGINA
   ===================================================================== */
.pie{border-top:1px solid var(--border);background:var(--surface);margin-top:var(--sp-9)}
.pie-in{
  max-width:var(--ancho);margin:0 auto;padding:var(--sp-8) var(--sp-5) var(--sp-6);
  display:grid;gap:var(--sp-7);
  /* Cuatro columnas en escritorio; la primera más ancha porque lleva el texto. */
  grid-template-columns:1.6fr 1fr 1.1fr 1fr;
}
@media(max-width:1080px){.pie-in{grid-template-columns:1fr 1fr;gap:var(--sp-6)}}
@media(max-width:620px){
  .pie-in{grid-template-columns:1fr;gap:var(--sp-6);padding:var(--sp-6) var(--sp-4)}
}

.pie-col{min-width:0}
.pie-marca{display:flex;align-items:center;gap:11px;margin-bottom:var(--sp-4)}
/* Altura acotada y contain: el logo conserva su proporción. */
.pie-logo{height:42px;width:auto;max-width:54px;object-fit:contain;flex:0 0 auto}
.pie-nombre{font-family:var(--f-display);font-weight:700;font-size:14px;
  letter-spacing:-.015em;line-height:1.25}
.pie-lema{font-size:12px;color:var(--text-3);line-height:1.35;margin-top:2px}

.pie-titulo{
  font-size:11px;font-weight:700;letter-spacing:.09em;text-transform:uppercase;
  color:var(--text-3);margin:0 0 var(--sp-3);
}
.pie-texto{font-size:13px;line-height:1.65;color:var(--text-2);margin:0;max-width:52ch}

.pie-lista{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:2px}
.pie-lista a{
  display:inline-block;padding:5px 0;font-size:13.5px;color:var(--text-2);
  transition:color var(--t-rapido);
}
.pie-lista a:hover{color:var(--primary)}

.pie-contacto{display:flex;flex-direction:column;gap:8px}
.pie-canal{
  display:flex;align-items:center;gap:11px;padding:9px 12px;
  border:1px solid var(--border);border-radius:var(--r-sm);background:var(--surface);
  color:var(--text-2);transition:all var(--t-rapido);
}
.pie-canal:hover{border-color:var(--primary-light);background:var(--primary-softer);
  color:var(--primary-dark);transform:translateX(2px)}
.pie-canal svg{flex:0 0 auto;color:var(--text-3);transition:color var(--t-rapido)}
.pie-canal:hover svg{color:var(--primary)}
/* WhatsApp mantiene su color de marca al pasar por encima: es el canal
   principal de contacto y conviene que se reconozca. */
.pie-canal.whatsapp:hover{border-color:#25D366;background:rgba(37,211,102,.07)}
.pie-canal.whatsapp:hover svg{color:#1DA851}
.pie-canal span{display:flex;flex-direction:column;min-width:0}
.pie-canal b{font-size:13px;font-weight:650;line-height:1.25}
.pie-canal small{font-size:11.5px;color:var(--text-3);line-height:1.3}

.pie-marcas{display:flex;gap:9px;flex-wrap:wrap;align-items:center}
/* Cada logo en su caja blanca: los tres archivos traen fondo blanco opaco,
   así que cualquier tinte dejaría ver el rectángulo recortado. */
.pie-marca-caja{
  height:52px;min-width:74px;padding:8px 12px;
  border:1px solid var(--border);border-radius:var(--r-sm);background:#fff;
  display:grid;place-items:center;transition:border-color var(--t-rapido);
}
.pie-marca-caja:hover{border-color:var(--primary-light)}
.pie-marca-caja img{max-height:30px;max-width:72px;width:auto;object-fit:contain;display:block}
.pie-marca-caja.vertical img{max-height:36px;max-width:26px}
.pie-marca-caja.cuadrado img{max-height:34px;max-width:38px}

.pie-legal{
  border-top:1px solid var(--border-2);
  max-width:var(--ancho);margin:0 auto;padding:var(--sp-4) var(--sp-5);
  display:flex;justify-content:space-between;gap:var(--sp-4);flex-wrap:wrap;
  font-size:12px;color:var(--text-3);
}
@media(max-width:620px){.pie-legal{padding:var(--sp-4)}}

/* El nombre y la imagen de la tarjeta llevan a la ficha, sin alterar el resto. */
.prod-enlace{color:inherit;display:block;min-width:0}
.prod-enlace:hover .prod-nom{color:var(--primary)}
a.prod-img{cursor:pointer}

/* =====================================================================
   ADMINISTRACIÓN DE LA GALERÍA
   ===================================================================== */
.ficha-editor{
  background:var(--surface-2);border:1px solid var(--border-2);
  border-radius:var(--r);padding:var(--sp-4);margin-bottom:var(--sp-4);
}
.galeria-admin{display:flex;gap:9px;flex-wrap:wrap;margin-bottom:var(--sp-3)}

.gal-item{
  position:relative;width:96px;height:96px;border-radius:var(--r-sm);
  border:1px solid var(--border);background:#fff;overflow:hidden;
  display:grid;place-items:center;transition:border-color var(--t-rapido);
}
.gal-item.principal{border-color:var(--primary);box-shadow:var(--ring)}
.gal-item img{width:100%;height:100%;object-fit:contain;padding:6px}
.gal-item .ph{color:var(--border-strong)}

.gal-badge{
  position:absolute;top:4px;left:4px;display:inline-flex;align-items:center;gap:3px;
  padding:2px 6px;border-radius:var(--r-xs);background:var(--primary);color:#fff;
  font-size:9px;font-weight:700;letter-spacing:.04em;
}
/* Las acciones aparecen al pasar por encima o al enfocar con teclado:
   ocultarlas del todo las haría inalcanzables sin ratón. */
.gal-acciones{
  position:absolute;inset:auto 0 0 0;display:flex;justify-content:center;gap:1px;
  padding:3px;background:rgba(255,255,255,.95);border-top:1px solid var(--border-2);
  opacity:0;transform:translateY(100%);transition:all var(--t-rapido);
}
.gal-item:hover .gal-acciones,
.gal-item:focus-within .gal-acciones{opacity:1;transform:none}
.gal-acciones .icon-btn{width:24px;height:24px}
.gal-acciones .icon-btn.peligro:hover{color:var(--danger);background:var(--danger-soft)}
.gal-acciones .icon-btn:disabled{opacity:.28;cursor:not-allowed}

.gal-agregar{
  width:96px;height:96px;border-radius:var(--r-sm);
  border:1.5px dashed var(--border-strong);background:var(--surface);
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;
  color:var(--text-3);font-size:11.5px;font-weight:600;transition:all var(--t-rapido);
}
.gal-agregar:hover{border-color:var(--primary);color:var(--primary);
  background:var(--primary-softer)}

/* Fila de característica: etiqueta, valor y botón de quitar. */
.car-fila{display:grid;grid-template-columns:1fr 1.4fr auto;gap:7px;align-items:center}
@media(max-width:520px){.car-fila{grid-template-columns:1fr auto}
  .car-fila .inp:first-child{grid-column:1/-1}}

/* --- Generador de catálogos PDF --- */
.campos-catalogo{display:grid;gap:4px 14px;
  grid-template-columns:repeat(auto-fill,minmax(min(100%,150px),1fr))}
.portada-previa{display:flex;align-items:center;gap:12px;padding:10px;
  border:1px solid var(--border-2);border-radius:var(--r-sm);background:var(--surface-2);
  min-height:64px}
/* contain: la portada se ve entera, nunca recortada ni estirada. */
.portada-previa img{max-height:88px;max-width:70px;object-fit:contain;
  border:1px solid var(--border);border-radius:var(--r-xs);background:#fff}
.previa-resumen{min-height:30px;margin-bottom:var(--sp-3)}
.previa-muestra{display:grid;gap:7px;
  grid-template-columns:repeat(auto-fill,minmax(min(100%,168px),1fr))}
.previa-item{display:flex;align-items:center;gap:8px;padding:7px 9px;
  border:1px solid var(--border-2);border-radius:var(--r-sm);background:var(--surface-2)}
.previa-item img{width:34px;height:34px;object-fit:contain;flex:0 0 auto;background:#fff;
  border-radius:var(--r-xs)}
.previa-item .ph{width:34px;height:34px;display:grid;place-items:center;flex:0 0 auto;
  color:var(--border-strong);background:#fff;border-radius:var(--r-xs)}
.previa-nom{font-size:11.5px;font-weight:600;line-height:1.3;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}

/* --- Forma de pago: tarjetas en vez de un desplegable ---
   Es una decisión importante de la compra, así que ocupa sitio propio y
   tiene zona táctil amplia. */
.metodos-pago{display:grid;gap:8px;
  grid-template-columns:repeat(auto-fit,minmax(min(100%,150px),1fr))}
.metodo-card{
  display:flex;align-items:center;gap:10px;padding:12px;min-height:58px;
  border:1.5px solid var(--border);border-radius:var(--r);background:var(--surface);
  text-align:left;transition:all var(--t-rapido);
}
.metodo-card:hover{border-color:var(--primary-light);background:var(--primary-softer)}
.metodo-card.on{border-color:var(--primary);background:var(--primary-soft);box-shadow:var(--ring)}
.metodo-ico{display:grid;place-items:center;width:34px;height:34px;flex:0 0 auto;
  border-radius:var(--r-sm);background:var(--surface-3);color:var(--text-2)}
.metodo-card.on .metodo-ico{background:var(--primary);color:#fff}
.metodo-txt{display:flex;flex-direction:column;min-width:0;flex:1}
.metodo-nom{font-size:13.5px;font-weight:650;line-height:1.25;color:var(--text)}
.metodo-sub{font-size:11.5px;color:var(--text-3);line-height:1.3}
.metodo-check{width:20px;height:20px;flex:0 0 auto;display:grid;place-items:center;
  border-radius:50%;color:#fff;background:transparent}
.metodo-card.on .metodo-check{background:var(--primary)}

/* Con una sola forma de pago no se pregunta: se informa. */
.metodo-unico{display:flex;align-items:center;gap:11px;padding:12px 14px;
  border:1px solid var(--primary-light);border-radius:var(--r);
  background:var(--primary-soft);color:var(--primary-dark)}
.metodo-unico svg{flex:0 0 auto;color:var(--primary)}

/* La tarjeta de cliente tiene dos acciones: no debe comportarse como botón. */
.card-cliente{display:flex;flex-direction:column;transition:border-color var(--t-rapido),box-shadow var(--t-rapido)}
.card-cliente:hover{border-color:var(--primary-light);box-shadow:var(--sh-2)}
.card-cliente .fila{margin-top:auto}

/* Filtros desactivados cuando se elige "catálogo completo": siguen visibles
   para que se vea qué se está omitiendo, pero sin invitar a tocarlos. */
.zona-filtros{transition:opacity var(--t)}
.zona-filtros.atenuado{opacity:.45;pointer-events:none}

/* =====================================================================
   TÁCTIL Y ÁREA SEGURA
   ---------------------------------------------------------------------
   Va al final a propósito: son correcciones que deben ganar por orden a
   las medidas pensadas para ratón, sin subir especificidad ni usar
   !important.

   `viewport-fit=cover` ya estaba en el HTML, pero nadie leía los
   env(safe-area-*). En un iPhone con muesca eso deja el pie del modal y
   el carrito adherido por debajo de la barra de inicio: se ven, pero el
   dedo toca el sistema operativo, no el botón.
   ===================================================================== */

/* --- Área segura --- */
@supports(padding:env(safe-area-inset-bottom)){
  .hdr-in{
    padding-left:max(var(--sp-5),env(safe-area-inset-left));
    padding-right:max(var(--sp-5),env(safe-area-inset-right));
  }
  @media(max-width:640px){
    .hdr-in{
      padding-left:max(var(--sp-3),env(safe-area-inset-left));
      padding-right:max(var(--sp-3),env(safe-area-inset-right));
    }
    .main{padding-bottom:calc(var(--sp-8) + env(safe-area-inset-bottom))}
  }
  @media(max-width:1080px){
    .nav{padding-bottom:calc(var(--sp-3) + env(safe-area-inset-bottom))}
  }
  @media(max-width:1100px){
    /* El carrito es una hoja inferior: el color debe llegar hasta el borde
       físico aunque los botones se queden por encima de la barra. */
    .carrito-wrap{background:var(--surface);padding-bottom:env(safe-area-inset-bottom)}
  }
  @media(max-width:520px){
    .modal-pie{padding-bottom:calc(var(--sp-4) + env(safe-area-inset-bottom))}
    .toasts{bottom:calc(var(--sp-3) + env(safe-area-inset-bottom))}
  }
}

/* --- Dispositivos sin ratón ---
   Primero se subió todo a 40 px, que ya era mucho mejor que los 32 y 34
   pensados para un cursor de un píxel. Ahora van a 44, que es el mínimo de
   la pauta táctil y, sobre todo, lo que mide la yema de un pulgar: por
   debajo de ahí hay que apuntar, y quien usa esto lo hace de pie en una
   bodega o con el teléfono en una mano.

   No todo crece igual. Un control que se pulsa -un botón, un campo, un
   paso de cantidad- crece de verdad. Un enlace dentro de un texto o una
   miga de navegación NO: inflar su caja descolocaría la línea donde vive.
   Esos ganan superficie con un pseudoelemento invisible, que agranda la
   zona sensible sin mover ni un píxel de lo que se ve. */
@media(hover:none){
  .icon-btn{width:44px;height:44px}
  .btn{min-height:44px}
  .btn-sm{min-height:44px;padding:10px 14px}
  .inp,select,textarea{min-height:44px}
  .paginacion button{min-width:44px;height:44px}
  .stepper button{width:44px;height:44px}

  /* Los filtros en forma de ficha -estados de un pedido, vencimientos de
     cartera- median 33 px. No son decoracion: es como logistica recorta la
     lista de despachos desde una tableta, de pie. Solo los que se pulsan:
     `.chip` tambien se usa como etiqueta suelta, y ahi estorbaria. */
  button.chip,a.chip{min-height:44px}

  /* Filtro de marca de la barra lateral: 38 px para una lista que se recorre
     con el pulgar mientras se compara.

     Va con `.cat-lateral-caja` delante por una razon concreta: la regla de
     38 px se declara MAS ABAJO en este mismo archivo, en la seccion del
     catalogo, y con la misma especificidad. Escrita a secas aqui, perdia por
     orden y no hacia nada. Es el mismo tropiezo que ya esta anotado unas
     lineas mas abajo con `.gal-acciones .icon-btn`. */
  .cat-lateral-caja .cat-marca-item{min-height:44px}

  /* Enlaces de navegación que van en lista -pie de página, migas-. Se
     estiran a lo alto con una zona sensible centrada en el texto; el texto
     no se mueve. */
  .pie-lista a,.migas a{position:relative}
  .pie-lista a::after,.migas a::after{
    content:'';position:absolute;left:0;right:0;
    top:50%;transform:translateY(-50%);height:44px;
  }

  /* "Vista rápida" vive ENCIMA de la foto del producto. Agrandar la pastilla
     a 44 px la convertiría en lo más llamativo de cada tarjeta, veinte veces
     por pantalla; y un fallo de puntería aquí abre una ventana en vez del
     producto, que es peor que no acertar. Así que crece la zona sensible y
     no el dibujo. */
  .prod-ojear::after{
    content:'';position:absolute;left:0;right:0;
    top:50%;transform:translateY(-50%);height:44px;
  }

  /* iOS Safari amplía la página entera al enfocar un campo de menos de
     16 px, y despues no vuelve a su sitio. El formulario no estaba roto:
     el navegador lo estaba rescatando. */
  .inp,.stepper input{font-size:16px}

  /* Sin :hover el botón no da señal de haber recibido el toque. El
     resaltado azul del navegador se sustituye por un estado propio, que
     respeta la paleta y no parpadea al hacer scroll. */
  a,button,.btn,.icon-btn,label,summary{
    -webkit-tap-highlight-color:transparent;
    touch-action:manipulation;
  }
  .icon-btn:active{background:var(--surface-3);color:var(--primary-dark)}
  .nav>a:active,.nav-grupo-menu a:active{background:var(--surface-3)}
  .btn-sec:active:not(:disabled){background:var(--surface-2);border-color:var(--border-strong)}
  .btn-fantasma:active:not(:disabled){background:var(--surface-3)}
  .btn-primario:active:not(:disabled){background:var(--primary-hover)}

  /* En táctil no existe el hover: la barra de acciones de la galería quedaba
     permanentemente oculta y borrar una imagen o marcarla como principal era
     imposible desde el teléfono. Va aquí, al final, porque `.gal-acciones
     .icon-btn{width:24px}` se declara más abajo en su propia sección y con la
     misma especificidad: escrita antes, esta regla perdía por orden. */
  .gal-item{height:132px;display:flex;flex-direction:column}
  .gal-item img{height:auto;flex:1;min-height:0}
  .gal-acciones{opacity:1;transform:none;position:static;background:var(--surface-2)}
  /* Una de estas acciones borra la imagen: 24 px no es un objetivo honesto
     para un pulgar. */
  .gal-acciones .icon-btn{width:44px;height:44px}
  .tabla.apilable tr:active{background:var(--primary-softer)}
}

/* En pantallas estrechas el rotulo del boton de portal sobra: el candado ya
   dice lo que hace, y quitarlo deja sitio al carrito, que ahi importa mas. */
@media(max-width:560px){
  .solo-ancho{display:none}
}

/* Boton flotante de WhatsApp. Fijo y sobre el contenido: es el canal por el que
   llega la mayoria de las consultas, y en el pie solo lo encuentra quien baja
   hasta el final. Se aparta de la barra inferior del telefono con el area
   segura, como el resto de elementos anclados abajo. */
.wa-flotante{
  position:fixed;right:16px;z-index:50;
  bottom:calc(16px + env(safe-area-inset-bottom,0px));
  width:56px;height:56px;border-radius:50%;
  display:grid;place-items:center;
  background:#25D366;color:#fff;
  box-shadow:var(--sh-3);
  transition:transform var(--t),box-shadow var(--t);
}
.wa-flotante:hover{transform:translateY(-2px);box-shadow:var(--sh-4,var(--sh-3))}
.wa-flotante:active{transform:none}
@media(max-width:560px){
  /* Algo mas pequeño y pegado al borde: en un movil 56px tapan contenido. */
  .wa-flotante{width:52px;height:52px;right:12px}
}

/* Corazón de "guardar", en la esquina de la foto del producto.
   Siempre visible, también sin ratón: a diferencia de "Vista rápida", esto no
   se puede hacer de otra manera desde la rejilla. Apagado es un contorno gris
   discreto; encendido se rellena. */
.prod-fav{
  position:absolute;top:var(--sp-2);right:var(--sp-2);z-index:2;
  width:36px;height:36px;border-radius:50%;
  display:grid;place-items:center;
  background:rgba(255,255,255,.92);border:1px solid var(--border);
  color:var(--text-3);cursor:pointer;
  box-shadow:var(--sh-1);
  transition:color var(--t),background var(--t),transform var(--t-rapido);
}
.prod-fav:hover{color:var(--danger,#DC2626);border-color:var(--danger,#DC2626)}
.prod-fav:active{transform:scale(.92)}
.prod-fav.on{color:var(--danger,#DC2626);border-color:var(--danger,#DC2626)}
.prod-fav.on svg{fill:currentColor}
.prod-fav:focus-visible{outline:none;box-shadow:var(--ring)}
/* Zona sensible a 44 px sin agrandar el círculo, que taparía la foto. */
@media(hover:none){
  .prod-fav::after{
    content:'';position:absolute;top:50%;left:50%;
    transform:translate(-50%,-50%);width:44px;height:44px;
  }
}

/* Segunda foto al pasar el ratón, solo en las tarjetas que la tienen (de ahí
   `.con-segunda`: sin esa clase no hay nada que hacer y la regla no se aplica).
   Va encima de la primera con un fundido corto; las dos ocupan el mismo hueco,
   así que la tarjeta no se mueve ni un píxel al cambiar. */
.prod-img.con-segunda{position:relative}
.prod-img-2{
  position:absolute;inset:0;width:100%;height:100%;object-fit:contain;
  opacity:0;transition:opacity 180ms ease;pointer-events:none;
}
.prod:hover .prod-img.con-segunda .prod-img-2{opacity:1}
/* En táctil no hay ratón: la segunda foto no se enseña nunca y, sobre todo,
   no se descarga por nada. Está en la ficha del producto, que es donde quien
   va en serio la busca. */
@media(hover:none){
  .prod-img-2{display:none}
}
@media(prefers-reduced-motion:reduce){
  .prod-img-2{transition:none}
}

/* Progreso hacia el envío gratis. La cifra sola ("te faltan $60.000") obliga
   a compararla mentalmente con el umbral; la barra se entiende de un vistazo,
   que es lo que se hace mirando un carrito. */
.envio-barra-texto{
  display:flex;justify-content:space-between;align-items:baseline;gap:var(--sp-2);
  font-size:12.5px;color:var(--text-2);margin-bottom:5px;
}
.envio-barra-pct{font-weight:700;color:var(--success);font-variant-numeric:tabular-nums}
.envio-barra-pista{
  height:7px;border-radius:999px;background:var(--surface-3);overflow:hidden;
}
.envio-barra-relleno{
  height:100%;border-radius:999px;
  background:linear-gradient(90deg,var(--success-soft,#86efac),var(--success));
  transition:width var(--t);
}
.envio-gratis-ok{
  display:flex;align-items:center;gap:7px;
  font-size:13px;font-weight:650;color:var(--success);
}
/* Quien pide no ver animaciones tampoco quiere una barra deslizándose. */
@media(prefers-reduced-motion:reduce){
  .envio-barra-relleno{transition:none}
}

/* Selector de ubicación sobre el mapa (modal de dos pasos).
   Las baldas se ven como lo que son: una rejilla por nivel, cada una con lo
   que ya contiene. Quien elige decide con el dato delante, no a ciegas. */
.elg-migas{
  display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  font-size:13px;color:var(--text-3);margin-bottom:var(--sp-3);
}
.elg-migas [aria-current]{color:var(--text-2);font-weight:650}
.elg-atras{
  display:inline-flex;align-items:center;gap:5px;min-height:32px;
  background:none;border:0;color:var(--primary);cursor:pointer;font:inherit;padding:0;
}
/* Volver al paso anterior se pulsa con el pulgar, de pie frente al estante.
   Medido en movil: 86x32. El resto de la pantalla cumple 44 porque hereda de
   `.btn`; este boton no es un `.btn`, asi que hay que decirlo aqui. */
@media(hover:none){ .elg-atras{min-height:44px;padding-right:8px} }
.elg-atras:hover{text-decoration:underline}
.elg-sep{color:var(--border-2)}
.elg-cargando{padding:var(--sp-5);text-align:center;color:var(--text-3)}
.elg-pisos{display:flex;flex-wrap:wrap;gap:var(--sp-2)}
.elg-lista{display:flex;flex-direction:column;gap:6px;max-height:48vh;overflow:auto}
.elg-item{
  display:flex;align-items:center;gap:var(--sp-3);width:100%;min-height:44px;
  padding:var(--sp-2) var(--sp-3);
  background:var(--surface);border:1px solid var(--border);border-radius:var(--r-sm);
  text-align:left;cursor:pointer;
}
.elg-item:hover{border-color:var(--primary-light);background:var(--surface-2)}
.elg-item svg{margin-left:auto;color:var(--text-3)}
.elg-resumen{font-size:13px;color:var(--text-2);margin-bottom:var(--sp-3)}
.elg-nivel{margin-bottom:var(--sp-4)}
.elg-posiciones{
  display:grid;gap:var(--sp-2);margin-top:6px;
  grid-template-columns:repeat(auto-fill,minmax(150px,1fr));
}
.elg-balda{
  display:flex;flex-direction:column;gap:3px;min-height:72px;
  padding:var(--sp-2) var(--sp-3);text-align:left;cursor:pointer;
  background:var(--surface);border:1px solid var(--border);border-radius:var(--r-sm);
  font-size:12px;
}
.elg-balda:hover:not(:disabled){border-color:var(--primary);background:var(--primary-softer,var(--surface-2))}
.elg-balda:focus-visible{outline:none;box-shadow:var(--ring)}
/* Una balda que no se puede elegir se ve apagada Y dice por qué: el color
   solo no distingue "desactivada" de "es el origen". */
.elg-balda.no{opacity:.55;cursor:not-allowed}
/* Avisa, no impide: la capacidad configurada puede estar desactualizada y
   quien está delante del estante ve si cabe. */
.elg-balda.justa{border-color:var(--amber)}
.elg-pos{font-family:var(--f-display);font-weight:700;font-size:15px;color:var(--text)}
.elg-estado{color:var(--text-2);line-height:1.35}
.elg-prod{display:inline-block;margin-right:6px}
.elg-cap{color:var(--text-3);font-variant-numeric:tabular-nums}
.elg-motivo{color:var(--amber);font-weight:650}

/* Ficha de localización de un producto en el plano.
   Las cifras van en fila y con su rótulo: "27 / 20 / +7" sin etiquetas obliga
   a recordar cuál es cuál, y la del medio es la que decide si hay que ir a
   contar una balda. */
.loc-cifras{display:flex;flex-wrap:wrap;gap:var(--sp-5)}
.loc-cifras>div{display:flex;flex-direction:column;gap:2px}
.loc-cifras strong{font-family:var(--f-display);font-size:19px;letter-spacing:-.02em}

/* Cada ubicación es un botón: lleva el mapa hasta ella. */
.loc-sitio{
  display:flex;align-items:center;gap:var(--sp-3);width:100%;
  min-height:44px;padding:var(--sp-2) var(--sp-3);
  background:var(--surface);border:1px solid var(--border);
  border-radius:var(--r-sm);text-align:left;cursor:pointer;
  transition:border-color var(--t),background var(--t);
}
.loc-sitio:hover{border-color:var(--primary-light);background:var(--surface-2)}
.loc-sitio:focus-visible{outline:none;box-shadow:var(--ring)}
.loc-sitio svg{color:var(--text-3);flex:0 0 auto}

/* Título del panel de fallo del lector. El mensaje dice QUÉ pasó y CÓMO se
   arregla, así que necesita jerarquía: el título se lee de un vistazo desde
   un pasillo, el detalle se lee si hace falta. */
.esc-permiso-tit{
  display:flex;align-items:center;gap:8px;
  font-family:var(--f-display);font-weight:700;font-size:var(--fs-md);
  color:var(--text);
}
.esc-permiso-tit svg{color:var(--amber);flex:0 0 auto}

/* Aviso de referencias ausentes en la vista previa de una importación.
   Borde ámbar: no es un error -el archivo puede ser parcial a propósito- pero
   tampoco es un detalle, porque marcar su casilla cambia existencias de
   productos que no están en la pantalla. */
.imp-ausentes{border-left:3px solid var(--amber)}
.imp-ausentes .filtro-check{align-items:flex-start;min-height:0;padding:6px 0}
.imp-ausentes .filtro-check span{line-height:1.45}

/* Casilla de filtro en la barra lateral del catálogo. Toda la fila es la
   etiqueta, así que el toque acierta en el texto y no solo en el cuadrito. */
.filtro-check{
  display:flex;align-items:center;gap:var(--sp-2);
  min-height:44px;cursor:pointer;
  font-size:var(--fs-sm);color:var(--text-2);
}
.filtro-check input{width:18px;height:18px;accent-color:var(--primary);flex:0 0 auto}
.filtro-check:hover{color:var(--text)}

/* Estrella de "producto destacado" en la tabla de administración.
   Apagada es un contorno gris que no compite con el resto de la fila;
   encendida se rellena en ámbar, que es como se lee "destacado" sin leer. */
.icon-btn.destacado-on{color:var(--amber);background:var(--amber-soft,rgba(217,119,6,.10))}
.icon-btn.destacado-on svg{fill:currentColor}

/* =====================================================================
   BARRA FIJA DE COMPRA (móvil)
   El botón de compra de la ficha arranca a 866 px de alto en un teléfono de
   844: nace fuera de la primera pantalla, y la ficha mide 3.542. Esta barra
   lo mantiene al alcance mientras se lee el resto.
   Solo en pantallas estrechas: en un escritorio el botón real se ve casi
   siempre y una barra anclada abajo sobra.
   ===================================================================== */
.compra-fija{display:none}

@media(max-width:860px){
  .compra-fija{
    display:block;position:fixed;left:0;right:0;z-index:55;
    /* `bottom:0` más el área segura: en un iPhone con barra de gestos, una
       barra pegada al borde queda medio tapada y el pulgar la falla. */
    bottom:0;padding-bottom:env(safe-area-inset-bottom,0px);
    background:rgba(255,255,255,.94);
    backdrop-filter:saturate(180%) blur(12px);
    border-top:1px solid var(--border);
    box-shadow:0 -6px 20px rgba(15,42,66,.10);
  }
  .compra-fija[hidden]{display:none}

  .compra-fija-caja{
    display:flex;align-items:center;gap:var(--sp-3);
    padding:var(--sp-3) var(--sp-4);
  }
  .compra-fija-texto{min-width:0;flex:1}
  /* Una línea y con puntos suspensivos: el nombre está arriba completo, aquí
     solo sirve para confirmar qué se está agregando. */
  .compra-fija-nom{
    font-size:12px;color:var(--text-3);line-height:1.2;
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  }
  .compra-fija-precio{
    font-family:var(--f-display);font-weight:700;font-size:17px;
    letter-spacing:-.02em;color:var(--text);line-height:1.25;
  }
  /* `width:auto` deshace el `width:100%` de `.btn-comprar`, que ahí tiene
     sentido -en la ficha el botón ocupa la línea entera- y aquí dejaba el
     precio en 0 px: solo se veía el símbolo de la moneda. */
  .compra-fija .btn{min-height:46px;width:auto;flex:0 1 auto;min-width:0}

  /* Red de seguridad, no un arreglo a algo que pasa hoy: la ficha de producto
     no monta el botón flotante de WhatsApp —solo lo hace el catálogo—, así
     que ahora mismo no hay colisión. Pero los dos son `position:fixed` en la
     misma esquina, y el día que la ficha lo lleve, la barra le pasaría por
     debajo y el pulgar acertaría el que no es. Cuesta tres líneas dejarlo
     resuelto de antemano. */
  body.con-compra-fija .wa-flotante{
    bottom:calc(84px + env(safe-area-inset-bottom,0px));
  }
}

/* =====================================================================
   CAPA DE ACABADO
   ---------------------------------------------------------------------
   Va al final para ganar por orden sin subir especificidad ni usar
   !important. Aqui solo hay profundidad, movimiento y aire: nada que
   cambie QUE hace un elemento, solo como se siente al usarlo.
   ===================================================================== */

/* --- Movimiento ---------------------------------------------------- */

/* Se anima una lista corta de propiedades, no `all`. Animar `all` incluye
   `height`, `width` y `top`, que provocan recalculo de diseno en cada
   fotograma y hacen que una tabla larga vaya a tirones en un telefono. */
.btn, .icon-btn, .card, .prod, .tag, .chip, .inp, select, textarea,
.nav > a, .nav-grupo-menu a, a.enlace-prod{
  transition:
    background-color var(--t),
    border-color var(--t),
    color var(--t),
    box-shadow var(--t),
    transform var(--t);
}

/* --- Botones ------------------------------------------------------- */

.btn{border-radius:var(--r)}
.btn:hover:not(:disabled){transform:translateY(-1px)}
/* Al pulsar vuelve a su sitio: el boton "se hunde" bajo el dedo, que es la
   metafora que todo el mundo entiende sin explicacion. */
.btn:active:not(:disabled){transform:translateY(0) scale(.985)}
.btn:disabled{opacity:.55;cursor:not-allowed;box-shadow:none;transform:none}

.btn-primario{box-shadow:var(--sh-1)}
.btn-primario:hover:not(:disabled){box-shadow:var(--sh-2)}
.btn-exito:hover:not(:disabled),
.btn-peligro:hover:not(:disabled){box-shadow:var(--sh-2)}

/* El foco se ve SIEMPRE, tambien con raton. Ocultarlo deja sin pista a quien
   navega con teclado, y es la ayuda mas barata que existe. */
.btn:focus-visible,
.icon-btn:focus-visible,
.chip:focus-visible,
a:focus-visible{outline:none;box-shadow:var(--ring)}
.btn-peligro:focus-visible{box-shadow:var(--ring-danger)}

/* --- Tarjetas ------------------------------------------------------ */

.card{
  border-radius:var(--r-lg);
  box-shadow:var(--sh-1);
}
/* Solo las tarjetas que SON un enlace o un boton reaccionan al raton. Que se
   levante algo que no se puede pulsar promete una accion que no existe. */
a .card:hover,
.prod:hover,
button .card:hover{box-shadow:var(--sh-3);transform:translateY(-3px)}

.card-pad{padding:var(--sp-5)}
@media(min-width:900px){
  /* En pantalla grande sobra sitio: mas aire se lee mejor. En movil el mismo
     padding se comeria el ancho util. */
  .card-pad{padding:var(--sp-6)}
}

/* --- Campos -------------------------------------------------------- */

.inp, select.inp, textarea.inp{border-radius:var(--r-sm)}
.inp:hover:not(:disabled):not(:focus){border-color:var(--border-strong)}
.inp:focus{
  outline:none;
  border-color:var(--primary);
  box-shadow:var(--ring);
}

/* --- Modales ------------------------------------------------------- */

.modal{
  border-radius:var(--r-xl);
  box-shadow:var(--sh-4);
  animation:modal-entra var(--t-lento) both;
}
@keyframes modal-entra{
  from{opacity:0;transform:translateY(10px) scale(.985)}
  to{opacity:1;transform:none}
}
.modal-fondo{backdrop-filter:blur(2px)}
@media(max-width:520px){
  /* Hoja inferior en movil: entra desde abajo, que es de donde el pulgar
     espera que salga. Y sin escala, que en pantalla completa se ve raro. */
  .modal{border-radius:var(--r-xl) var(--r-xl) 0 0}
  @keyframes modal-entra{
    from{opacity:0;transform:translateY(24px)}
    to{opacity:1;transform:none}
  }
}

/* --- Tablas y etiquetas -------------------------------------------- */

.tabla-scroll{border-radius:var(--r-lg)}
.tabla tbody tr:hover{background:var(--primary-softer)}
.tag{border-radius:var(--r-full);letter-spacing:.1px}

/* --- Aire ---------------------------------------------------------- */

.main{padding-top:var(--sp-6)}
.card + .card{margin-top:var(--sp-4)}
.rejilla-campos{gap:var(--sp-4)}
h1{letter-spacing:-.4px}
h2{letter-spacing:-.2px}

/* Cabecera con un filo de marca: da altura a la barra sin anadir una sombra
   pesada que compita con las tarjetas. */
.hdr{box-shadow:0 1px 0 var(--border-2), 0 4px 16px rgba(10,45,80,.05)}

/* =====================================================================
   REDISEÑO — SISTEMA DE COMPONENTES
   ---------------------------------------------------------------------
   Va al final para ganar por orden, sin !important ni subir especificidad.
   ===================================================================== */

:root{
  /* Acento calido. La paleta era azul de principio a fin, y en una tienda eso
     deja el precio y el "agregar" compitiendo con la navegacion. Un acento
     ambar separa lo comercial de lo estructural sin colorear la interfaz. */
  --accent:#C2410C;
  --accent-hover:#9A3412;
  --accent-soft:#FFF1E7;
  --accent-border:#FBD5BC;

  /* Elevacion por niveles, no por tamaño de sombra. Nombrarlos por su altura
     obliga a decidir QUE esta por encima de que. */
  --elev-1:var(--sh-1);
  --elev-2:var(--sh-2);
  --elev-3:var(--sh-3);
  --elev-4:var(--sh-4);
}

/* --- Tarjeta de producto ------------------------------------------- */

.prod{border-radius:var(--r-lg);box-shadow:var(--elev-1)}
.prod:hover{box-shadow:var(--elev-3);transform:translateY(-3px)}
/* La imagen se acerca un poco al pasar: sugiere que hay algo mas que ver
   sin mover la tarjeta entera, que marearia en una rejilla de veinte. */
.prod:hover .prod-img img{transform:scale(1.04)}

.prod-img{aspect-ratio:1/1;background:var(--surface)}
@media(min-width:700px){
  /* Cuadrada en movil —aprovecha el ancho— y algo apaisada en pantalla
     grande, donde caben mas columnas. */
  .prod-img{aspect-ratio:4/3}
}
.prod-img img{padding:var(--sp-3)}

.prod-cuerpo{display:flex;flex-direction:column;gap:var(--sp-1);padding:var(--sp-4)}

/* Categoria: dato de contexto, no titular. */
.prod-linea{
  font-size:var(--fs-caption);text-transform:uppercase;letter-spacing:.6px;
  color:var(--text-3);font-weight:600;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}

.prod-nom{
  font-size:var(--fs-md);line-height:1.32;font-weight:650;color:var(--text);
  /* Tres lineas: los nombres de ferreteria son largos y cortarlos en dos deja
     mitades sin sentido. Un alto fijo mantiene alineadas todas las tarjetas
     de la fila, que es lo que hace que una rejilla se lea como rejilla. */
  display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;
  overflow:hidden;min-height:calc(1.32em * 3);
}

.prod-pie{margin-top:auto;padding-top:var(--sp-3)}
.prod-precio{
  font-family:var(--f-display);
  font-size:var(--fs-xl);font-weight:700;color:var(--text);
  letter-spacing:-.5px;line-height:1.1;
}
.prod-estado{margin-top:var(--sp-2)}
/* La referencia baja al final y en gris: sirve para pedirla por telefono, no
   para presentar el producto. */
.prod-ref{
  margin-top:var(--sp-2);font-size:var(--fs-caption);color:var(--text-3);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}

/* --- Rejilla ------------------------------------------------------- */

.rejilla-prod{
  display:grid;gap:var(--sp-4);
  /* auto-fill con minimo: dos columnas en un telefono de 360px y hasta seis
     en escritorio, sin escribir un punto de corte por cada tamaño. */
  grid-template-columns:repeat(auto-fill,minmax(160px,1fr));
}
@media(min-width:700px){ .rejilla-prod{grid-template-columns:repeat(auto-fill,minmax(210px,1fr))} }

/* --- Botón de compra ----------------------------------------------- */

.btn-comprar{
  width:100%;min-height:44px;
  background:var(--accent);color:#fff;border-color:var(--accent);
  font-weight:650;
}
.btn-comprar:hover:not(:disabled){background:var(--accent-hover);box-shadow:var(--elev-2)}
.btn-comprar:focus-visible{box-shadow:0 0 0 3px rgba(194,65,12,.25)}

/* --- Estados vacíos ------------------------------------------------ */

.vacio{
  display:grid;place-items:center;text-align:center;
  padding:var(--sp-8) var(--sp-5);color:var(--text-3);
}
.vacio svg{color:var(--border-strong);margin-bottom:var(--sp-3)}
.vacio-titulo{
  font-family:var(--f-display);font-size:var(--fs-lg);font-weight:650;
  color:var(--text);margin-bottom:var(--sp-1);
}

/* --- Carga --------------------------------------------------------- */

/* Esqueletos en vez de un giro: el usuario ve DONDE va a aparecer cada cosa,
   asi que la pagina no da un salto al cargar. */
@keyframes latido{0%,100%{opacity:.55}50%{opacity:.9}}
.cargando-fila,.cargando-prod{
  background:var(--surface-3);border-radius:var(--r-sm);
  animation:latido 1.4s ease-in-out infinite;
}

/* --- Tablas -------------------------------------------------------- */

.tabla thead th{
  font-size:var(--fs-caption);text-transform:uppercase;letter-spacing:.5px;
  color:var(--text-3);font-weight:650;
  background:var(--surface-2);
  position:sticky;top:0;z-index:1;
}
.tabla tbody td{padding-top:var(--sp-3);padding-bottom:var(--sp-3)}

/* --- Notificaciones ------------------------------------------------ */

.toast{
  border-radius:var(--r);box-shadow:var(--elev-3);
  border-left:4px solid var(--primary);
  animation:toast-entra var(--t-lento) both;
}
.toast.ok{border-left-color:var(--success)}
.toast.err{border-left-color:var(--danger)}
@keyframes toast-entra{
  from{opacity:0;transform:translateY(-8px)}
  to{opacity:1;transform:none}
}

/* --- Franja de confianza (tienda pública) --------------------------- */

.franja{
  background:var(--surface);
  border-top:1px solid var(--border-2);
  border-bottom:1px solid var(--border-2);
  margin-bottom:var(--sp-6);
}
.franja-in{
  max-width:var(--ancho);margin:0 auto;
  padding:var(--sp-5) var(--sp-4);
  display:grid;gap:var(--sp-4);
  /* Cuatro en escritorio, dos en tableta y una columna en telefono. Con
     auto-fit no hace falta un punto de corte por cada tamaño. */
  grid-template-columns:repeat(auto-fit,minmax(230px,1fr));
}
.franja-item{display:flex;gap:var(--sp-3);align-items:flex-start}
.franja-ico{
  flex:none;width:40px;height:40px;border-radius:var(--r-sm);
  display:grid;place-items:center;
  background:var(--primary-soft);color:var(--primary);
}
.franja-item strong{display:block;font-size:var(--fs-base);color:var(--text);line-height:1.3}
.franja-item span:last-child{display:block;font-size:var(--fs-sm);color:var(--text-3);margin-top:2px}

/* EN EL TELEFONO, DOS COLUMNAS Y NO CUATRO FILAS.
 *
 * `minmax(230px,1fr)` sobre 358 px utiles daba UNA columna, asi que los
 * cuatro puntos se apilaban: 201 px medidos, mas que medio hero, puestos
 * entre el visitante y el primer producto.
 *
 * No se esconde nada —el umbral de envio gratis y el minimo de pedido son
 * informacion comercial que hay que poder leer—: se compacta el icono, se
 * aprieta la tipografia y entran dos por fila. */
@media(max-width:620px){
  .franja-in{grid-template-columns:repeat(2,minmax(0,1fr));
    gap:var(--sp-3);padding:var(--sp-4) var(--sp-4)}
  .franja-item{gap:var(--sp-2)}
  .franja-ico{width:30px;height:30px;border-radius:8px}
  .franja-ico svg{width:16px;height:16px}
  .franja-item strong{font-size:12.5px;line-height:1.25}
  .franja-item span:last-child{font-size:11px;line-height:1.3;margin-top:1px}
}

/* --- Mosaico de categorías ----------------------------------------- */

.cat-mosaico{
  display:grid;gap:var(--sp-3);
  /* Dos columnas en un telefono de 320px, cuatro en escritorio. */
  grid-template-columns:repeat(auto-fit,minmax(150px,1fr));
}
.cat-item{
  display:flex;flex-direction:column;align-items:flex-start;gap:var(--sp-1);
  padding:var(--sp-4);text-align:left;
  background:var(--surface);border:1px solid var(--border);
  border-radius:var(--r-lg);box-shadow:var(--elev-1);
  cursor:pointer;
  /* 44px minimos aunque el contenido sea corto: es un objetivo tactil. */
  min-height:96px;
  transition:box-shadow var(--t),transform var(--t),border-color var(--t);
}
.cat-item:hover{box-shadow:var(--elev-2);transform:translateY(-2px);border-color:var(--primary-light)}
.cat-item:active{transform:none}
.cat-item:focus-visible{outline:none;box-shadow:var(--ring)}
.cat-ico{
  width:38px;height:38px;border-radius:var(--r-sm);
  display:grid;place-items:center;
  background:var(--primary-soft);color:var(--primary);
  margin-bottom:var(--sp-1);
}
.cat-nom{
  font-family:var(--f-display);font-size:var(--fs-base);font-weight:650;
  color:var(--text);line-height:1.25;
}
.cat-num{font-size:var(--fs-caption);color:var(--text-3)}

/* --- Garantías de la ficha ----------------------------------------- */

.ficha-garantias{
  display:grid;gap:var(--sp-2);
  padding-top:var(--sp-3);
  border-top:1px solid var(--border-2);
  font-size:var(--fs-sm);color:var(--text-2);
}
.ficha-garantias > div{display:flex;align-items:center;gap:var(--sp-2)}
.ficha-garantias svg{color:var(--primary);flex:none}

/* --- Badge de últimas unidades -------------------------------------- */

.badge-pocas{
  display:inline-block;margin-left:var(--sp-2);
  /* Sin padding vertical propio: la altura la da la linea del texto. Un valor
     suelto en pixeles no cambia cuando cambia la escala. */
  padding:var(--sp-1) var(--sp-2);border-radius:var(--r-full);
  line-height:1;
  background:var(--accent-soft);color:var(--accent);
  border:1px solid var(--accent-border);
  font-size:var(--fs-caption);font-weight:700;
  text-transform:none;letter-spacing:0;
}

/* --- Localizar pedido ---------------------------------------------- */

.loc-resumen{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--sp-2)}
.loc-dato{
  display:flex;flex-direction:column;align-items:center;text-align:center;
  padding:var(--sp-3) var(--sp-2);border-radius:var(--r);
  background:var(--surface-2);
}
.loc-dato strong{font-family:var(--f-display);font-size:var(--fs-2xl);line-height:1}
.loc-dato span{font-size:var(--fs-caption);color:var(--text-3);margin-top:var(--sp-1)}
.loc-ok strong{color:var(--success)}
.loc-aviso strong{color:var(--warning)}
.loc-error strong{color:var(--danger)}

/* El numero de parada: el auxiliar sabe en que punto del recorrido va. */
.loc-orden{
  flex:none;width:32px;height:32px;border-radius:50%;
  display:grid;place-items:center;
  background:var(--primary);color:#fff;font-weight:700;font-size:var(--fs-sm);
}

/* El piso va primero y grande: decide a que escalera se va. */
.loc-pisos{display:flex;flex-wrap:wrap;gap:var(--sp-1);margin-bottom:var(--sp-1)}
.loc-pisos span{
  padding:var(--sp-1) var(--sp-2);border-radius:var(--r-full);
  background:var(--primary-soft);color:var(--primary);
  font-weight:700;font-size:var(--fs-sm);line-height:1;
}

.loc-estante{
  display:flex;flex-wrap:wrap;align-items:baseline;gap:var(--sp-2);
  padding:var(--sp-2) 0;border-top:1px solid var(--border-2);
  font-size:var(--fs-sm);
}
.loc-estante code{font-weight:700;font-size:var(--fs-base)}
.loc-estante span{flex-basis:100%}

/* La comparacion con Orion es contexto, no la tarea: va al final y en gris.
   Solo el caso de EXCESO lleva color, porque ese si indica un error. */
.loc-dif{
  margin-top:var(--sp-2);padding-top:var(--sp-2);
  border-top:1px dashed var(--border-2);
  font-size:var(--fs-caption);color:var(--text-3);
}
.loc-dif-excede{color:var(--warning);font-weight:600}

/* --- Ubicar en tres pasos ------------------------------------------ */

.ubi-cab{display:flex;align-items:center;gap:var(--sp-2);margin-bottom:var(--sp-3)}
.ubi-num{
  width:28px;height:28px;border-radius:50%;flex:none;
  display:grid;place-items:center;
  background:var(--primary);color:#fff;font-weight:700;font-size:var(--fs-sm);
}
/* Opciones grandes: se tocan con el pulgar y a veces con guantes. */
.ubi-opcion{
  width:100%;min-height:52px;margin-bottom:var(--sp-2);
  display:flex;align-items:center;gap:var(--sp-2);text-align:left;
}
.ubi-hecho{
  display:flex;align-items:center;gap:var(--sp-3);
  padding:var(--sp-3) var(--sp-4);margin-bottom:var(--sp-2);
  border-radius:var(--r);background:var(--success-soft);color:var(--success);
}
.ubi-hecho > div{color:var(--text)}

/* --- Informe de diferencias ---------------------------------------- */

.inf-pct{font-family:var(--f-display);font-size:var(--fs-4xl);line-height:1;color:var(--primary)}
.inf-grupos{display:grid;gap:var(--sp-2);grid-template-columns:repeat(auto-fit,minmax(150px,1fr))}
.inf-grupo{
  display:flex;flex-direction:column;align-items:flex-start;gap:2px;text-align:left;
  padding:var(--sp-3) var(--sp-4);border-radius:var(--r);
  background:var(--surface);border:1px solid var(--border);box-shadow:var(--elev-1);
  cursor:pointer;min-height:88px;
  transition:box-shadow var(--t),border-color var(--t),transform var(--t);
}
.inf-grupo:hover{box-shadow:var(--elev-2);transform:translateY(-1px)}
.inf-grupo:focus-visible{outline:none;box-shadow:var(--ring)}
/* El grupo activo se distingue por borde Y peso, no solo por color. */
.inf-grupo.activo{border:2px solid var(--primary);background:var(--primary-softer)}
.inf-grupo strong{font-family:var(--f-display);font-size:var(--fs-2xl);line-height:1}
.inf-grupo.loc-error strong{color:var(--danger)}
.inf-grupo.loc-aviso strong{color:var(--warning)}
.inf-grupo.loc-ok strong{color:var(--success)}
.inf-tit{font-weight:650;font-size:var(--fs-sm);color:var(--text)}
.inf-ayuda{font-size:var(--fs-caption);color:var(--text-3)}
.inf-cifras{display:flex;gap:var(--sp-4);font-size:var(--fs-sm);color:var(--text-2)}

/* --- Inventario físico --------------------------------------------- */
.conteo-fila{display:block;width:100%;text-align:left;cursor:pointer}
.conteo-fila:hover{box-shadow:var(--elev-2)}
.conteo-fila:focus-visible{outline:none;box-shadow:var(--ring)}

/* --- Plano de bodega ------------------------------------------------ */

.plano-caja{
  /* El plano puede ser mas ancho que la pantalla: se desplaza dentro de su
     caja, nunca arrastrando la pagina entera de lado. */
  overflow-x:auto;-webkit-overflow-scrolling:touch;
  background:var(--surface-2);border:1px solid var(--border-2);
  border-radius:var(--r-lg);padding:var(--sp-3);
}
.plano-svg{display:block;width:100%;min-width:420px;height:auto}
.plano-el{cursor:pointer}
.plano-el rect{transition:opacity var(--t),stroke-width var(--t)}
.plano-el:hover rect{opacity:.85}
.plano-el:focus-visible{outline:none}
.plano-el:focus-visible rect{stroke:var(--primary);stroke-width:3}
/* La resaltada parpadea dos veces y se queda: llama la atencion sin marear. */
.plano-el.resaltada rect{animation:plano-late 1.2s ease-out 2}
@keyframes plano-late{0%,100%{opacity:1}50%{opacity:.55}}
.plano-txt{
  font-family:var(--f-mono);font-size:10px;font-weight:700;
  fill:#fff;pointer-events:none;
}
.plano-pendiente{
  display:inline-block;width:7px;height:7px;border-radius:50%;
  background:var(--warning);margin-left:6px;vertical-align:middle;
}
.plano-leyenda{
  display:flex;flex-wrap:wrap;gap:var(--sp-3);
  margin-top:var(--sp-3);font-size:var(--fs-caption);color:var(--text-3);
}
.plano-leyenda span{display:flex;align-items:center;gap:var(--sp-1)}
.plano-leyenda i{width:12px;height:12px;border-radius:3px;display:inline-block}

/* --- Modo edición del plano ----------------------------------------- */

/* Mientras se arrastra, el elemento se levanta y deja ver lo que hay debajo:
   sin eso, no se sabe si se esta soltando encima de otra estanteria. */
.plano-el.moviendo rect{opacity:.7;stroke:var(--primary);stroke-width:3}
.plano-el.moviendo{filter:drop-shadow(0 6px 10px rgba(10,45,80,.35))}
/* Sin seleccion de texto al arrastrar con el dedo. */
.plano-caja{touch-action:pan-x pan-y}
.plano-el{touch-action:none;user-select:none}

/* --- Diseñador de bodega -------------------------------------------- */

.plano-marco{position:relative}

/* El lienzo ocupa alto real, no una tarjeta: el plano es el protagonista. */
.plano-caja{min-height:56vh}
@media(min-width:900px){ .plano-caja{min-height:64vh} }

/* Controles de zoom flotando sobre el plano, al alcance del pulgar. */
.plano-zoom{
  position:absolute;right:var(--sp-3);bottom:var(--sp-3);
  display:flex;flex-direction:column;gap:var(--sp-1);
  background:var(--surface);border:1px solid var(--border);
  border-radius:var(--r);box-shadow:var(--elev-2);padding:var(--sp-1);
}
.plano-zoom-btn{
  /* 44px: es un objetivo tactil, no un icono decorativo. */
  width:44px;height:44px;border-radius:var(--r-sm);
  display:grid;place-items:center;
  background:transparent;color:var(--text-2);
  font-size:var(--fs-caption);font-weight:700;cursor:pointer;
  transition:background var(--t),color var(--t);
}
.plano-zoom-btn:hover{background:var(--primary-soft);color:var(--primary)}
.plano-zoom-btn:focus-visible{outline:none;box-shadow:var(--ring)}

.plano-tools{
  background:var(--surface);border:1px solid var(--border-2);
  border-radius:var(--r);padding:var(--sp-3);margin-bottom:var(--sp-3);
  display:flex;flex-wrap:wrap;gap:var(--sp-4);
}
.plano-tool-grupo{display:flex;flex-direction:column;gap:var(--sp-1)}

/* --- Ficha de estantería en árbol ----------------------------------- */

.est-mod{margin-bottom:var(--sp-4)}
/* Sangría por nivel: es la jerarquía real del estante, no decoración. */
.est-niv{margin-left:var(--sp-3);padding-left:var(--sp-3);
  border-left:2px solid var(--border-2);margin-bottom:var(--sp-3)}
.est-niv-tit{font-size:var(--fs-sm);font-weight:650;color:var(--text-2);
  margin-bottom:var(--sp-1)}
.est-pos{padding:var(--sp-2) 0;border-bottom:1px solid var(--border-2)}
.est-pos:last-child{border-bottom:0}
.est-prod{display:flex;align-items:center;gap:var(--sp-2);
  margin-top:var(--sp-1);font-size:var(--fs-sm)}

/* --- Barra contextual del diseñador --------------------------------- */

/* Pegada arriba del lienzo: al hacer scroll sigue a la vista, porque las
   acciones deben estar donde el usuario ya está mirando. */
.plano-ctx{
  position:sticky;top:0;z-index:5;
  background:var(--surface);border:1px solid var(--primary-light);
  border-radius:var(--r);box-shadow:var(--elev-2);
  padding:var(--sp-3);margin-bottom:var(--sp-2);
}
.plano-ctx-tit{
  display:flex;align-items:center;gap:var(--sp-2);
  margin-bottom:var(--sp-2);color:var(--primary);
}
.plano-ctx-tit strong{font-family:var(--f-display);font-size:var(--fs-md)}
/* Las acciones se envuelven y siguen siendo tocables: en un móvil caben tres
   por fila en vez de salirse de la pantalla. */
.plano-ctx-acc{display:flex;flex-wrap:wrap;gap:var(--sp-2)}
.plano-acc{min-height:44px}
@media(max-width:520px){
  /* El texto se conserva: un icono suelto no enseña qué hace el botón, que es
     justo el problema que esta barra viene a resolver. */
  .plano-acc{flex:1 1 calc(50% - var(--sp-2))}
}

.plano-colores{display:flex;flex-wrap:wrap;gap:var(--sp-2)}
.plano-color{
  width:48px;height:48px;border-radius:var(--r-sm);
  border:2px solid var(--border);cursor:pointer;
  display:grid;place-items:center;color:var(--text-3);font-weight:700;
  transition:transform var(--t),border-color var(--t);
}
.plano-color:hover{transform:scale(1.06);border-color:var(--primary)}
.plano-color:focus-visible{outline:none;box-shadow:var(--ring)}

/* --- Handles de redimensionar --------------------------------------- */

.plano-handle{
  fill:var(--surface);
  stroke:var(--accent);
  stroke-width:2.5;
  /* Sin esto el arrastre del dedo desplaza la página en vez del handle. */
  touch-action:none;
  transition:fill var(--t),r var(--t);
}
.plano-handle:hover{fill:var(--accent)}
.plano-handle:focus-visible{outline:none;fill:var(--accent);stroke:var(--primary)}
/* Los handles van sobre todo lo demás: si una estantería vecina los tapara,
   no habría forma de agarrarlos. */
.plano-handles{pointer-events:all}

/* --- Panel de capas -------------------------------------------------- */

.capas{
  background:var(--surface);border:1px solid var(--border);
  border-radius:var(--r-sm);
}
.capas summary{
  /* 44px de alto real: es un control táctil, no un enlace de texto. */
  display:flex;align-items:center;gap:var(--sp-1);
  padding:var(--sp-2) var(--sp-3);min-height:44px;
  cursor:pointer;font-size:var(--fs-sm);font-weight:600;color:var(--text-2);
  list-style:none;
}
.capas summary::-webkit-details-marker{display:none}
.capas[open] summary{border-bottom:1px solid var(--border-2)}
.capas-cuerpo{padding:var(--sp-3);min-width:210px}
.capa-item{
  display:flex;align-items:center;gap:var(--sp-2);
  padding:var(--sp-1) 0;min-height:36px;cursor:pointer;font-size:var(--fs-sm);
}
.capa-item input{width:18px;height:18px;flex:none}
/* Los ocultos se separan: no son una capa, son elementos que alguien apagó. */
.capa-ocultos{border-top:1px solid var(--border-2);margin-top:var(--sp-2);padding-top:var(--sp-2)}

/* --- Herramienta de medir -------------------------------------------- */

.plano-medida line{stroke:var(--accent);stroke-width:2;stroke-dasharray:6 4}
.plano-medida circle{fill:var(--accent)}
/* La cifra sobre fondo sólido: encima de una estantería oscura, un texto
   suelto no se lee. */
.plano-medida-fondo{fill:var(--surface);stroke:var(--accent);stroke-width:1}
.plano-medida-txt{
  font-family:var(--f-mono);font-size:11px;font-weight:700;
  fill:var(--accent);pointer-events:none;
}

/* --- Producto sin precio público ------------------------------------- */

/* Se dice, no se deja el hueco en blanco: un espacio vacío donde debería ir
   el precio hace dudar de si la tienda está rota. */
.prod-sin-precio{
  font-size:var(--fs-sm);font-weight:650;color:var(--text-3);
  line-height:1.1;padding-top:var(--sp-1);
}
.ficha-sin-precio{
  font-family:var(--f-display);font-size:var(--fs-xl);font-weight:700;
  color:var(--text-3);
}

/* --- Selector de cliente por búsqueda --------------------------------- */

.sel-cli-res{max-height:240px;overflow-y:auto;margin-top:var(--sp-2)}
.sel-cli-item{
  display:flex;align-items:center;gap:var(--sp-2);width:100%;
  /* 44px: se elige con el dedo en una tableta, no solo con el ratón. */
  min-height:44px;padding:var(--sp-2) var(--sp-3);
  background:transparent;border:0;border-bottom:1px solid var(--border-2);
  cursor:pointer;text-align:left;font-size:var(--fs-sm);
  transition:background var(--t);
}
.sel-cli-item:hover{background:var(--primary-soft)}
.sel-cli-item:focus-visible{outline:none;background:var(--primary-soft);box-shadow:var(--ring)}
/* El elegido en verde y con su código: se ve que la selección quedó hecha. */
.sel-cli-ok{
  display:flex;align-items:center;gap:var(--sp-2);
  padding:var(--sp-3);border-radius:var(--r-sm);
  background:var(--success-soft);color:var(--success);
}
.sel-cli-ok > div{color:var(--text)}

/* --- `hidden` tiene que ganar siempre ---------------------------------
 *
 * El navegador oculta con `[hidden]{display:none}` en su hoja por defecto, y
 * CUALQUIER regla propia de `display` la sobrescribe. Es decir: todo
 * componente nuestro con `display` declarado se seguia viendo aunque el
 * codigo lo marcara como oculto.
 *
 * Paso con el panel de categorias —la lista quedaba fija en pantalla tras
 * elegir— y afecta igual a los botones, que son `inline-flex`: el enlace de
 * WhatsApp de la ficha y el del formulario de contacto nacen ocultos.
 *
 * Esta regla va aqui, una sola vez, en vez de repetirla en cada componente. */
[hidden]{display:none !important}

/* --- Selector de categorías ------------------------------------------ */

/* El contenedor del filtro crece con su contenido: ninguna altura fija ni
   max-height, para que nada quede cortado si se abre el panel. */
.cat-sel{position:relative;height:auto;margin-bottom:var(--sp-3)}
/* La tarjeta que contiene los filtros debe poder dejar salir el panel. Se
   declara aqui, junto al selector, para que no se pierda si alguien retoca
   .card mas adelante. */
.card:has(.cat-sel){overflow:visible}

/* Una sola línea, tenga el catálogo diez categorías o doscientas. */
.cat-sel-btn{
  display:flex;align-items:center;gap:var(--sp-2);width:100%;
  min-height:46px;padding:0 var(--sp-3);
  background:var(--surface);border:1px solid var(--border);
  border-radius:var(--r-sm);color:var(--text-2);
  font-size:var(--fs-sm);font-weight:600;cursor:pointer;text-align:left;
  transition:border-color var(--t),background var(--t);
}
/* Hover sutil: no cambia de color, solo marca el borde. */
.cat-sel-btn:hover{border-color:var(--border-strong)}
.cat-sel-btn:focus-visible{outline:none;box-shadow:var(--ring)}
/* Con categoría puesta, el color principal del B2B — y nada más. */
.cat-sel-btn.activa{
  border-color:var(--primary);color:var(--primary);background:var(--primary-softer);
}

/* El contador es secundario: informa, no compite con el nombre. */
.cat-sel-n{
  font-family:var(--f-mono);font-size:11.5px;font-weight:600;
  color:var(--text-3);flex:none;
}
.cat-sel-btn.activa .cat-sel-n{color:var(--primary-light)}

.cat-sel-panel{
  /* z-index alto: debe quedar sobre el contador de productos y la rejilla,
     que vienen justo debajo. */
  position:absolute;z-index:60;top:calc(100% + 4px);left:0;right:0;
  background:var(--surface);border:1px solid var(--border);
  border-radius:var(--r-sm);box-shadow:var(--elev-2);
  display:flex;flex-direction:column;max-height:min(60vh,420px);
}
/* ESTO ES OBLIGATORIO y no es cosmetico.
 *
 * El atributo `hidden` oculta porque el navegador aplica `[hidden]{display:none}`
 * en su hoja por defecto. Cualquier regla propia de `display` —aqui, el
 * `display:flex` de arriba— GANA sobre esa, asi que el panel seguia visible
 * aunque el componente lo marcara como oculto: la flecha decia "cerrado" y la
 * lista seguia tapando el catalogo.
 *
 * Declararlo explicitamente hace que el DOM respete de verdad el estado. */
.cat-sel-cab{padding:var(--sp-2);border-bottom:1px solid var(--border-2)}
.cat-sel-buscar{font-size:16px}  /* 16px evita que iOS haga zoom al enfocar */
.cat-sel-lista{overflow-y:auto;-webkit-overflow-scrolling:touch;padding:var(--sp-1) 0}

.cat-sel-item{
  display:flex;align-items:center;gap:var(--sp-2);width:100%;
  /* 44px: se elige con el pulgar, no solo con el ratón. */
  min-height:44px;padding:0 var(--sp-3);
  background:transparent;border:0;cursor:pointer;text-align:left;
  font-size:var(--fs-sm);color:var(--text);
  transition:background var(--t);
}
.cat-sel-item:hover{background:var(--surface-2)}
.cat-sel-item:focus-visible{outline:none;background:var(--surface-2);box-shadow:var(--ring)}
.cat-sel-item.on{color:var(--primary);font-weight:650;background:var(--primary-softer)}
.cat-sel-vacio{padding:var(--sp-3);margin:0;color:var(--text-3);font-size:var(--fs-sm)}

/* En móvil el panel sube desde abajo y ocupa el ancho de la pantalla: un
   desplegable estrecho obliga a apuntar, y el pulgar llega mejor abajo. */
@media(max-width:699px){
  .cat-sel-panel{
    position:fixed;top:auto;bottom:0;left:0;right:0;
    max-height:70vh;border-radius:var(--r-lg) var(--r-lg) 0 0;
    padding-bottom:env(safe-area-inset-bottom,0px);
  }
  .cat-sel-item{min-height:48px}
}

/* --- Fila de filtros del catálogo ------------------------------------ */

/* Dos columnas en escritorio, una en móvil. Los filtros ocupan el alto de
   uno solo en vez de tres líneas apiladas. */
.filtros-fila{display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-3);align-items:end}
@media(max-width:699px){.filtros-fila{grid-template-columns:1fr;gap:var(--sp-2)}}
.filtro-campo{display:flex;flex-direction:column;gap:var(--sp-1);min-width:0}
/* El selector de categoría ya no añade su propio margen: lo pone la rejilla. */
.filtro-campo .cat-sel{margin-bottom:0}
/* Tres controles en una fila: orden, color y categoría. */
.filtros-3{grid-template-columns:repeat(3,1fr)}
@media(max-width:899px){.filtros-3{grid-template-columns:1fr 1fr}}
@media(max-width:599px){.filtros-3{grid-template-columns:1fr}}

/* --- Catálogo público: tarjeta de tienda ------------------------------
 *
 * La tarjeta pasó de "ficha de inventario" a unidad de compra. Los cambios no
 * son de adorno: cada uno responde a un problema concreto de la pantalla
 * anterior.
 */

/* 1. La imagen manda. Era 4/3 y el producto quedaba pequeño entre márgenes
 *    blancos. Cuadrada y más alta, el producto se reconoce de un vistazo, que
 *    es lo primero que hace quien compra. */
.publico .prod-img{aspect-ratio:1/1}

/* `object-fit:contain` y el padding ya los pone `.prod-img img` más arriba: no
   se repiten aquí. Lo único que cambia en la tienda es la proporción. */
.prod-img-link{display:block;text-decoration:none}
.prod-img-link:focus-visible{outline:none;box-shadow:var(--ring)}

/* 2. El nombre enlaza, pero no parece un enlace: en una rejilla, el subrayado
 *    azul en veinte tarjetas es ruido. Se comporta como enlace al pulsarlo. */
.prod-nom-link{color:inherit;text-decoration:none}
/* En tactil, el nombre es el segundo punto de entrada a la ficha -mucha gente
   pulsa el texto antes que la foto- y medía 33 px de alto. Se le da zona
   sensible sin tocar el texto: subirle la caja separaria el titulo del precio
   y descuadraria la tarjeta, que es justo lo que no se quiere en una rejilla
   de veinte. */
@media(hover:none){
  .prod-nom-link{position:relative;display:inline-block}
  .prod-nom-link::after{
    content:'';position:absolute;left:0;right:0;
    top:50%;transform:translateY(-50%);height:44px;
  }
}
.prod-nom-link:hover{color:var(--primary)}
.prod-nom-link:focus-visible{outline:none;box-shadow:var(--ring);border-radius:2px}

/* 3. El precio sube de jerarquía: es el dato que decide la compra y estaba al
 *    mismo peso que la referencia. */
.publico .prod-precio{font-size:var(--fs-2xl);color:var(--text)}

/* 4. El CTA cierra la tarjeta, pegado a su borde inferior: así se lee como
 *    parte del producto y no como un botón suelto debajo. */
.prod-cta{
  width:100%;margin-top:var(--sp-3);border-radius:0 0 var(--r-lg) var(--r-lg);
  min-height:44px;
}
.prod:has(.prod-cta){padding-bottom:0}
.prod:has(.prod-cta) .prod-cuerpo{padding-bottom:0}

/* 5. Tarjetas más anchas: con 236px entraban seis por fila y el producto se
 *    veía diminuto. A 260px entran cuatro o cinco según la pantalla, y cada
 *    uno tiene presencia real. */
.publico .rejilla-prod{
  /* 230 y no 260: con la barra lateral de filtros la rejilla dispone de unos
     1.090px en una pantalla de 1.440, y a 260 solo entraban TRES columnas de
     349px —mas anchas que antes de poner el lateral, justo lo contrario de lo
     que se buscaba—. A 230 entran cuatro de ~250px, y como la foto es cuadrada
     la tarjeta baja de 574px a poco mas de 480. */
  grid-template-columns:repeat(auto-fill,minmax(min(100%,230px),1fr));
}
/* En móvil, dos columnas fijas: `auto-fill` dejaba una sola y obligaba a
   desplazarse el doble para ver lo mismo. */
@media(max-width:620px){
  .publico .rejilla-prod{grid-template-columns:1fr 1fr;gap:var(--sp-3)}
  .publico .prod-nom{font-size:13px}
  .publico .prod-precio{font-size:var(--fs-lg)}
}

/* --- Rejilla o lista --------------------------------------------------
 *
 * POR QUE EXISTEN LAS DOS
 * Esto es una tienda mayorista. Quien descubre quiere ver el producto; quien
 * ya sabe lo que necesita quiere recorrer muchas referencias deprisa.
 *
 * UNA CORRECCION A LO QUE SE ESCRIBIO PRIMERO AQUI
 * Decia "en rejilla caben cuatro y en lista doce". Era falso y se comprobo
 * midiendo: la rejilla de cuatro columnas gasta 138 px por producto y la
 * primera version de esta lista gastaba 118. Un 15 %, no el triple. Una
 * rejilla de varias columnas ya es densa; la fila alta no lo era.
 *
 * Asi que la lista se apreto hasta ser lo que decia ser: miniatura de 52 px,
 * nombre en una linea y la fila entera por debajo de 80 px. Si no va a ser
 * mucho mas densa, no merece existir: dos formas de ver lo mismo que se
 * parecen solo añaden una decision que tomar.
 *
 * La foto cuadrada de la REJILLA no se toca: una llave o un grifo se
 * reconocen por la forma, y achatarla para ganar alto estropearia justo lo
 * que hace util esa vista.
 *
 * ES LA MISMA TARJETA
 * No hay un segundo componente: el mismo <article class="prod"> se recoloca.
 * En cuanto se duplica el molde, las dos vistas empiezan a decir cosas
 * distintas del mismo producto y el fallo solo aparece en una de ellas.
 */
.vista-sel{display:inline-flex;gap:2px;padding:var(--sp-1);flex:none;
  background:var(--surface-3);border:1px solid var(--border);border-radius:var(--r-sm)}
.vista-btn{
  display:inline-flex;align-items:center;gap:6px;
  min-height:34px;padding:0 var(--sp-3);
  background:transparent;border:0;border-radius:8px;cursor:pointer;
  font:inherit;font-size:13px;font-weight:600;color:var(--text-3);
  transition:background var(--t),color var(--t);
}
.vista-btn:hover{color:var(--text)}
.vista-btn[aria-pressed="true"]{background:var(--surface);color:var(--primary);
  box-shadow:var(--sh-1)}
.vista-btn:focus-visible{outline:none;box-shadow:var(--ring)}
/* En el telefono el conmutador se queda, pero solo con los iconos: dos
   etiquetas de texto al lado del recuento no caben en 390 px. */
@media(max-width:560px){
  .vista-btn span{position:absolute;width:1px;height:1px;overflow:hidden;
    clip-path:inset(50%);white-space:nowrap}
  .vista-btn{padding:0 var(--sp-2)}
}

.cat-cab-fila{display:flex;align-items:flex-start;gap:var(--sp-4);flex-wrap:wrap}

/* La lista: una sola columna de filas. */
.publico .rejilla-prod.es-lista{
  grid-template-columns:1fr;
  gap:var(--sp-2);
}
.rejilla-prod.es-lista .prod{
  display:grid;
  grid-template-columns:52px minmax(0,1fr);
  align-items:center;
  gap:var(--sp-3);
  padding:var(--sp-2) var(--sp-3);
}
/* La foto baja a una miniatura, pero sigue siendo cuadrada: cambiar tambien
   la proporcion dejaria el producto recortado de otra manera en cada vista. */
.rejilla-prod.es-lista .prod-img-caja,
.rejilla-prod.es-lista .prod-img-link{width:52px}

/* EL CORAZON, FUERA DE LA FOTO.
 *
 * En la rejilla el boton de guardar va flotando sobre una foto de 248 px y
 * ocupa una esquina. En lista la foto mide 44 px y el boton 36: medido, le
 * tapaba el 67 %. Aqui no se veia porque este entorno no tiene las
 * fotografias; con ellas puestas, el producto queda detras del corazon.
 *
 * Se saca a su propia columna. El boton es hijo de `.prod-img-caja` en el
 * HTML, asi que la caja pasa a ser la rejilla de dos columnas en vez de
 * tocar la estructura, que es compartida con la rejilla y el carrusel. */
@media(min-width:700px){
  .rejilla-prod.es-lista .prod{grid-template-columns:86px minmax(0,1fr)}
  /* Las pistas van en el orden del HTML: primero el enlace de la foto y
     despues el boton. Puestas al reves, la foto de 44 px se metia en una
     pista de 36 y volvia a solaparse, con menos aspaviento pero igual. */
  .rejilla-prod.es-lista .prod-img-caja{
    width:86px;display:grid;grid-template-columns:44px 36px;
    align-items:center;gap:6px;
  }
  .rejilla-prod.es-lista .prod-fav{
    position:static;inset:auto;width:36px;height:36px;
  }
  .rejilla-prod.es-lista .prod-img-link{width:44px}
}
/* El relleno de la foto esta pensado para una tarjeta grande; en 52 px deja
   el producto reducido a un sello. */
.publico .rejilla-prod.es-lista .prod-img img{padding:var(--sp-1)}
/* "Vista rapida" sobre una miniatura de 52 px no se puede ni pulsar. En
   lista, la fila entera lleva al producto por el nombre. */
.rejilla-prod.es-lista .prod-ojear{display:none}
.rejilla-prod.es-lista .publico .prod-img,
.publico .rejilla-prod.es-lista .prod-img{aspect-ratio:1/1;border-radius:var(--r-sm)}
/* La segunda foto al pasar el raton no tiene sentido en una miniatura. */
.rejilla-prod.es-lista .prod-img .prod-img-2{display:none}

.rejilla-prod.es-lista .prod-cuerpo{
  display:grid;
  /* La tercera pista tiene ANCHO FIJO y no `auto`.
     Con `auto` se encogia a cero en las filas sin boton -las agotadas-, el
     nombre se estiraba para rellenar y el bloque de precio se iba 170 px a la
     derecha. Resultado: los precios de las filas disponibles y los de las
     agotadas caian en dos verticales distintas, justo en una pantalla que
     sirve para comparar precios.
     Reservado, la columna existe aunque este vacia y todas las filas cuadran. */
  grid-template-columns:minmax(0,1fr) auto 178px;
  align-items:center;
  column-gap:var(--sp-4);
  padding:0;
}
/* La categoria se va: en una pagina de categoria TODAS las filas dirian lo
   mismo, y en el catalogo general ya esta el filtro lateral puesto. Era un
   renglon entero de texto repetido en cada fila. */
.rejilla-prod.es-lista .prod-linea{display:none}
/* Pero el aviso de pocas unidades no: ese si cambia de fila a fila. */
.rejilla-prod.es-lista .prod-linea:has(.badge-pocas){
  display:block;grid-area:1/1/2/2;margin:0}
.rejilla-prod.es-lista .prod-linea:has(.badge-pocas) span:not(.badge-pocas){display:none}
.rejilla-prod.es-lista .prod-nom{grid-area:1/1/3/2;margin:0;align-self:center}
.rejilla-prod.es-lista .prod-linea:has(.badge-pocas)~.prod-nom{grid-area:2/1/3/2}
/* El nombre cabe en una linea: en una fila ancha no hace falta recortarlo a
   dos, y asi todas las filas miden igual. */
.rejilla-prod.es-lista .prod-nom,
.rejilla-prod.es-lista .prod-nom-link{
  -webkit-line-clamp:1;line-clamp:1;
  display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden;
  /* Y el alto minimo tambien: `.prod-nom` reserva 2,7 em para que todas las
     tarjetas de la rejilla midan igual con nombres de una o dos lineas. Aqui
     el nombre va recortado a UNA linea, asi que ese minimo solo estaba
     metiendo 11 px de aire en cada fila -once por fila, en una pantalla
     pensada para recorrer quinientas-. */
  min-height:0;
}
/* `.publico` delante a proposito: mas abajo en este archivo hay un
   `.publico .prod-pie{flex-direction:column}` que gana por venir despues con
   la misma especificidad. Su motivo era que en una tarjeta de 258 px la
   referencia se quedaba sin sitio y desaparecia, y en ferreteria media
   clientela pide por referencia. Aqui la fila mide mas de mil pixeles: el
   motivo no se da, y en fila los tres datos se leen de un vistazo. */
/* EN COLUMNAS, NO EN FILA SUELTA.
 *
 * Esto era un `flex` y ahi estaba el fallo de la vista de lista. Cada fila
 * colocaba precio, estado y referencia pegados unos a otros, asi que su
 * posicion dependia de lo largo que fuera el texto de al lado: $130.789
 * caia en un sitio y $45.288 en otro, cuatro pixeles mas alla.
 *
 * Y comparar precios es EXACTAMENTE para lo que sirve una lista. Con 518
 * referencias de griferia delante, unas cifras que no caen en la misma
 * vertical no se pueden recorrer con la vista: hay que leerlas una por una,
 * que es lo que hace la rejilla y por eso existe la otra vista.
 *
 * Con pistas fijas cada dato tiene su columna y la coma decimal de todas las
 * filas queda alineada. El ancho esta puesto para el peor caso real del
 * catalogo -el precio mas largo y la referencia mas larga- y no al tanteo. */
.publico .rejilla-prod.es-lista .prod-pie{
  grid-area:1/2/3/3;
  display:grid;
  grid-template-columns:minmax(0,118px) minmax(0,104px) minmax(0,120px);
  align-items:center;
  column-gap:var(--sp-4);
  padding:0;border-top:0;margin-top:0;
}
/* El precio pegado a la derecha de SU columna: asi se alinean las unidades
   de mil aunque una cifra tenga un digito mas que la otra. */
.publico .rejilla-prod.es-lista .prod-precio{justify-self:end;text-align:right}
.publico .rejilla-prod.es-lista .prod-sin-precio{justify-self:end;text-align:right}
/* El hueco del estado se reserva aunque la fila no lleve etiqueta: si se
   encogiera, las referencias de las filas disponibles quedarian desplazadas
   respecto a las agotadas y volveria el problema por otro lado. */
.publico .rejilla-prod.es-lista .prod-estado{justify-self:start;min-height:1px}
.publico .rejilla-prod.es-lista .prod-ref{justify-self:start}

/* Mas filas por pantalla. La vista de lista existe para recorrer mucho
   catalogo, y medida contra la rejilla entraban SIETE frente a ocho: hacia
   peor su propio trabajo. La miniatura baja de 52 a 44 px y la fila pierde
   el relleno que no estaba separando nada. */
@media(min-width:700px){
  .rejilla-prod.es-lista .prod{padding:var(--sp-2) var(--sp-3);gap:var(--sp-3)}
  .rejilla-prod.es-lista .prod-img-caja,
  .rejilla-prod.es-lista .prod-img-link{width:44px}
  .rejilla-prod.es-lista .prod-nom{font-size:13.5px}
  .publico .rejilla-prod.es-lista{gap:6px}
}
/* La marca sobre una miniatura de 84 px tapa el producto y no se lee. En
   lista se oculta: la marca esta en el filtro lateral y en la ficha, asi que
   no se pierde: deja de estorbar donde no cabe. */
.rejilla-prod.es-lista .prod-marca{display:none}
.rejilla-prod.es-lista .prod-precio{padding:0;white-space:nowrap}
.rejilla-prod.es-lista .prod-ref{white-space:nowrap}
.rejilla-prod.es-lista .prod-cta{
  grid-area:1/3/3/4;
  width:auto;margin:0;padding:0 var(--sp-4);border-radius:var(--r-sm);
  white-space:nowrap;
  /* 40 px y no 44: la fila entera mide menos que eso en una lista densa, y el
     boton no puede ser mas alto que lo que lo contiene. Sigue por encima del
     minimo comodo para el dedo porque la fila le deja su zona alrededor. */
  min-height:40px;
}
/* El relleno inferior extra de las filas con boton se retira.
   Venia de cuando el CTA se apilaba debajo del nombre y necesitaba aire por
   abajo. Ahora el boton tiene su propia columna, asi que ese relleno solo
   hacia dos cosas: dejar la fila descentrada -8 px arriba, 20 abajo- y que
   las filas con boton midieran distinto de las agotadas. */
.rejilla-prod.es-lista .prod:has(.prod-cta) .prod-cuerpo{padding-bottom:0}

/* En el telefono la fila no da para cuatro columnas: el precio y el boton
   bajan debajo del nombre, y la miniatura se queda al lado. */
@media(max-width:620px){
  .publico .rejilla-prod.es-lista{grid-template-columns:1fr}
  /* El corazon, al lado de la foto y no encima. Medido en el telefono,
     flotando sobre la miniatura le tapaba el 32 %: en un catalogo donde
     veinte accesorios cromados se parecen entre si, un tercio de la foto es
     justo lo que hace falta para distinguirlos.
     Cabe porque el nombre ya no comparte fila con nada. */
  .rejilla-prod.es-lista .prod{grid-template-columns:84px minmax(0,1fr);gap:var(--sp-3)}
  .rejilla-prod.es-lista .prod-img-caja{
    width:84px;display:grid;grid-template-columns:48px 32px;
    align-items:center;gap:4px;
  }
  .rejilla-prod.es-lista .prod-img-link{width:48px}
  .rejilla-prod.es-lista .prod-fav{position:static;inset:auto;width:32px;height:32px}
  /* EL NOMBRE OCUPA SU PROPIA FILA.
     Antes compartia fila con el boton: el boton mide 170 px fijos, la fila
     util 264, y al nombre le quedaban 78. En pantalla se leia "ACCESOR..." y
     ocho caracteres no distinguen una referencia de otra en un catalogo
     donde veinte productos empiezan por "ACCESORIO PARA BANO".
     Ahora el nombre cruza las dos columnas y debajo van, en la misma linea,
     el precio a la izquierda y el boton a la derecha. */
  .rejilla-prod.es-lista .prod-cuerpo{
    grid-template-columns:minmax(0,1fr) auto;row-gap:var(--sp-2);
  }
  .rejilla-prod.es-lista .prod-nom,
  .rejilla-prod.es-lista .prod-linea:has(.badge-pocas)~.prod-nom{
    grid-area:2/1/3/3;
  }
  /* Y en movil si cabe en dos lineas: una fila de lista en un telefono es
     ancha pero corta, y recortar a una linea era lo que obligaba a elegir
     entre nombre y boton. */
  .rejilla-prod.es-lista .prod-nom,
  .rejilla-prod.es-lista .prod-nom-link{-webkit-line-clamp:2;line-clamp:2}
  .rejilla-prod.es-lista .prod-linea:has(.badge-pocas){grid-area:1/1/2/3}
  /* Las tres columnas fijas de escritorio se deshacen aqui: 118+104+120 mas
     separaciones no caben en un telefono junto a la miniatura, y la fila
     desbordaria. En movil el precio va solo y a la izquierda, que es como se
     lee de arriba abajo. Lleva `.publico` porque la regla de escritorio
     tambien lo lleva y si no, ganaria ella por especificidad. */
  /* El precio y la referencia, uno debajo del otro.
     En fila no cabian: la columna del nombre mide 264 px, el boton se lleva
     170 fijos y el bloque precio+referencia desbordaba su columna, asi que
     el boton acababa pintado ENCIMA de la referencia. En ferreteria la
     referencia es con lo que se pide, de modo que taparla no es un detalle
     estetico. `min-width:0` es lo que permite que la columna encoja en vez
     de empujar: sin el, una rejilla no deja que su contenido se estreche. */
  .publico .rejilla-prod.es-lista .prod-pie{
    grid-area:3/1/4/2;
    display:flex;flex-direction:column;align-items:flex-start;
    justify-content:center;gap:2px;min-width:0;
    grid-template-columns:none;
  }
  .publico .rejilla-prod.es-lista .prod-precio,
  .publico .rejilla-prod.es-lista .prod-sin-precio{justify-self:start;text-align:left}
  /* 44 px y no 40: en tactil es el minimo para pulsar sin fallar, y aqui el
     boton ya no compite con el nombre por el ancho. */
  .rejilla-prod.es-lista .prod-cta{grid-area:3/2/4/3;min-height:44px}
  /* Solo en la LISTA se acorta el texto. En la rejilla la tarjeta tiene el
     ancho entero para el boton y no hace falta. */
  .rejilla-prod.es-lista .prod-cta-largo{display:none}
  .rejilla-prod.es-lista .prod-estado{display:none}
}

/* --- Cabecera de tienda ----------------------------------------------- */

/* Tres zonas: marca, buscador, acciones. El buscador se lleva el espacio
   sobrante porque es la vía principal para llegar a un producto. */
.hdr-publico.con-buscador .hdr-publico-in{
  display:flex;align-items:center;gap:var(--sp-4);
}
.hdr-buscador{flex:1 1 auto;max-width:560px;min-width:0}
.hdr-buscador .buscador{margin:0}
.hdr-buscador .inp{font-size:15px}

/* En móvil el buscador baja a su propia línea y ocupa todo el ancho: comprimido
   entre el logo y el carrito no cabría ni el texto del placeholder. */
@media(max-width:860px){
  .hdr-publico.con-buscador .hdr-publico-in{flex-wrap:wrap;row-gap:var(--sp-2)}
  .hdr-buscador{order:3;flex:1 0 100%;max-width:none}
}

/* --- Filtros secundarios ---------------------------------------------- */

/* Sin tarjeta ni borde: los filtros dejaron de ser un bloque con el mismo peso
   visual que los productos. Ahora se leen como una barra de ajuste. */
.barra-filtros{
  display:flex;flex-wrap:wrap;align-items:flex-end;gap:var(--sp-3);
  padding-bottom:var(--sp-3);border-bottom:1px solid var(--border-2);
}
.barra-filtros .filtros-fila{flex:1 1 auto;margin:0}
@media(max-width:699px){
  .barra-filtros{padding-bottom:var(--sp-2)}
}

/* --- Mini carrito: confirmación de "agregado" -------------------------- */

.mini-cart{position:fixed;inset:0;z-index:200;display:flex;justify-content:flex-end}
.mini-cart-velo{
  position:absolute;inset:0;background:rgba(10,45,80,.28);
  opacity:0;transition:opacity .18s ease;
}
.mini-cart.abierta .mini-cart-velo{opacity:1}

.mini-cart-panel{
  position:relative;width:min(380px,100%);background:var(--surface);
  box-shadow:var(--elev-3);display:flex;flex-direction:column;gap:var(--sp-3);
  padding:var(--sp-4);
  /* Entra desde el borde: el movimiento dice de dónde viene y hacia dónde se
     va al cerrarla. */
  transform:translateX(100%);transition:transform .2s ease;
}
.mini-cart.abierta .mini-cart-panel{transform:none}

.mini-cart-cab{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-2)}
.mini-cart-ok{
  display:flex;align-items:center;gap:var(--sp-2);
  color:var(--success);font-weight:650;font-size:var(--fs-sm);
}

.mini-cart-prod{display:flex;gap:var(--sp-3);align-items:flex-start}
.mini-cart-img{
  width:72px;height:72px;flex:none;border-radius:var(--r-sm);
  background:var(--surface-2);border:1px solid var(--border-2);
  display:grid;place-items:center;overflow:hidden;color:var(--text-3);
}
.mini-cart-img img{width:100%;height:100%;object-fit:contain;padding:var(--sp-2)}
.mini-cart-nom{
  font-weight:650;font-size:var(--fs-sm);line-height:1.35;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
}
.mini-cart-precio{
  font-family:var(--f-display);font-weight:700;font-size:var(--fs-lg);
  color:var(--text);margin-top:4px;
}

.mini-cart-resumen{
  display:flex;align-items:baseline;justify-content:space-between;gap:var(--sp-2);
  padding-top:var(--sp-3);border-top:1px solid var(--border-2);
  font-size:var(--fs-sm);color:var(--text-2);
}
.mini-cart-resumen strong{font-family:var(--f-display);font-size:var(--fs-lg);color:var(--text)}

.mini-cart-acciones{display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-2)}
.mini-cart-acciones .btn{min-height:46px}

/* En móvil sube desde abajo y no ocupa toda la altura: así se sigue viendo el
   producto que acaba de agregar y la confirmación no tapa el catálogo. */
@media(max-width:620px){
  .mini-cart{align-items:flex-end;justify-content:stretch}
  .mini-cart-panel{
    width:100%;border-radius:var(--r-lg) var(--r-lg) 0 0;
    transform:translateY(100%);
    padding-bottom:calc(var(--sp-4) + env(safe-area-inset-bottom,0px));
  }
  .mini-cart.abierta .mini-cart-panel{transform:none}
}

/* Quien prefiere menos movimiento recibe la hoja sin desplazamiento. */
@media(prefers-reduced-motion:reduce){
  .mini-cart-panel{transition:none;transform:none}
  .mini-cart-velo{transition:none}
}

/* --- Sugerencias de búsqueda ------------------------------------------ */

.buscador.con-sug{position:relative}

.sug{
  position:absolute;z-index:120;top:calc(100% + 6px);left:0;right:0;
  background:var(--surface);border:1px solid var(--border);
  border-radius:var(--r-sm);box-shadow:var(--elev-3);
  max-height:min(70vh,460px);overflow-y:auto;-webkit-overflow-scrolling:touch;
  padding:var(--sp-1) 0;
}

.sug-titulo{
  /* Agrupa por tipo: sin la etiqueta, una marca y un producto se leen igual y
     el usuario no sabe a dónde le lleva cada fila. */
  padding:var(--sp-2) var(--sp-3) var(--sp-1);
  font-size:var(--fs-caption);font-weight:700;letter-spacing:.06em;
  text-transform:uppercase;color:var(--text-3);
}

.sug-item{
  display:flex;align-items:center;gap:var(--sp-2);width:100%;
  min-height:44px;padding:var(--sp-2) var(--sp-3);
  background:transparent;border:0;cursor:pointer;text-align:left;
  font-size:var(--fs-sm);color:var(--text);
  transition:background var(--t);
}
.sug-item:hover,.sug-item.on{background:var(--primary-soft)}
.sug-item:focus-visible{outline:none;background:var(--primary-soft);box-shadow:var(--ring)}

.sug-img{
  width:40px;height:40px;flex:none;border-radius:var(--r-sm);
  background:var(--surface-2);border:1px solid var(--border-2);
  display:grid;place-items:center;overflow:hidden;color:var(--text-3);
}
.sug-img img{width:100%;height:100%;object-fit:contain;padding:var(--sp-1)}

.sug-prod .crecer{display:flex;flex-direction:column;gap:2px}
.sug-nom{
  font-weight:600;line-height:1.3;
  display:-webkit-box;-webkit-line-clamp:1;-webkit-box-orient:vertical;overflow:hidden;
}
.sug-sku{font-size:11.5px;color:var(--text-3)}
.sug-precio{
  font-family:var(--f-display);font-weight:700;color:var(--text);flex:none;
  font-variant-numeric:tabular-nums;
}
.sug-n{font-family:var(--f-mono);font-size:11.5px;color:var(--text-3);flex:none}
.sug-vacio{padding:var(--sp-4) var(--sp-3);margin:0;color:var(--text-3);font-size:var(--fs-sm)}

/* En móvil ocupa el ancho de la pantalla y deja sitio al teclado. */
@media(max-width:620px){
  .sug{max-height:52vh}
  .sug-item{min-height:48px}
}

/* --- Migas de navegación ---------------------------------------------- */

.migas{
  display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp-2);
  font-size:var(--fs-sm);color:var(--text-3);
}
.migas a{color:var(--text-2);text-decoration:none}
.migas a:hover{color:var(--primary);text-decoration:underline}
.migas a:focus-visible{outline:none;box-shadow:var(--ring);border-radius:2px}
/* El producto actual no es enlace y se recorta: un nombre largo no puede
   empujar las migas a tres líneas. */
.migas [aria-current]{
  color:var(--text);font-weight:600;
  max-width:min(100%,460px);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
@media(max-width:620px){
  .migas{font-size:var(--fs-caption)}
  .migas [aria-current]{max-width:100%}
}

/* --- Vista rápida ------------------------------------------------------ */

.prod-img-caja{position:relative}

.prod-ojear{
  position:absolute;left:50%;bottom:var(--sp-3);transform:translateX(-50%);
  display:flex;align-items:center;gap:var(--sp-1);
  min-height:36px;padding:0 var(--sp-3);border-radius:999px;
  background:var(--surface);border:1px solid var(--border);
  box-shadow:var(--elev-2);color:var(--text-2);
  font-size:var(--fs-caption);font-weight:600;cursor:pointer;white-space:nowrap;
  /* Oculto hasta que el ratón se acerca: en una rejilla de veinte tarjetas,
     veinte botones permanentes compiten con el producto. */
  opacity:0;transition:opacity var(--t),color var(--t);
}
.prod:hover .prod-ojear{opacity:1}
.prod-ojear:hover{color:var(--primary);border-color:var(--primary-light)}
/* Con teclado no hay hover: sin esto el control sería inalcanzable. */
.prod-ojear:focus-visible{opacity:1;outline:none;box-shadow:var(--ring)}

/* En táctil no existe el hover, así que se queda visible. */
@media(hover:none){
  .prod-ojear{opacity:1;min-height:32px;font-size:11.5px}
}

.vr{display:grid;grid-template-columns:240px 1fr;gap:var(--sp-4)}
.vr-img{
  aspect-ratio:1/1;background:var(--surface-2);border:1px solid var(--border-2);
  border-radius:var(--r);display:grid;place-items:center;overflow:hidden;color:var(--text-3);
}
.vr-img img{width:100%;height:100%;object-fit:contain;padding:var(--sp-3)}
.vr-datos{display:flex;flex-direction:column;min-width:0}
.vr-marca{
  align-self:flex-start;font-size:11px;font-weight:700;letter-spacing:.04em;
  text-transform:uppercase;color:var(--text-3);margin-bottom:var(--sp-1);
}
.vr-nom{
  font-family:var(--f-display);font-size:var(--fs-lg);font-weight:700;
  line-height:1.3;margin:0 0 4px;
}
.vr-precio{
  font-family:var(--f-display);font-size:var(--fs-2xl);font-weight:750;
  color:var(--text);margin-top:var(--sp-3);font-variant-numeric:tabular-nums;
}
.vr-detalle{
  display:inline-flex;align-items:center;gap:6px;margin-top:auto;
  color:var(--primary);font-size:var(--fs-sm);font-weight:600;text-decoration:none;
}
.vr-detalle:hover{text-decoration:underline}

/* En móvil la imagen va arriba y más baja: a 240px de ancho sobraría altura. */
@media(max-width:620px){
  .vr{grid-template-columns:1fr;gap:var(--sp-3)}
  .vr-img{aspect-ratio:4/3}
}


/* --- Hero: altura contenida -------------------------------------------
 *
 * Medido con un navegador real: el primer producto quedaba a 1,2 pantallas en
 * escritorio y a 2,0 en móvil. Un hero que obliga a bajar dos pantallas para
 * ver mercancía no está presentando la tienda: la está tapando.
 */
@media(max-width:640px){
  /* Las tres cifras en una sola fila: apiladas sumaban otra línea completa. */
  .hero-datos{gap:var(--sp-4);margin-top:var(--sp-4)}
  .hero-datos > div{flex:1 1 0;min-width:0}
  .hero-contenido{padding:var(--sp-5) var(--sp-4)}
  .hero h1{margin-bottom:var(--sp-2)}
  /* El párrafo de presentación se recorta a dos líneas: en un teléfono, cuatro
     líneas de texto introductorio valen menos que ver un producto. */
  .hero p{
    display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;
    overflow:hidden;font-size:var(--fs-sm);
  }
}

/* --- Móvil: llegar antes a los productos -------------------------------
 *
 * Medido con un navegador: en un teléfono había 377px de hero + 250 de franja
 * + 444 de categorías antes del primer producto — 1,8 pantallas de scroll para
 * ver mercancía en una tienda.
 */
@media(max-width:640px){
  /* La franja de confianza en dos columnas: cuatro mensajes apilados ocupaban
     250px para decir lo que cabe en la mitad. */
  .franja-in{
    display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-3) var(--sp-4);
  }
  .franja-in > *{min-width:0}
  /* El subtexto SE CONSERVA. Lo oculté y, al verlo en un navegador, resultó
     que aporta: "Pedidos menores: $20.000" le dice al comprador cuándo paga
     envío, y en dos columnas se lee sin apretarse. El espacio ya se ganó al
     pasar de cuatro filas a dos. */
  .franja-item strong{font-size:var(--fs-sm);line-height:1.3}

  /* Categorías deslizables en horizontal, como en cualquier tienda: cinco
     tarjetas apiladas eran 444px; en una fila son 150 y se recorren con el
     pulgar. */
  .cat-mosaico{
    display:flex;gap:var(--sp-2);overflow-x:auto;-webkit-overflow-scrolling:touch;
    scroll-snap-type:x proximity;
    /* El margen negativo deja que la fila llegue al borde de la pantalla: una
       tarjeta cortada a la derecha es la señal de que hay más. */
    margin-inline:calc(var(--sp-4) * -1);padding-inline:var(--sp-4);
    padding-bottom:var(--sp-2);
  }
  .cat-mosaico::-webkit-scrollbar{display:none}
  .cat-item{
    flex:0 0 132px;scroll-snap-align:start;
  }
}

/* ===================================================================
   CATALOGO EN DOS COLUMNAS
   ===================================================================
   Los filtros a un lado y los productos al otro. El motivo no es la moda:
   con los filtros en una fila sobre la rejilla, la rejilla se quedaba con
   los 1.400px enteros y repartia ese ancho entre cuatro tarjetas de 328px,
   con fotos cuadradas de 326px de alto. Cada tarjeta medía 553px: en una
   pantalla de 900px no entraba ni fila y media de productos.

   Quitandole 280px a la rejilla, la tarjeta baja a ~285px y la pagina
   enseña mas mercancia sin encoger ni una letra. Y el filtro deja de ser
   algo que se abre: esta siempre ahi, al lado de lo que filtra. */

.cat-layout{display:grid;gap:var(--sp-5)}

/* Movil: una sola columna y los filtros arriba, sin pegarse a nada —una
   barra fija en un telefono se come la pantalla que queremos llenar. */
.cat-lateral-caja{
  display:flex;flex-direction:column;gap:var(--sp-4);
  background:var(--surface);border:1px solid var(--border);
  border-radius:var(--r-lg);padding:var(--sp-4);
}
/* El titulo del panel ES el boton que lo pliega. En escritorio no se pliega
   nada y se comporta como el titulo de antes: sin borde, sin fondo y sin
   cursor de boton. */
.cat-lateral-tit{
  font-size:var(--fs-sm);font-weight:700;color:var(--text);margin:0;
  text-transform:uppercase;letter-spacing:.6px;
  display:flex;align-items:center;gap:var(--sp-2);width:100%;
  background:none;border:0;padding:0;text-align:left;font-family:inherit;
}
.cat-filtros-cuerpo{display:flex;flex-direction:column;gap:var(--sp-4)}
/* Cuantos filtros hay puestos. Solo sale si hay alguno. */
.cat-filtros-n{display:none}
.cat-filtros-n.hay{
  display:inline-grid;place-items:center;min-width:19px;height:19px;padding:0 5px;
  background:var(--primary);color:#fff;border-radius:var(--r-full);
  font-size:11px;font-weight:700;letter-spacing:0;
}

/* --- Telefono: el panel nace plegado --------------------------------- */
@media(max-width:899px){
  .cat-lateral-tit{
    cursor:pointer;min-height:44px;padding:0 var(--sp-1);
  }
  /* La flecha gira al abrir: dice en que estado esta sin leer nada. */
  .cat-lateral-tit svg{margin-left:auto;transition:transform var(--t-2,.18s) ease}
  .cat-lateral.abierto .cat-lateral-tit svg{transform:rotate(180deg)}
  .cat-lateral:not(.abierto) .cat-filtros-cuerpo{display:none}
  /* Sin el panel desplegado la caja es solo el boton: se le quita el aire
     de arriba y abajo para que no parezca una tarjeta vacia. */
  .cat-lateral:not(.abierto) .cat-lateral-caja{padding:var(--sp-2) var(--sp-3)}
  .cat-lateral-caja{gap:var(--sp-3)}
}

@media(min-width:900px){
  .cat-layout{grid-template-columns:260px minmax(0,1fr);align-items:start}
  /* `top` deja sitio a la cabecera fija; sin esto el titulo del filtro
     queda debajo del buscador y no se lee. */
  .cat-lateral-caja{position:sticky;top:96px}
  /* En escritorio no hay nada que plegar: la flecha sobra y el cuerpo va
     siempre visible, pase lo que pase con la clase `abierto`. */
  .cat-lateral-tit svg{display:none}
  .cat-lateral .cat-filtros-cuerpo{display:flex}
}

/* --- Cabecera de resultados --- */
.cat-cab{margin-bottom:var(--sp-4)}
.cat-tit{
  font-family:var(--f-display);
  font-size:var(--fs-2xl);font-weight:700;color:var(--text);
  letter-spacing:-.6px;line-height:1.15;margin:0 0 2px;
}
/* El recuento era una linea gris de 13px perdida sobre la rejilla. Ahora
   es el subtitulo del titulo, que es su papel. */
.cat-cab .muted{font-size:var(--fs-sm);margin:0}

/* --- Fichas de filtros puestos --- */
.cat-chips{display:flex;flex-wrap:wrap;gap:6px;margin-top:var(--sp-3)}
.cat-chip{
  display:inline-flex;align-items:center;gap:6px;
  /* 32px de alto: por debajo de los 44 recomendados, pero es un control
     secundario y agrandarlo partiria la fila en dos en el telefono. */
  min-height:32px;padding:0 10px;
  background:var(--primary-soft);color:var(--primary-dark);
  border:1px solid var(--primary-light);border-radius:999px;
  font-size:var(--fs-caption);font-weight:600;cursor:pointer;
}
.cat-chip:hover{background:var(--primary-light);color:#fff}
.cat-chip:focus-visible{outline:none;box-shadow:var(--ring)}

/* --- Marcas como filtro, en la barra lateral --- */
.cat-marcas-lista{display:flex;flex-direction:column;gap:2px;margin-top:4px}
.cat-marca-item{
  display:flex;align-items:center;gap:8px;width:100%;
  min-height:38px;padding:0 10px;
  background:transparent;border:0;border-radius:var(--r-sm);
  font-size:var(--fs-sm);color:var(--text-2);text-align:left;cursor:pointer;
}
.cat-marca-item:hover{background:var(--surface-2);color:var(--text)}
.cat-marca-item.on{background:var(--primary-soft);color:var(--primary-dark);font-weight:650}
.cat-marca-item:focus-visible{outline:none;box-shadow:var(--ring)}
.cat-marca-n{font-size:var(--fs-caption);color:var(--text-3);font-variant-numeric:tabular-nums}
.cat-marca-item.on .cat-marca-n{color:inherit}

/* El pie de la tarjeta, en columna y no en fila.
   Venia de `.prod-pie{display:flex}` pensado para tarjetas anchas: precio,
   disponibilidad y referencia cabian uno al lado del otro. Al estrechar la
   tarjeta a 258px para que entraran cuatro columnas, la referencia se quedo
   sin sitio y DESAPARECIO de la tarjeta. En ferreteria mayorista eso no es un
   detalle: media clientela pide por referencia, no por nombre. */
/* En rejilla pasa de columna flexible a tres renglones FIJOS: precio,
   existencia y referencia. El del medio reserva su alto aunque no lleve
   etiqueta.
   Hace falta desde que "Disponible" dejo de pintarse: salia en el 87 % de
   las tarjetas, no informaba de nada y le restaba fuerza al "Agotado", que
   es el 12,6 % y es lo que hay que ver. Pero al quitarla, las tarjetas con
   etiqueta y las que no median distinto y sus precios caian a alturas
   diferentes dentro de la misma fila. Con los renglones fijos todas las
   tarjetas de una fila alinean precio, existencia y referencia, lleven
   etiqueta o no. */
   `:not(.es-lista)` NO es adorno: sin el, estos renglones fijos se cuelan en
   la vista de lista -que define sus propias columnas mas arriba en este
   archivo pero no sus renglones- y cada fila crece 20 px. Medido: de 62 px
   por fila a 82, de nueve filas por pantalla a siete. */
   DOS renglones, no tres. El primer intento reservaba un renglon para la
   etiqueta y no cuadraba: el pie vive dentro de una caja flexible que le da
   64 px, y tres renglones piden 108. En vez de pelearse con eso, la etiqueta
   comparte renglon con la referencia. Asi el NUMERO de renglones no depende
   de que haya etiqueta, que era la causa de que el precio de una tarjeta
   cayera 44 px por debajo del de sus vecinas. */
.publico .rejilla-prod:not(.es-lista) .prod-pie{
  display:grid;
  grid-template-columns:auto minmax(0,1fr);
  grid-template-areas:"precio precio" "estado ref";
  align-items:center;justify-items:start;
  column-gap:7px;row-gap:4px;
}
.publico .rejilla-prod:not(.es-lista) .prod-precio{grid-area:precio}
.publico .rejilla-prod:not(.es-lista) .prod-estado{grid-area:estado}
.publico .rejilla-prod:not(.es-lista) .prod-ref{grid-area:ref}

/* Hueco del boton en las tarjetas agotadas.
   Un producto sin existencia no lleva "Agregar al carrito", y sin el la
   tarjeta reparte su alto de otra manera: medido, el precio de las agotadas
   caia 44 px -justo el alto del boton- por debajo del de sus vecinas de
   fila. Reservar el sitio deja las cuatro tarjetas de una fila con el precio
   a la misma altura, que es lo que permite compararlas de un vistazo. */
.publico .rejilla-prod:not(.es-lista) .prod:not(:has(.prod-cta))::after{
  content:"";display:block;height:44px;flex:0 0 auto;
}
.publico .prod-estado{margin-top:0;display:flex;align-items:center}
.publico .prod-ref{
  margin-top:0;
  /* Sin recorte: una referencia a medias ("ART000…") no sirve para pedirla. */
  white-space:normal;overflow:visible;text-overflow:clip;
  font-variant-numeric:tabular-nums;
}

/* ===================================================================
   VISTA ISOMETRICA DE BODEGA
   ===================================================================
   El volumen lo dibuja el SVG con tres caras de distinta luz; aqui solo
   van el encuadre, el texto y los estados. */

.iso-svg{
  width:100%;height:auto;display:block;
  /* Alto maximo para que la nave entera quepa sin desplazarse: el sentido de
     esta vista es ver el conjunto de un vistazo. */
  max-height:72vh;
}

.iso-el{transition:filter .12s ease}
.iso-el:hover{filter:brightness(1.06)}
.iso-el:focus-visible{outline:none;filter:brightness(1.12) drop-shadow(0 0 0 var(--primary))}
.iso-el.elegido{filter:drop-shadow(0 2px 6px rgba(0,0,0,.25))}

/* Las etiquetas van en su propia capa por encima de los volumenes, asi que
   necesitan leerse sobre cualquier color de cara. El trazo del mismo tono que
   el fondo las separa sin recuadrarlas. */
.iso-txt{
  font-family:var(--f-mono);font-size:11px;font-weight:700;
  fill:#fff;paint-order:stroke;
  stroke:rgba(0,0,0,.45);stroke-width:2.5px;stroke-linejoin:round;
  pointer-events:none;user-select:none;
}

.iso-vacio{
  display:grid;place-items:center;min-height:40vh;
  border:1px dashed var(--border-strong);border-radius:var(--r-lg);
}

/* Conmutador planta / perspectiva. */
.iso-switch{display:inline-flex;gap:4px}

@media(max-width:620px){
  .iso-svg{max-height:60vh}
  .iso-txt{font-size:10px}
}

/* ===================================================================
   ETIQUETAS DE UBICACION
   ===================================================================
   Pensadas para imprimirse y pegarse en la balda, asi que mandan los
   milimetros, no los pixeles: una etiqueta de 62x32 mm entra en las
   impresoras de etiquetas y tambien en una hoja A4 cortada a mano. */

.etq-lista{
  display:grid;gap:2px;max-height:38vh;overflow-y:auto;
  border:1px solid var(--border);border-radius:var(--r-md);padding:var(--sp-2);
}
.etq-fila{
  display:flex;align-items:center;gap:10px;
  min-height:38px;padding:0 8px;border-radius:var(--r-sm);cursor:pointer;
}
.etq-fila:hover{background:var(--surface-2)}
.etq-fila code{font-size:12.5px}

.etq-hoja{
  display:grid;gap:4mm;
  grid-template-columns:repeat(auto-fill,minmax(62mm,1fr));
}

.etq{
  display:flex;align-items:center;gap:3mm;
  width:62mm;min-height:32mm;padding:2.5mm;
  /* Fondo blanco y borde fino SIEMPRE, tambien en modo oscuro: la etiqueta se
     imprime en papel, y un QR claro sobre fondo oscuro no lo lee nadie. */
  background:#fff;border:1px solid #bbb;border-radius:1.5mm;
  color:#000;
  break-inside:avoid;page-break-inside:avoid;
}
.etq-qr{flex:0 0 auto;line-height:0}
.etq-cuerpo{min-width:0;display:flex;flex-direction:column;gap:1mm}
.etq-codigo{
  font-family:var(--f-mono);font-size:10.5pt;font-weight:700;
  letter-spacing:-.2px;line-height:1.15;word-break:break-all;color:#000;
}
.etq-donde{font-size:7pt;color:#444;line-height:1.3}
.etq-pie{font-size:6pt;color:#777;margin-top:auto}

@media print{
  /* Al imprimir solo salen las etiquetas: ni menu, ni filtros, ni botones.
     Sin esto se gastan dos hojas en la interfaz antes de la primera etiqueta. */
  .no-print, header, nav, .plano-zoom, .toast-zona{display:none !important}
  body{background:#fff}
  .vista{padding:0;margin:0}
  .etq-hoja{gap:3mm}
  .etq{border:1px dashed #999}
  @page{margin:8mm}
}

/* ===================================================================
   CONSULTA POR ESCANEO (pantalla de telefono)
   ===================================================================
   Se usa de pie en un pasillo, con una mano y a veces con guantes: todo
   lo pulsable pasa de 48px y las cifras se leen a un brazo de distancia. */

.esc .campo .inp{min-height:52px}

.esc-camara{
  margin-top:var(--sp-3);position:relative;
  border-radius:var(--r-lg);overflow:hidden;background:#000;
}
.esc-video{width:100%;max-height:48vh;object-fit:cover;display:block}

/* Marco guia: sin el, nadie sabe a que distancia poner la etiqueta. */
.esc-mira{
  position:absolute;inset:18% 22%;
  border:2px solid rgba(255,255,255,.9);border-radius:var(--r-md);
  box-shadow:0 0 0 100vmax rgba(0,0,0,.28);
  pointer-events:none;
}

.esc-ficha{margin-top:var(--sp-3)}
.esc-codigo{
  font-family:var(--f-mono);font-size:var(--fs-xl);font-weight:700;
  word-break:break-all;line-height:1.2;margin:0 0 2px;
}
.esc-nombre{font-size:var(--fs-lg);line-height:1.25;margin:0 0 2px}
.esc-donde{font-size:var(--fs-sm);color:var(--text-2);margin-bottom:var(--sp-3)}

.esc-cifras{display:flex;gap:var(--sp-5);margin-bottom:var(--sp-3)}
.esc-cifras strong{display:block;font-size:var(--fs-2xl);line-height:1;font-family:var(--f-display)}
.esc-cifras span{font-size:var(--fs-caption);color:var(--text-3)}

.esc-items{display:flex;flex-direction:column;gap:2px}
.esc-item{
  display:flex;align-items:center;gap:var(--sp-3);
  min-height:52px;padding:0 var(--sp-3);
  border-radius:var(--r-sm);background:var(--surface-2);
}
.esc-item-nom{font-size:var(--fs-sm);font-weight:600;line-height:1.25}
/* La cantidad es el dato que se viene a mirar: se lee sin acercarse. */
.esc-cant{
  font-family:var(--f-display);font-size:var(--fs-xl);font-weight:700;
  font-variant-numeric:tabular-nums;
}
.esc-opcion{
  display:flex;width:100%;min-height:52px;gap:var(--sp-3);
  justify-content:flex-start;text-align:left;margin-bottom:4px;
}

/* Pasos de las operaciones guiadas desde el telefono. */
.esc-paso{
  display:flex;align-items:center;gap:var(--sp-3);
  min-height:52px;padding:var(--sp-2) var(--sp-3);margin-bottom:6px;
  background:var(--surface-2);border-radius:var(--r-md);
}
.esc-paso-val{font-size:var(--fs-sm);font-weight:650;line-height:1.25;word-break:break-all}

/* ===================================================================
   Panel de capas del plano de bodega.

   Es una columna fija junto al dibujo, no un panel flotante: flotando
   taparia justo la parte del plano sobre la que se esta trabajando.
   Por debajo de 1100 px la rejilla colapsa y el panel pasa a ir encima
   del mapa con altura limitada, porque las dos cosas no caben al lado
   en una tableta en vertical ni en un telefono.
   =================================================================== */
.plano-area{display:block}
@media(min-width:1100px){
  .plano-area.con-panel{
    display:grid;grid-template-columns:280px minmax(0,1fr);
    gap:var(--sp-3);align-items:start;
  }
}
.cap-panel{
  display:flex;flex-direction:column;min-width:0;
  background:var(--surface-1);border:1px solid var(--border);
  border-radius:var(--r-lg);overflow:hidden;margin-bottom:var(--sp-3);
}
@media(min-width:1100px){
  .cap-panel{margin-bottom:0;position:sticky;top:var(--sp-3)}
}
.cap-cab{
  display:flex;align-items:baseline;justify-content:space-between;gap:var(--sp-2);
  padding:var(--sp-3) var(--sp-3) var(--sp-2);border-bottom:1px solid var(--border);
}
.cap-resumen{display:flex;gap:4px;font-size:11.5px;color:var(--text-3);white-space:nowrap}
.cap-punto{opacity:.5}
.cap-buscador{position:relative;display:flex;align-items:center;padding:var(--sp-2) var(--sp-2) 0}
.cap-buscador svg{position:absolute;left:calc(var(--sp-2) + 9px);color:var(--text-3);pointer-events:none}
.cap-buscar{padding-left:32px;font-size:13px;min-height:38px}
.cap-lista{overflow:auto;max-height:46vh;padding:var(--sp-2) 0 var(--sp-2)}
@media(min-width:1100px){ .cap-lista{max-height:min(62vh,660px)} }
.cap-seccion{
  font-size:10.5px;letter-spacing:.07em;text-transform:uppercase;font-weight:700;
  color:var(--text-3);padding:var(--sp-2) var(--sp-3) 4px;
}
.cap-fila{
  display:flex;align-items:center;gap:5px;min-height:30px;
  padding:var(--sp-1) var(--sp-2) var(--sp-1) var(--sp-1);cursor:pointer;font-size:12.5px;
  border-left:2px solid transparent;
}
.cap-fila:hover{background:var(--surface-2)}
.cap-fila:focus-visible{outline:2px solid var(--primary);outline-offset:-2px}
.cap-sel{background:var(--primary-softer);border-left-color:var(--primary);font-weight:650}
.cap-oculta .cap-nombre{opacity:.5;text-decoration:line-through}
.cap-grupo{font-weight:650}
.cap-chevron{
  display:inline-flex;align-items:center;justify-content:center;
  width:17px;height:17px;flex:0 0 17px;border:0;background:none;padding:0;
  color:var(--text-3);cursor:pointer;border-radius:4px;
}
.cap-chevron:hover{background:var(--surface-3);color:var(--text-1)}
.cap-chevron-vacio{cursor:default}
.cap-ico{display:inline-flex;color:var(--text-3);flex:0 0 auto}
.cap-nombre{
  flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.cap-cuenta{font-size:10.5px;color:var(--text-3);white-space:nowrap;flex:0 0 auto}
.cap-marca{
  display:inline-flex;align-items:center;gap:2px;flex:0 0 auto;
  font-size:10px;color:var(--text-3);
}
.cap-marca-aviso{
  background:var(--warning-soft);color:var(--warning-ink,var(--text-1));
  border-radius:3px;padding:0 4px;font-weight:650;
}
/* Las acciones aparecen al pasar por encima, pero NUNCA se ocultan al
   teclado: sin esto, quien navega con Tab no podria ocultar ni bloquear
   nada desde el panel. */
.cap-acciones{display:flex;gap:1px;flex:0 0 auto;opacity:0}
.cap-fila:hover .cap-acciones,
.cap-fila:focus-within .cap-acciones,
.cap-sel .cap-acciones{opacity:1}
.cap-accion{
  display:inline-flex;align-items:center;justify-content:center;
  width:22px;height:22px;border:0;background:none;padding:0;border-radius:4px;
  color:var(--text-3);cursor:pointer;
}
.cap-accion:hover{background:var(--surface-3);color:var(--text-1)}
.cap-accion:focus-visible{outline:2px solid var(--primary);outline-offset:-1px;opacity:1}
.cap-accion-on{color:var(--primary)}
.cap-accion-peligro:hover{background:var(--danger-soft);color:var(--danger)}
.cap-vacio{padding:var(--sp-3);font-size:12.5px}

/* Conflicto: contorno a rayas rojas sobre el elemento implicado. Rayas y
   no relleno, para que se siga viendo el color de ocupacion debajo. */
.plano-el.en-conflicto > rect,
.plano-el.en-conflicto > polygon{
  stroke:var(--danger);stroke-width:2.5;stroke-dasharray:5 3;
}
.rev-chip{
  display:inline-flex;align-items:center;justify-content:center;
  min-width:17px;height:17px;padding:0 4px;margin-left:2px;
  border-radius:9px;background:var(--danger);color:#fff;
  font-size:10.5px;font-weight:700;line-height:1;
}
.btn-sec .rev-chip{background:var(--text-3)}
.rev-fila{align-items:flex-start;gap:var(--sp-2);margin-bottom:var(--sp-2)}
.rev-msg{font-weight:600;font-size:13px;line-height:1.35}
.rev-arreglo{font-size:12.5px;opacity:.85;margin-top:2px;line-height:1.35}

/* ===================================================================
   Vista 3D de la bodega (canvas).

   El lienzo lleva `touch-action:none` desde JS porque sin el el navegador
   se queda el gesto para hacer scroll y la camara no gira en el telefono.
   =================================================================== */
.esc3d{display:flex;flex-direction:column;gap:var(--sp-2)}
.esc3d-barra{
  display:flex;flex-wrap:wrap;gap:var(--sp-2);align-items:center;
}
.esc3d-vistas,.esc3d-grupo{display:flex;flex-wrap:wrap;gap:4px;align-items:center}
.esc3d-btn{min-height:38px}
.esc3d-marco{
  position:relative;border:1px solid var(--border);border-radius:var(--r-lg);
  overflow:hidden;background:var(--surface-2);
}
.esc3d-lienzo{display:block;width:100%;height:56vh;min-height:320px}
@media(min-width:900px){ .esc3d-lienzo{height:64vh} }
.esc3d-canvas{display:block;cursor:grab}
.esc3d-canvas:active{cursor:grabbing}
.esc3d-canvas:focus-visible{outline:2px solid var(--primary);outline-offset:-2px}
.esc3d-brujula{
  position:absolute;top:var(--sp-2);right:var(--sp-2);
  display:flex;flex-direction:column;align-items:center;gap:2px;
  padding:var(--sp-2);border-radius:var(--r-md);
  background:var(--surface-1);border:1px solid var(--border);
  pointer-events:none;
}
.esc3d-rosa{
  position:relative;width:30px;height:30px;border-radius:50%;
  border:1.5px solid var(--border-strong);
  display:flex;align-items:flex-start;justify-content:center;
}
.esc3d-n{font-size:10px;font-weight:800;color:var(--primary);line-height:1.1}
.esc3d-angulo{font-size:10px;color:var(--text-3);font-variant-numeric:tabular-nums}
.esc3d-pie{
  display:flex;flex-wrap:wrap;gap:6px;align-items:baseline;
  font-size:12.5px;color:var(--text-2);min-height:20px;
}
.esc3d-sep{opacity:.45}
.esc3d-fav{position:relative}
.esc3d-fav summary{
  display:inline-flex;align-items:center;gap:5px;min-height:38px;
  padding:0 var(--sp-3);border:1px solid var(--border);border-radius:var(--r-md);
  background:var(--surface-1);cursor:pointer;font-size:13px;font-weight:600;
  list-style:none;
}
.esc3d-fav summary::-webkit-details-marker{display:none}
.esc3d-fav-cuerpo{
  position:absolute;right:0;top:calc(100% + 4px);z-index:20;width:230px;
  padding:var(--sp-3);border:1px solid var(--border);border-radius:var(--r-md);
  background:var(--surface-1);box-shadow:var(--sombra-2,0 8px 24px rgba(0,0,0,.14));
}
.esc3d-fav-fila{display:flex;gap:4px;align-items:center;margin-bottom:4px}

/* ===================================================================
   Etiquetas de producto.

   Las medidas van en MILIMETROS porque es lo que entiende una impresora
   de etiquetas y lo que viene escrito en el rollo. Blanco y negro
   siempre: el tema oscuro bajaria el contraste por debajo de lo que
   necesita un lector termico.
   =================================================================== */
.etqp{
  display:flex;flex-direction:column;justify-content:space-between;
  box-sizing:border-box;padding:1.6mm 2mm;
  background:#fff;color:#000;border:1px solid #c8d0d8;border-radius:1mm;
  overflow:hidden;
}
.etqp-cab{min-width:0}
.etqp-nombre{
  font-weight:600;line-height:1.12;
  display:-webkit-box;-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;
  overflow:hidden;
}
.etqp-sku{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-weight:800;line-height:1.3}
.etqp-cuerpo{display:flex;align-items:flex-end;gap:1.5mm;min-width:0}
.etqp-barras{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;align-items:center}
.etqp-barras svg{display:block}
.etqp-cifras{
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  letter-spacing:.08em;line-height:1.2;margin-top:.3mm;
}
.etqp-marca{font-weight:800;letter-spacing:.1em;line-height:1.1}
.etqp-nocabe{font-size:6pt;text-align:center;color:#a00;padding:2mm 0}
.etqp-qr{flex:0 0 auto;display:flex;align-items:flex-end}
.etqp-qr svg{display:block}
.etqp-pie{font-size:5.5pt;opacity:.7;line-height:1.1;margin-top:.5mm}
.etqp-corta{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}

.cod-fila{
  display:flex;align-items:center;gap:var(--sp-2);
  padding:var(--sp-2);border:1px solid var(--border);border-radius:var(--r-md);
  margin-bottom:6px;
}
.esc-leido{
  display:flex;align-items:center;gap:var(--sp-2);flex-wrap:wrap;
  margin:var(--sp-2) 0;padding:var(--sp-2);
  background:var(--surface-2);border-radius:var(--r-md);
}
.esc-leido code{font-size:15px;font-weight:700;letter-spacing:.04em}
.esc-permiso{background:var(--surface-2);border-color:var(--border)}

/* ===================================================================
   Historial de bodega: una linea de tiempo con tres fuentes.
   El color de la izquierda identifica la fuente, pero nunca va solo:
   cada linea lleva tambien su icono y su palabra.
   =================================================================== */
.hb-dia{margin-bottom:var(--sp-4)}
.hb-fecha{
  font-size:11px;letter-spacing:.07em;text-transform:uppercase;font-weight:700;
  color:var(--text-3);padding:0 0 var(--sp-2);position:sticky;top:0;
  background:var(--surface-0,var(--surface-1));z-index:1;
}
.hb-linea{
  display:flex;gap:var(--sp-2);align-items:flex-start;
  padding:var(--sp-3);margin-bottom:6px;
  background:var(--surface-1);border:1px solid var(--border);
  border-left:3px solid var(--border-strong);border-radius:var(--r-md);
}
.hb-mov{border-left-color:var(--primary)}
.hb-cnt{border-left-color:var(--warning)}
.hb-est{border-left-color:var(--text-3)}
.hb-ico{display:inline-flex;color:var(--text-3);flex:0 0 auto;padding-top:1px}
.hb-cab{display:flex;gap:var(--sp-2);align-items:baseline;flex-wrap:wrap}
.hb-hora{font-size:11.5px;color:var(--text-3);font-variant-numeric:tabular-nums}
.hb-detalle{font-size:13.5px;line-height:1.35;margin-top:1px;overflow-wrap:anywhere}
.hb-nota{font-size:12.5px;color:var(--text-2);margin-top:2px;font-style:italic}
.hb-quien{
  display:flex;gap:5px;align-items:center;flex-wrap:wrap;
  font-size:11.5px;color:var(--text-3);margin-top:4px;
}
.hb-sello{
  display:inline-flex;gap:3px;align-items:center;
  padding:0 5px;border-radius:3px;background:var(--surface-3);
  font-size:10px;letter-spacing:.03em;
}

/* =====================================================================
   PÁGINA DE CATEGORÍA Y DE MARCA
   Sustituye al hero cuando el visitante llega a /categoria/... o /marca/...
   Es deliberadamente BAJA: el hero vende la empresa a quien no la conoce,
   pero aquí la persona ya buscó un nombre concreto y lo que necesita es ver
   producto. En un teléfono, la primera fila de la rejilla tiene que caber en
   la primera pantalla.
   ===================================================================== */
.pag-cab{margin-bottom:var(--sp-5)}

/* Migas. No son adorno: quien llega desde Google no tiene historial al que
   volver, y esto es su única salida hacia el catálogo completo. */
.migas{
  display:flex;flex-wrap:wrap;align-items:center;gap:8px;
  font-size:13px;color:var(--text-3);margin-bottom:var(--sp-3);
}
.migas a{color:var(--text-3);text-decoration:none}
.migas a:hover{color:var(--primary);text-decoration:underline}
.migas [aria-current]{color:var(--text-2);font-weight:600}
/* El separador se lee, pero no compite con los enlaces. Con --border-2
   (#EBF1F6, pensado para bordes) sobre fondo claro era invisible: las migas
   parecian tres palabras sueltas. */
.migas-sep{color:var(--text-3);opacity:.55}

.pag-cab-cuerpo{
  display:flex;align-items:center;gap:var(--sp-5);
  background:var(--surface);border:1px solid var(--border);
  border-radius:var(--r-lg);padding:var(--sp-5) var(--sp-6);
  box-shadow:var(--sh-1);
}
/* El logo de la marca, con el mismo trato que en las tarjetas: fondo blanco
   y `contain`, porque los tres logos vienen con fondo opaco y proporciones
   muy distintas entre sí. */
.pag-cab-logo{
  flex:0 0 auto;display:grid;place-items:center;
  width:96px;height:96px;background:#fff;
  border:1px solid var(--border-2);border-radius:var(--r);
  padding:var(--sp-3);
}
.pag-cab-logo img{max-width:100%;max-height:100%;object-fit:contain;display:block}
.pag-cab-texto{min-width:0}
.pag-cab-tit{
  font-family:var(--f-display);font-size:clamp(22px,4.2vw,30px);
  font-weight:700;letter-spacing:-.02em;line-height:1.15;margin:0;color:var(--text);
}
.pag-cab-desc{
  margin:6px 0 0;color:var(--text-2);font-size:var(--fs-md);line-height:1.5;
  max-width:62ch;
}
@media(max-width:560px){
  .pag-cab-cuerpo{gap:var(--sp-4);padding:var(--sp-4)}
  .pag-cab-logo{width:64px;height:64px;padding:var(--sp-2)}
}

/* =====================================================================
   PRODUCTOS FRECUENTES
   =====================================================================
   Una fila compacta por referencia: nombre, precio, cantidad y agregar.
   No es una tarjeta de catalogo en pequeno. Quien usa esto ya sabe lo que
   quiere -lo ha pedido varias veces-, asi que la foto sobraria y le quitaria
   el sitio a dos referencias mas. */
.frecuentes{
  display:grid;gap:var(--sp-2);
  grid-template-columns:repeat(auto-fill,minmax(min(100%,320px),1fr));
}
.frecuente{
  display:grid;grid-template-columns:minmax(0,1fr) auto 62px auto;
  align-items:center;gap:var(--sp-3);
  padding:var(--sp-2) var(--sp-3);
  background:var(--surface);border:1px solid var(--border);
  border-radius:var(--r-md);
}
.frecuente-nom{
  font-size:13px;font-weight:600;color:var(--text);
  display:-webkit-box;-webkit-line-clamp:1;line-clamp:1;
  -webkit-box-orient:vertical;overflow:hidden;
}
.frecuente-precio{font-weight:700;font-size:14px;white-space:nowrap}
/* En telefono el precio baja con la referencia: cuatro columnas en 390 px
   dejarian el nombre en dos palabras, que es el error que ya se corrigio en
   la vista de lista. */
@media(max-width:560px){
  .frecuentes{grid-template-columns:1fr}
  .frecuente{grid-template-columns:minmax(0,1fr) 62px auto;row-gap:var(--sp-1)}
  .frecuente-precio{grid-area:2/1/3/2;font-size:13.5px}
}

/* ===================== Preparacion de pedidos =====================
   La tarjeta del producto que toca recoger AHORA. Lo que decide este bloque
   es que se lea de pie, a un brazo de distancia y con una mano ocupada: la
   foto a tamano reconocible, las tres cifras separadas y con su nombre, y el
   boton de escanear a lo ancho. */
.prep-actual { display: flex; gap: 14px; align-items: flex-start; }
.prep-foto {
  width: 96px; height: 96px; flex: 0 0 96px;
  object-fit: cover; border-radius: 10px;
  border: 1px solid var(--border); background: var(--surface-2);
  display: flex; align-items: center; justify-content: center;
}
/* Las tres cifras en linea, y en columna cuando no caben: en un telefono
   estrecho, apretarlas las vuelve ilegibles justo donde mas se leen. */
.prep-cifras { display: flex; flex-wrap: wrap; gap: 18px; }
.prep-cifras > div { min-width: 86px; }
.prep-cifras strong { display: block; font-size: 26px; line-height: 1.1; font-variant-numeric: tabular-nums; }

@media (max-width: 420px) {
  .prep-actual { gap: 10px; }
  .prep-foto { width: 72px; height: 72px; flex: 0 0 72px; }
  .prep-cifras { gap: 12px; }
  .prep-cifras strong { font-size: 22px; }
}

/* Panel de logistica: los cuatro grupos del turno.
   Botones y no tarjetas muertas: cada uno filtra la lista de abajo. En el
   telefono caben dos por fila, que es lo que hay sitio para leer de un vistazo
   sin desplazarse. */
.prep-grupos { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; align-items: stretch; }
.prep-grupo {
  text-align: left; cursor: pointer; border: 1px solid var(--border);
  display: flex; flex-direction: column; gap: 4px; min-height: 76px;
}
.prep-grupo:disabled { cursor: default; opacity: .55; }
.prep-grupo.on { border-color: var(--primary); box-shadow: inset 0 0 0 1px var(--primary); }
.prep-grupo-n { font-size: 26px; line-height: 1; font-variant-numeric: tabular-nums; }

@media (max-width: 640px) {
  .prep-grupos { grid-template-columns: repeat(2, 1fr); gap: 8px; }
  .prep-grupo { min-height: 66px; }
  .prep-grupo-n { font-size: 22px; }
}
