/* ── Design Tokens ─────────────────────────────────────────── */
:root {
  --brand-navy:         #204080;
  --brand-teal:         #0078A8;
  --brand-green:        #5A9400;
  --brand-yellow:       #D4B800;
  --brand-orange:       #E89010;
  --brand-orange-dark:  #C86000;

  /* ⭐⭐ NARANJA DE OPERACIÓN — #D4600E (decisión de Manuel, 2026-07-31).
     Identifica DÓNDE TRABAJA EL OPERADOR: el operario de piso vive en naranja,
     el supervisor en azul. Nació en la APK de Colecta el 24/07 como
     --orange-module, elegido contra la TC26 REAL después de descartar #E89010
     porque en ese hardware tira a ocre y no lee como naranja.
     🔴 NO ES UN TERCER NARANJA: es el MISMO token de módulo, que ahora vive
     también acá. Sigue siendo distinto de --brand-orange (#E89010), que es
     SEMÁNTICO: alerta moderada, En reparación, Lista para entrega, warnings.
     ⭐ Se extiende al Web para heredar la identidad que el Kiosko va a necesitar
     (ADR-026) en vez de inventar otra cuando llegue. */
  --orange-module:      #D4600E;

  /* Texto oscuro sobre fondos naranja translúcidos (badges y alertas).
     🔴 Era el literal #9a5a00 repetido NUEVE veces y sin nombre: cualquier
     cambio de naranja lo iba a tocar a ciegas. Contraste medido sobre el tinte
     claro: 5,5:1 — pasa AA para texto normal. */
  --orange-text-on-tint: #9A5A00;

  --color-primary:      #204080;
  --color-secondary:    #0078A8;
  --color-success:      #5A9400;
  --color-warning:      #D4B800;
  --color-danger:       #DC2626;
  --color-info:         #0078A8;

  --text-primary:       #1A3060;
  --text-secondary:     #4A5A7A;
  --text-muted:         #718096;
  --text-on-primary:    #FFFFFF;
  --text-accent:        #0078A8;

  --bg-primary:         #FFFFFF;
  --bg-secondary:       #F4F7FB;
  --bg-accent:          #E8F2F8;
  --bg-navy:            #204080;
  --bg-navy-dark:       #172E5E;

  --border:             #D1DCE8;
  --border-strong:      #A8BCCF;
  --border-accent:      #0078A8;

  --status-alta:        #5A9400;
  --status-en-uso:      #204080;
  --status-para-lavar:  #718096;
  --status-en-proceso:  #6B21A8;
  --status-qc:          #D4B800;
  --status-lista:       #0078A8;
  --status-reparacion:  #E89010;
  --status-baja:        #DC2626;

  --font-sans:          'Segoe UI', -apple-system, BlinkMacSystemFont, sans-serif;
  --font-mono:          'Cascadia Code', 'Consolas', monospace;

  --radius-sm:          4px;
  --radius-md:          8px;
  --radius-lg:          12px;
  --radius-pill:        999px;

  --shadow-sm:          0 1px 3px rgba(32,64,128,0.08);
  --shadow-md:          0 4px 12px rgba(32,64,128,0.12);
  --shadow-lg:          0 8px 24px rgba(32,64,128,0.16);

  --sidebar-width:      260px;
  --sidebar-collapsed:  64px;
  --header-height:      56px;

  /* ── ⭐⭐ LOS CINCO BLOQUES DEL MENU (2026-08-15) ────────────────────────
     🔴 SON TOKENS Y NO HEX SUELTOS EN EL SELECTOR, por pedido explicito de
     Manuel y por la regla que el naranja ya dejo escrita: el problema no es que
     existan constantes, es que esten DUPLICADAS -- y el remedio es CENTRALIZAR.
     Antes `#4A7A00` vivia suelto en `.nav-ciclo-recepcion`; ahora los cinco
     salen de acá.

     ⭐ Los tres de OPERACION no cambian de valor: dos ya eran tokens y el verde
     se muda tal cual. Es un renombre, no un retoque -- lo validado el 14/08
     sigue pintando exactamente igual.

     ── CONTRASTE, CALCULADO (blanco encima; umbral AA 4,5:1 porque el menu es
        13,5 px / 600, que NO es texto grande) ──
       recepcion   #4A7A00   5,15:1  ✅
       lavanderia  #9A5A00   5,47:1  ✅
       entrega     #0078A8   4,94:1  ✅
       GESTION     #6E6200   6,16:1  ✅  (nuevo)
       ADMIN       #A32D2D   7,07:1  ✅  (nuevo, pasa incluso AAA)

     ⚠️ POR QUE LOS DOS NUEVOS SON TOKENS PROPIOS Y NO SE APROXIMAN CON LOS QUE
     YA HABIA -- medido, no supuesto:
       · Amarillo: el unico de paleta es `--brand-yellow` #D4B800, y con blanco
         encima da **1,97:1**. No hay con que aproximarlo.
       · Rojo: `--color-danger` #DC2626 da 4,83:1 y pasaria -- pero es el rojo de
         ERROR. Usarlo de cromo haria que un mensaje de error se viera igual que
         un bloque de menu. ⭐ Es la MISMA logica que ya separa el naranja del
         menu del naranja de accion: el de cromo es una version mas oscura y
         desaturada de la familia.
     ─────────────────────────────────────────────────────────────────────── */
  --nav-recepcion:      #4A7A00;
  --nav-lavanderia:     var(--orange-text-on-tint);   /* #9A5A00 */
  --nav-entrega:        var(--brand-teal);            /* #0078A8 */
  --nav-gestion:        #6E6200;
  --nav-admin:          #A32D2D;
}

/* ── Reset / Base ──────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html, body {
  height: 100%;
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--text-primary);
  background: var(--bg-secondary);
}

a { color: var(--text-accent); text-decoration: none; }
a:hover { text-decoration: underline; }

button { cursor: pointer; font-family: var(--font-sans); }

/* ── App Shell ─────────────────────────────────────────────── */
.app-shell {
  display: flex;
  height: 100vh;
  overflow: hidden;
}

.content-area {
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  min-width: 0;
}

/* ── Sidebar ───────────────────────────────────────────────── */
/* Sin superficie propia -- hereda el fondo de la página (--bg-secondary,
   vía <body>). Los .nav-block son ahora las únicas superficies navy;
   el sidebar solo las contiene y las separa del contenido con un borde
   sutil (ya no hay contraste de color que marque el límite). */
.sidebar {
  width: var(--sidebar-width);
  flex-shrink: 0;
  background: transparent;
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  transition: width 0.25s ease;
  overflow: hidden;
}

.sidebar.sidebar-collapsed {
  width: var(--sidebar-collapsed);
}

/* ⭐⭐ EL LOGO CRECIO DE 36 A 44 px, Y EL PADDING BAJO PARA COMPENSAR
   (2026-08-14, pedido de Manuel: "se ve pequeño").

   🔴 AL MEDIRLO APARECIO QUE LA CABECERA YA ESTABA DESALINEADA, y no por esto:
   `.top-header` mide `--header-height` = **56 px FIJOS**, y este bloque medía
   36 (logo) + 14 + 14 (padding) = **64 px**. Eran **8 px de desfase** contra la
   cabecera del contenido, de antes de tocar nada.

   ⭐ Por eso el padding vertical baja a 6: **44 + 6 + 6 = 56 px EXACTOS**. El
   logo crece un 22% y de paso la cabecera queda alineada, que es lo que la
   ampliación podría haber empeorado.

   ⚠️ El límite NO fue el ancho: con el sidebar en 260 px sobraban ~79 px
   después del logo, el gap y los 95 px que mide "WashFlow" a 18 px. **El techo
   es vertical**, y son los 56 px del `top-header`. Un logo más grande obliga a
   romper ese alineado o a comerse el padding hasta que el logo toque el borde. */
.sidebar-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 16px;
  background: #ffffff;
  border-bottom: 1px solid #e2e8f0;
  min-height: var(--header-height);
  flex-shrink: 0;
}

/* 🔴 EL CASO QUE DE VERDAD APRETABA: COLAPSADO. El sidebar baja a
   `--sidebar-collapsed` = 64 px, y con el padding horizontal de 16 quedaban
   **32 px** para un logo de 44. Se reduce a 8 px por lado -> 48 px de hueco,
   y el logo entra con aire.
   ⭐ Hay precedente en el propio archivo: `.sidebar-collapsed .nav-block` ya
   baja su padding por el mismo motivo. */
.sidebar-collapsed .sidebar-brand { padding: 6px 8px; justify-content: center; }

.sidebar-logo-img {
  height: 44px;
  width: auto;
  display: block;
  flex-shrink: 0;
}

.sidebar-brand-name {
  color: #204080;
  font-size: 18px;
  font-weight: 600;
  white-space: nowrap;
  letter-spacing: 0.01em;
}

/* ── Sidebar Nav ───────────────────────────────────────────── */
.sidebar-nav {
  flex: 1;
  padding: 12px 8px;
  overflow-y: auto;
  overflow-x: hidden;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.sidebar-nav::-webkit-scrollbar { width: 4px; }
.sidebar-nav::-webkit-scrollbar-thumb { background: rgba(32,64,128,0.25); border-radius: 2px; }

.nav-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 10px;
  border-radius: var(--radius-md);
  color: rgba(255,255,255,0.75);
  font-size: 13.5px;
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
  transition: background 0.15s, color 0.15s;
}

.nav-item:hover {
  background: rgba(255,255,255,0.12);
  color: #fff;
  text-decoration: none;
}

.nav-item.active {
  background: rgba(232,144,16,0.13);
  color: #fff;
  border: 1.5px solid var(--brand-orange);
  border-radius: 8px;
}

.nav-item .bi {
  font-size: 16px;
  flex-shrink: 0;
  width: 20px;
  text-align: center;
}

/* ⭐⭐ Ícono con color de OPERACIÓN -- solo en esa sección del menú.
   Sólo el glifo cambia de color; el texto del ítem sigue el estilo normal y
   .nav-item.active no se toca, sigue siendo el indicador universal de "estás
   acá". Gestión y Administración se quedan en navy (sin clase de acento).

   🔴 ANTES ERAN TRES COLORES por proceso (entrada=verde, intermedio=teal,
   salida=naranja). Desde el 2026-07-31 los cinco ítems comparten UNO: el corte
   dejó de ser "qué proceso es" y pasó a ser "quién usa la pantalla". */
.nav-item-accent-operation .bi      { color: var(--orange-module); }

.nav-label { flex: 1; }

/* Bloque de sección -- envuelve encabezado + ítems para que cada
   sección se lea como una isla propia, no ítems sueltos. El sidebar ya
   no tiene superficie navy propia (hereda el fondo claro de la página):
   cada bloque es ahora la superficie navy sólida, con el mismo radio
   que las tarjetas de los hubs (--radius-lg) y una sombra sutil para
   que "flote" igual que ellas. El texto/íconos del menú (blancos a
   distintas opacidades) ya estaban pensados para verse sobre navy, no
   cambian. El highlight de .nav-item.active (naranja) sigue siendo
   claramente distinguible contra este fondo. */
.nav-block {
  display: flex;
  flex-direction: column;
  gap: 2px;
  background: var(--brand-navy);
  box-shadow: var(--shadow-sm);
  border-radius: var(--radius-lg);
  padding: 10px 6px 12px;
  margin-bottom: 20px;
}
.nav-block:last-child { margin-bottom: 0; }
/* Colapsado: el sidebar baja a 64px -- el padding del bloque sumado al
   del propio .nav-item ya no deja espacio para el ícono. Se angosta acá
   en vez de tocar .nav-item (que no cambia en ningún otro estado). */
.sidebar-collapsed .nav-block { padding-left: 2px; padding-right: 2px; }

/* Encabezado de sección -- discreto: texto chico, mayúsculas, gris
   claro, sin fondo ni línea propia (vive dentro del bloque). Es texto,
   no un control (sin tabindex, sin rol interactivo) -- no debe recibir
   foco de teclado. Se renderiza siempre (incluso colapsado, sin texto)
   para que el padding del bloque quede consistente en los dos modos. */
.nav-section-title {
  margin: 2px 4px 8px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(255,255,255,0.4);
}

.nav-separator {
  height: 1px;
  background: rgba(255,255,255,0.1);
  margin: 8px 4px;
}

/* ── Nav Groups (Catálogos, Configuración) ─────────────────── */
.nav-group { display: flex; flex-direction: column; }

.nav-group-toggle {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 10px;
  border-radius: var(--radius-md);
  background: none;
  border: none;
  color: rgba(255,255,255,0.75);
  font-size: 13.5px;
  font-weight: 500;
  width: 100%;
  text-align: left;
  white-space: nowrap;
  transition: background 0.15s, color 0.15s;
}

.nav-group-toggle:hover {
  background: rgba(255,255,255,0.12);
  color: #fff;
}

.nav-group-toggle .bi { font-size: 16px; flex-shrink: 0; width: 20px; text-align: center; }
.nav-chevron { font-size: 11px !important; }

.nav-sub-items {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 2px 0 2px 14px;
}

.nav-sub-item {
  display: block;
  padding: 7px 12px;
  border-radius: var(--radius-sm);
  color: rgba(255,255,255,0.6);
  font-size: 12.5px;
  text-decoration: none;
  border-left: 2px solid rgba(255,255,255,0.15);
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}

.nav-sub-item:hover {
  color: #fff;
  text-decoration: none;
  border-left-color: var(--brand-teal);
  background: rgba(255,255,255,0.07);
}

.nav-sub-item.active {
  color: #fff;
  text-decoration: none;
  background: rgba(232,144,16,0.13);
  border: 1.5px solid var(--brand-orange);
  border-radius: 8px;
}

/* Padre del grupo cuando un hijo está activo */
.nav-group-toggle.has-active-child .nav-label {
  color: rgba(232,144,16,0.9);
}
.nav-group-toggle.has-active-child {
  color: rgba(255,255,255,0.95);
}
/* Punto naranja cuando el sidebar está colapsado (solo icono visible) */
.sidebar-collapsed .nav-group-toggle.has-active-child {
  position: relative;
}
.sidebar-collapsed .nav-group-toggle.has-active-child::after {
  content: '';
  position: absolute;
  top: 7px;
  right: 7px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--brand-orange);
  border: 1px solid var(--bg-navy);
}

/* ── Top Header ────────────────────────────────────────────── */
.top-header {
  height: var(--header-height);
  background: var(--bg-primary);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  padding: 0 20px;
  gap: 12px;
  flex-shrink: 0;
  box-shadow: var(--shadow-sm);
}

.header-spacer { flex: 1; }

.toggle-btn {
  width: 36px;
  height: 36px;
  border-radius: var(--radius-md);
  background: none;
  border: 1px solid var(--border);
  color: var(--text-secondary);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
  transition: background 0.15s, color 0.15s;
}

.toggle-btn:hover {
  background: var(--bg-secondary);
  color: var(--color-primary);
}

.user-info {
  font-size: 13px;
  color: var(--text-secondary);
}

.role-badge {
  font-size: 11px;
  font-weight: 600;
  background: var(--bg-accent);
  color: var(--color-primary);
  padding: 2px 8px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--border-accent);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.logout-btn {
  background: none;
  border: 1px solid var(--border);
  color: var(--text-secondary);
  border-radius: var(--radius-md);
  padding: 5px 12px;
  font-size: 13px;
  display: flex;
  align-items: center;
  transition: border-color 0.15s, color 0.15s, background 0.15s;
}

.logout-btn:hover {
  border-color: var(--color-danger);
  color: var(--color-danger);
  background: rgba(220,38,38,0.04);
}

/* ── Main Content ──────────────────────────────────────────── */
.main-content {
  flex: 1;
  overflow-y: auto;
  background: var(--bg-secondary);
  padding: 28px;
}

/* ── App Loading ───────────────────────────────────────────── */
.app-loading {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
  background: var(--bg-secondary);
}

.loading-spinner {
  width: 40px;
  height: 40px;
  border: 3px solid var(--border);
  border-top-color: var(--color-primary);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

@keyframes spin { to { transform: rotate(360deg); } }

/* ── Auth Shell (Login) ────────────────────────────────────── */
.auth-shell {
  min-height: 100vh;
  background: var(--bg-secondary);
  display: flex;
  align-items: center;
  justify-content: center;
  /* Para anclar la salida del Kiosko al pie sin sacar la tarjeta del centro. */
  position: relative;
}

/*
  LA SALIDA DEL MODO KIOSKO DESDE LA PANTALLA DE ENTRAR -- ADR-056 D12.
  Agregada el 2026-08-20: con el token vencido el Kiosko cae en /login, y este
  layout no tenia NI UN boton. Puesto bloqueado, sesion muerta y ninguna puerta.

  Va ABAJO y en tinte, no arriba y en solido, y es deliberado: NO es la accion
  de esta pantalla --la accion es entrar-- sino la salida de excepcion. La regla
  de cantidad del repo se cumple: el unico solido de aqui sigue siendo "Iniciar
  sesion".
*/
.auth-kiosko-exit {
  position: absolute;
  bottom: 1.5rem;
  left: 50%;
  transform: translateX(-50%);
}

.login-card {
  background: var(--bg-primary);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: 40px 48px;
  width: 100%;
  max-width: 420px;
}

.login-header { text-align: center; margin-bottom: 32px; }

.login-logo-img {
  display: block;
  max-width: 180px;
  height: auto;
  margin: 0 auto 20px;
}

.login-title {
  font-size: 22px;
  font-weight: 700;
  color: var(--text-primary);
  margin-bottom: 4px;
}

.login-subtitle {
  font-size: 13px;
  color: var(--text-muted);
}

.login-form .form-label {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-secondary);
  margin-bottom: 4px;
}

.login-form .form-control {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 9px 12px;
  font-size: 14px;
  color: var(--text-primary);
  background: var(--bg-primary);
  transition: border-color 0.15s, box-shadow 0.15s;
}

.login-form .form-control:focus {
  border-color: var(--border-accent);
  box-shadow: 0 0 0 3px rgba(0,120,168,0.15);
  outline: none;
}

.btn-login {
  width: 100%;
  padding: 10px;
  background: var(--color-primary);
  color: #fff;
  border: none;
  border-radius: var(--radius-md);
  font-size: 14px;
  font-weight: 600;
  transition: background 0.15s;
}

.btn-login:hover:not(:disabled) { background: var(--bg-navy-dark); }
.btn-login:disabled { opacity: 0.65; cursor: not-allowed; }

.login-session-expired {
  margin-bottom: 20px;
  padding: 10px 14px;
  background: rgba(212,184,0,0.07);
  border: 1px solid rgba(212,184,0,0.4);
  border-radius: var(--radius-md);
  color: #5c4a00;
  font-size: 13px;
  text-align: center;
}

.login-error {
  margin-top: 12px;
  padding: 10px 14px;
  background: rgba(220,38,38,0.08);
  border: 1px solid rgba(220,38,38,0.3);
  border-radius: var(--radius-md);
  color: var(--color-danger);
  font-size: 13px;
  text-align: center;
}

/* Selector de idioma — solo visible en Login (POC ADR-010) */
.login-lang-bar {
  display: flex;
  justify-content: flex-end;
  margin-bottom: 16px;
}

.login-lang-select {
  font-size: 12px;
  padding: 3px 8px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-secondary);
  color: var(--color-primary);
  cursor: pointer;
}

.login-lang-select:focus {
  outline: none;
  border-color: var(--border-accent);
}

/* ── Dashboard ─────────────────────────────────────────────── */
.page-header {
  margin-bottom: 24px;
}

.page-title {
  font-size: 22px;
  font-weight: 700;
  color: var(--text-primary);
  margin-bottom: 4px;
}

.page-subtitle {
  font-size: 13px;
  color: var(--text-muted);
}

.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 16px;
  margin-bottom: 28px;
}

.stat-card {
  background: var(--bg-primary);
  border-radius: var(--radius-lg);
  padding: 20px;
  box-shadow: var(--shadow-sm);
  border: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.stat-card-alert {
  border-color: var(--color-danger);
  background: #fff5f5;
}
.stat-card-clickable {
  cursor: pointer;
  transition: box-shadow 0.15s, border-color 0.15s, transform 0.1s;
}
.stat-card-clickable:hover {
  box-shadow: var(--shadow-md);
  border-color: var(--color-primary);
  transform: translateY(-1px);
}

.stat-icon {
  width: 40px;
  height: 40px;
  border-radius: var(--radius-md);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
}

.stat-icon.navy    { background: rgba(32,64,128,0.1);  color: var(--brand-navy); }
.stat-icon.teal    { background: rgba(0,120,168,0.1);  color: var(--brand-teal); }
.stat-icon.green   { background: rgba(90,148,0,0.1);   color: var(--brand-green); }
.stat-icon.orange  { background: rgba(232,144,16,0.1); color: var(--brand-orange); }
.stat-icon.danger  { background: rgba(220,38,38,0.1);  color: var(--color-danger); }
.stat-icon.yellow  { background: rgba(212,184,0,0.1);  color: #9a8500; }

.stat-value {
  font-size: 28px;
  font-weight: 700;
  color: var(--text-primary);
  line-height: 1;
}

.stat-label {
  font-size: 12px;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-weight: 600;
}

.dashboard-section {
  background: var(--bg-primary);
  border-radius: var(--radius-lg);
  padding: 24px;
  border: 1px solid var(--border);
  box-shadow: var(--shadow-sm);
}

.section-title {
  font-size: 15px;
  font-weight: 600;
  color: var(--text-primary);
  margin-bottom: 16px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border);
}

.placeholder-msg {
  color: var(--text-muted);
  font-size: 13px;
  padding: 24px 0;
  text-align: center;
}

/* ── Botones de página ─────────────────────────────────────── */
.btn-wf {
  display: inline-flex;
  align-items: center;
  padding: 7px 16px;
  border-radius: var(--radius-md);
  font-size: 13px;
  font-weight: 600;
  border: 1px solid transparent;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
  text-decoration: none;
  white-space: nowrap;
}
.btn-wf:disabled { opacity: 0.55; cursor: not-allowed; }
.btn-wf-primary  { background: var(--color-primary); color: #fff; border-color: var(--color-primary); }
.btn-wf-primary:hover:not(:disabled)  { background: var(--bg-navy-dark); }
.btn-wf-secondary { background: var(--bg-accent); color: var(--color-secondary); border-color: var(--border-accent); }
.btn-wf-secondary:hover:not(:disabled) { background: #d0e9f5; }
.btn-wf-ghost    { background: transparent; color: var(--text-secondary); border-color: var(--border); }
.btn-wf-ghost:hover:not(:disabled) { background: var(--bg-secondary); }
.btn-wf-danger   { background: rgba(220,38,38,0.08); color: var(--color-danger); border-color: rgba(220,38,38,0.3); }
.btn-wf-danger:hover:not(:disabled) { background: rgba(220,38,38,0.15); }
.btn-wf-success  { background: rgba(90,148,0,0.09); color: var(--color-success); border-color: rgba(90,148,0,0.35); }
.btn-wf-success:hover:not(:disabled) { background: rgba(90,148,0,0.16); }
/* ═══════════════════════════════════════════════════════════════════════════
   🔴🔴 `.btn-wf-sm` SOLO CAMBIA EL TAMANO. **UN BOTON CHICO SIGUE SIENDO
   SOLIDO Y SIGUE CONTANDO PARA LA REGLA DE CANTIDAD** (escrito 2026-08-15).

   ⚠️ SE ESCRIBE ACA PORQUE SU AUSENCIA YA HIZO MENTIR A UN CIERRE. El
   2026-08-15 se declaro que "ninguna pagina tiene ya mas de un solido naranja",
   y al medirlo al dia siguiente eran DOS en `PrepararDespachos` (Actualizar +
   el puente) y **UNO POR FILA PENDIENTE** en `RecibirDelLavandero`
   (Materializar) mas *Enrolar*. La afirmacion era falsa y nadie la desmintio,
   porque **el grep de la regla busca `btn-wf-operation` y no distingue tamanos**
   -- asi que el que midio conto lo que le parecio y el que leyo entendio otra
   cosa.

   ⭐ EL CRITERIO, para que la proxima medicion de lo mismo en las dos manos:
     · CUENTAN todos los `btn-wf-operation`, con o sin `btn-wf-sm`.
     · Un boton que se pinta UNA VEZ POR FILA cuenta como N, no como 1. Por eso
       las LISTAS NUNCA SON SOLIDAS: es la unica forma de que el conteo no
       dependa de cuantos datos haya.
     · NO cuentan `-soft` ni `btn-wf-discard`: son tinte, no solido.
     · NO cuentan `.nav-ciclo` ni `.nav-bloque` (cromo del menu), y esa
       excepcion esta escrita mas abajo, en su propio bloque.

   🔴 VERIFICACION, y tiene que dar 1 por pagina --contando el markup, no la
   pantalla, porque el markup es lo que se puede automatizar--:
     grep -o 'btn-wf-operation"' *.razor | uniq -c
   ⚠️ Dos ocurrencias EXCLUYENTES entre si (ramas de un `@if`/`else`) son un
   falso positivo legitimo: se resuelven mirando, y si aparecen se anotan acá.

   📋 FALSOS POSITIVOS CONOCIDOS, medidos el 2026-08-15 --se anotan para que el
   proximo que corra el grep no los re-investigue--:
     · `VerificarBolsas.razor` da 2 y tiene 1: la otra ocurrencia esta DENTRO DE
       UN COMENTARIO (L91), citando esta misma regla.
   ⭐ Ese es el limite del grep y por eso el conteo se LEE, no se obedece: la
   herramienta acota el trabajo, no lo reemplaza.
   ═══════════════════════════════════════════════════════════════════════════ */
.btn-wf-sm { padding: 4px 10px; font-size: 12px; }

/* ── Filter bar ────────────────────────────────────────────── */
.filter-bar { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-bottom: 16px; }

/* ── Modificador: BLOQUES DE DISTINTO ALTO EN LA MISMA BARRA ──────────
   ⭐ Cuando UNO de los buscadores lleva una linea de ayuda debajo y el otro no,
   `align-items: center` --el default de `.filter-bar`-- CENTRA cada bloque por
   su propio alto: el mas alto baja su etiqueta y su campo, y los dos
   buscadores dejan de compartir linea de base.

   🔴 El sintoma es el de siempre en CSS: no falla, no avisa, solo se ve mal.
   Lo encontro Manuel mirando la pantalla (trazabilidad por tag, 2026-08-15).

   ⭐ `flex-start` alinea por ARRIBA, que es donde estan las etiquetas: los
   campos y sus botones quedan a la misma altura y **la linea de ayuda cuelga
   debajo de su propio bloque sin arrastrar al otro**.

   ⚠️ NO se toca `.filter-bar`, que usan 27 pantallas: ahi todos los hijos
   miden lo mismo y centrar es correcto. Un modificador y no un cambio global. */
.filter-bar-top { align-items: flex-start; }

/* ── Barra de ACCIONES, separada de los filtros ──────────────
   ⭐ Criterio de Manuel (2026-08-01): "no tenerle miedo a los colores".
   "Actualizar" vivia dentro de las filas de chips, con la misma forma y el
   mismo color que los botones que SI filtran -- indistinguible de un vistazo.
   Estas dos son ACCIONES, van arriba del bloque de filtros y llevan el naranja
   de OPERACION, que ya es el color de identidad de estas pantallas. */
.action-bar {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  align-items: center;
  margin-bottom: 14px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--border);
}

.btn-wf-operation {
  background: var(--orange-module);
  color: #fff;
  border-color: var(--orange-module);
}
.btn-wf-operation:hover:not(:disabled) { background: #b8520c; border-color: #b8520c; }

/* La secundaria: mismo color, menos peso -- son dos acciones de distinto rango
   y darles el mismo relleno haria competir a las dos por la mirada. */
.btn-wf-operation-soft {
  background: rgba(212,96,14,0.10);
  color: var(--orange-text-on-tint);
  border-color: rgba(212,96,14,0.35);
}
.btn-wf-operation-soft:hover:not(:disabled) { background: rgba(212,96,14,0.18); }

/* La tercera accion: DESCARTA, no trae ni navega -- y por eso lleva el AZUL de
   la paleta en vez del naranja. Estuvo en gris un rato y se leia como
   deshabilitada: en este producto una accion se distingue POR COLOR, y el gris
   esta reservado a lo que NO se puede tocar.
   ⭐ Mismo PESO que .btn-wf-operation-soft (tinte, no solido) y distinta FAMILIA
   de color: comparte rango con "Ver grupos" y se distingue de ella de un
   vistazo, sin competir con el solido de "Actualizar".
   ⚠️ Texto en --color-primary (navy) y NO en --color-secondary: el teal sobre
   este tinte da 4,35:1 --por debajo del 4,5:1 que pide AA para texto normal--
   mientras que el navy da 8,8:1. Tres tokens de la paleta, ningun valor nuevo. */
.btn-wf-discard {
  background: var(--bg-accent);
  color: var(--color-primary);
  border-color: var(--border-accent);
}
.btn-wf-discard:hover:not(:disabled) { background: #d0e9f5; }

/* ── Filtros de un toque (botones, no desplegables) ──────────
   Pensados para KIOSKO: el operario de pie no despliega listas ni escribe,
   toca. Un <select> son tres interacciones; un chip es una. Por eso el alto
   minimo es 40px -- el minimo comodo para un dedo, no para un mouse.
   Una FILA POR CRITERIO, con el nombre del criterio en columna fija: con los
   chips de tres ejes mezclados en una sola fila no se distingue cual filtra
   que. */
.chip-filters { display: flex; flex-direction: column; gap: 8px; margin-bottom: 16px; }
.chip-row { display: flex; align-items: flex-start; gap: 10px; }
.chip-row-label {
  flex: 0 0 104px;
  padding-top: 10px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: 0.3px;
}
.chip-row-items { display: flex; flex-wrap: wrap; gap: 6px; flex: 1 1 auto; min-width: 0; }

.filter-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 40px;
  padding: 6px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--bg-primary);
  color: var(--text-primary);
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s, color 0.12s;
}
.filter-chip:hover:not(:disabled) { background: var(--bg-secondary); border-color: var(--border-strong); }
.filter-chip:disabled { opacity: 0.55; cursor: not-allowed; }

/* Activo = naranja de OPERACION, el color de identidad del modulo. */
.filter-chip.active {
  background: var(--orange-module);
  border-color: var(--orange-module);
  color: #fff;
}
.filter-chip.active:hover { background: #b8520c; border-color: #b8520c; }

/* El conteo va DENTRO del boton: el operador ve cuanto trae cada filtro sin
   tener que aplicarlo. */
.chip-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 20px;
  padding: 0 6px;
  border-radius: var(--radius-pill);
  background: var(--bg-secondary);
  color: var(--text-secondary);
  font-size: 11px;
  font-weight: 700;
}
.filter-chip.active .chip-count { background: rgba(255,255,255,0.28); color: #fff; }

.filter-chip-more { border-style: dashed; color: var(--text-secondary); }

/* ── Barra de seleccion ──────────────────────────────────────
   Pegajosa: con cientos de filas el boton de accion quedaria al final de un
   scroll largo, y quien marca 40 filas tendria que volver a buscarlo. */
.select-bar {
  position: sticky;
  top: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 10px;
  padding: 10px 14px;
  margin-bottom: 10px;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
}
.select-bar-counts { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.select-bar-total { font-size: 14px; font-weight: 600; color: var(--text-primary); }
.select-bar-selected {
  font-size: 13px;
  font-weight: 600;
  color: var(--orange-text-on-tint);
  background: rgba(212,96,14,0.10);
  border: 1px solid rgba(212,96,14,0.28);
  border-radius: var(--radius-pill);
  padding: 3px 12px;
}

/* Casilla grande: misma razon que el alto del chip -- se toca con el dedo. */
.chk-lg { width: 20px; height: 20px; cursor: pointer; accent-color: var(--orange-module); }

.data-table tbody tr.row-selected { background: rgba(212,96,14,0.08); }
.data-table tbody tr.row-selected:hover { background: rgba(212,96,14,0.13); }

/* ── Table card ────────────────────────────────────────────── */
.table-card {
  background: var(--bg-primary);
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-sm);
  overflow-x: auto;
}
.data-table {
  width: 100%;
  min-width: 100%;
  border-collapse: collapse;
  font-size: 13.5px;
}
.data-table thead tr { background: var(--bg-secondary); border-bottom: 2px solid var(--border); }
.data-table th { padding: 10px 16px; text-align: left; font-size: 11px; font-weight: 700; color: var(--text-secondary); text-transform: uppercase; letter-spacing: 0.06em; white-space: nowrap; }
.data-table td { padding: 11px 16px; color: var(--text-primary); border-bottom: 1px solid var(--border); vertical-align: middle; white-space: nowrap; }
.data-table tbody tr:last-child td { border-bottom: none; }
.data-table tbody tr.clickable-row { cursor: pointer; transition: background 0.1s; }
.data-table tbody tr.clickable-row:hover { background: var(--bg-secondary); }

/* ── Status badges ─────────────────────────────────────────── */
.badge {
  display: inline-flex; align-items: center;
  padding: 3px 9px;
  border-radius: var(--radius-pill);
  font-size: 10.5px; font-weight: 700;
  letter-spacing: 0.05em; text-transform: uppercase; white-space: nowrap;
}
/* Verde #5A9400 -- OK / completado: Confirmada, Disponible, Entregada, Resuelta, Aprobado */
/* ⭐⭐ `.badge-success` — el SEMANTICO del grupo verde, agregado el 2026-08-09.
   🔴 POR QUE FALTABA Y POR QUE IMPORTA: `PrepararDespachos.razor` ya pintaba el
   estado "Escaneada" con `badge-success`, y la clase NO EXISTIA. No falla al
   compilar ni en runtime: la regla base `.badge` solo pone forma --padding,
   radio, mayusculas-- y ninguna define color, asi que el badge salia SIN pastilla
   y se leia como "esta fila no tiene estado". Es exactamente el defecto de
   `table-wf` que `CLAUDE.md` documenta: un nombre inventado en un lenguaje que no
   protesta.
   ⚠️ Y el sintoma enganaba al maximo: como la tabla ordena las verificadas
   PRIMERO, las filas sin pastilla eran justo las que SI habian funcionado.
   ⭐ No se inventa un valor: reusa el verde de marca del grupo. */
.badge-success       { background: rgba(90,148,0,0.12);    color: #4a7a00; border: 1px solid rgba(90,148,0,0.3);    }
.badge-disponible    { background: rgba(90,148,0,0.12);    color: #4a7a00; border: 1px solid rgba(90,148,0,0.3);    }
.badge-alta          { background: rgba(90,148,0,0.12);    color: #4a7a00; border: 1px solid rgba(90,148,0,0.3);    }
.badge-entregada     { background: rgba(90,148,0,0.12);    color: #4a7a00; border: 1px solid rgba(90,148,0,0.3);    }
.badge-resuelta      { background: rgba(90,148,0,0.12);    color: #4a7a00; border: 1px solid rgba(90,148,0,0.3);    }
.badge-aprobado      { background: rgba(90,148,0,0.12);    color: #4a7a00; border: 1px solid rgba(90,148,0,0.3);    }
.badge-confirmada    { background: rgba(90,148,0,0.12);    color: #4a7a00; border: 1px solid rgba(90,148,0,0.3);    }

/* Navy -- estado operativo normal, sin urgencia: EnUso */
.badge-en-uso        { background: rgba(32,64,128,0.1);    color: #204080; border: 1px solid rgba(32,64,128,0.25);  }

/* Gris -- neutro: Borrador, Normal, Reconocida */
.badge-borrador      { background: rgba(113,128,150,0.12); color: #5a6a7e; border: 1px solid rgba(113,128,150,0.3); }
.badge-reconocida    { background: rgba(113,128,150,0.12); color: #5a6a7e; border: 1px solid rgba(113,128,150,0.3); }
.badge-default       { background: rgba(113,128,150,0.1);  color: #5a6a7e; border: 1px solid rgba(113,128,150,0.2); }

/* Azul/Teal #0078A8 -- en curso: EnProceso, EnQc, ControlQc, ParaLavar */
.badge-en-proceso    { background: rgba(0,120,168,0.1);    color: #0078A8; border: 1px solid rgba(0,120,168,0.25);  }
.badge-en-qc         { background: rgba(0,120,168,0.1);    color: #0078A8; border: 1px solid rgba(0,120,168,0.25);  }
.badge-control-qc    { background: rgba(0,120,168,0.1);    color: #0078A8; border: 1px solid rgba(0,120,168,0.25);  }
.badge-para-lavar    { background: rgba(0,120,168,0.1);    color: #0078A8; border: 1px solid rgba(0,120,168,0.25);  }
.badge-info          { background: rgba(0,120,168,0.1);    color: #0078A8; border: 1px solid rgba(0,120,168,0.25);  }

/* Ambar/Naranja #E89010 -- atencion / intermedio: ListaEntrega, EnReparacion, Urgente, Warning */
.badge-lista-entrega { background: rgba(232,144,16,0.12);  color: var(--orange-text-on-tint); border: 1px solid rgba(232,144,16,0.3);  }
.badge-lista         { background: rgba(232,144,16,0.12);  color: var(--orange-text-on-tint); border: 1px solid rgba(232,144,16,0.3);  }
.badge-en-reparacion { background: rgba(232,144,16,0.12);  color: var(--orange-text-on-tint); border: 1px solid rgba(232,144,16,0.3);  }
.badge-reparacion    { background: rgba(232,144,16,0.12);  color: var(--orange-text-on-tint); border: 1px solid rgba(232,144,16,0.3);  }
.badge-warning       { background: rgba(232,144,16,0.12);  color: var(--orange-text-on-tint); border: 1px solid rgba(232,144,16,0.3);  }

/* Rojo #DC2626 -- negativo / cancelado: Anulada, Critica, Baja, Activa (sin atender) */
.badge-baja          { background: rgba(220,38,38,0.1);    color: #DC2626; border: 1px solid rgba(220,38,38,0.25);  }
.badge-anulada       { background: rgba(220,38,38,0.1);    color: #DC2626; border: 1px solid rgba(220,38,38,0.25);  }
.badge-activa        { background: rgba(220,38,38,0.1);    color: #DC2626; border: 1px solid rgba(220,38,38,0.25);  }
.badge-critical      { background: rgba(220,38,38,0.1);    color: #DC2626; border: 1px solid rgba(220,38,38,0.25);  }

/* ── State rows (loading / error / empty) ──────────────────── */
.state-row { display: flex; align-items: center; gap: 10px; padding: 32px 20px; color: var(--text-muted); font-size: 14px; background: var(--bg-primary); border-radius: var(--radius-lg); border: 1px solid var(--border); }
.state-error { color: var(--color-danger); background: rgba(220,38,38,0.04); border-color: rgba(220,38,38,0.2); }
.state-empty { color: var(--text-muted); }
/* ⚠️ NO existe `.state-loading`, y es a proposito (barrido de `①h`, 2026-08-25).
   La familia tiene `.state-error` y `.state-empty`; el estado "cargando" se
   expresa con `.state-row` mas el spinner, y asi esta en 36 sitios contra 8 que
   agregaban un `.state-loading` que NUNCA tuvo regla. Se quito el modificador en
   vez de inventarle un estilo: el patron son los 36. */
.loading-spinner-sm { width: 20px; height: 20px; border: 2px solid var(--border); border-top-color: var(--color-primary); border-radius: 50%; animation: spin 0.7s linear infinite; flex-shrink: 0; }

/* Agrupa un contador con su etiqueta —«12 · A tiempo»— en la banda de plazos del
   tablero. Se usaba en 3 sitios SIN estar definida (barrido de `①h`, 2026-08-25).
   ⭐ Aca se DEFINIO en vez de quitarse, al reves que `.state-loading`: el nombre
   promete un agrupamiento real y `nowrap` es lo que evita que el numero se separe
   de su etiqueta cuando la banda se angosta. */
.deadline-counter { display: inline-flex; align-items: center; white-space: nowrap; }

/* ── Modal ─────────────────────────────────────────────────── */
.modal-overlay {
  position: fixed; inset: 0;
  background: rgba(26,48,96,0.45);
  display: flex; align-items: center; justify-content: center;
  z-index: 1000;
  padding: 20px;
  animation: fadeIn 0.15s ease;
}
.modal-dialog {
  position: relative;
  pointer-events: auto;
  background: var(--bg-primary);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  width: 100%; max-width: 520px;
  max-height: 90vh; overflow-y: auto;
  animation: slideUp 0.2s ease;
}
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes slideUp { from { transform: translateY(16px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
.modal-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 18px 24px 16px;
  border-bottom: 1px solid var(--border);
}
.modal-title { font-size: 16px; font-weight: 700; color: var(--text-primary); }
.modal-close { background: none; border: none; color: var(--text-muted); font-size: 16px; padding: 4px; border-radius: var(--radius-sm); transition: color 0.15s; }
.modal-close:hover { color: var(--text-primary); }
.modal-body { padding: 20px 24px; }
.modal-footer { padding: 16px 24px; border-top: 1px solid var(--border); display: flex; justify-content: flex-end; gap: 10px; }

/* ── Custom Select Dropdown ─────────────────────────────────── */
.custom-select { position: relative; }
.custom-select-trigger {
  display: flex; align-items: center; justify-content: space-between;
  padding: 6px 12px; min-height: 38px;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--bg-primary); cursor: pointer;
  font-size: 14px; color: var(--text-primary); user-select: none;
  transition: border-color 0.15s;
}
.custom-select-trigger:hover { border-color: #adb5bd; }
.custom-select.csd-disabled .custom-select-trigger {
  background: #f8f9fa; color: var(--text-muted); cursor: not-allowed; pointer-events: none;
}
.custom-select.is-invalid .custom-select-trigger { border-color: #dc3545; }
.csd-placeholder { color: var(--text-muted); }
.csd-chevron { font-size: 12px; color: var(--text-muted); flex-shrink: 0; margin-left: 8px; }
.custom-select-opts {
  list-style: none; padding: 4px 0; margin: 1px 0 0;
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--bg-primary); box-shadow: 0 4px 12px rgba(0,0,0,0.12);
  max-height: 180px; overflow-y: auto;
}
.custom-select-opts li {
  padding: 8px 12px; cursor: pointer; font-size: 14px; color: var(--text-primary);
  transition: background 0.1s;
}
.custom-select-opts li:hover { background: var(--bg-secondary); }
.csd-placeholder-opt { color: var(--text-muted) !important; }
.csd-selected { color: var(--navy); font-weight: 600; }

/* ── Form helpers ──────────────────────────────────────────── */
.form-group { margin-bottom: 14px; }
.form-group .form-label { font-size: 12px; font-weight: 600; color: var(--text-secondary); margin-bottom: 5px; display: block; }
.form-row-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }

/* ── Items checklist (dispatch modal) ─────────────────────── */
.items-checklist {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  max-height: 220px;
  overflow-y: auto;
}
.items-checklist-header {
  padding: 8px 12px;
  background: var(--bg-secondary);
  border-bottom: 1px solid var(--border);
  font-size: 13px;
  font-weight: 500;
}
.check-label {
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  user-select: none;
}
.check-label input[type="checkbox"] { flex-shrink: 0; width: 15px; height: 15px; cursor: pointer; }
.check-label-item {
  padding: 7px 12px;
  border-bottom: 1px solid var(--border);
  font-size: 13px;
}
.check-label-item:last-child { border-bottom: none; }
.check-label-item:hover { background: var(--bg-accent); }
/* Prenda ya comprometida en otro lote pendiente (ADR-021, ajuste de UX de
   armado) -- se muestra pero no se puede seleccionar. */
.check-label-item.is-disabled { cursor: default; opacity: 0.6; }
.check-label-item.is-disabled:hover { background: none; }
.check-label-item.is-disabled input[type="checkbox"] { cursor: not-allowed; }

/* Subtitulo de grupo dentro del checklist (Paso 4, Lote B -- agrupar por tipo
   de lavado efectivo). Mismo tono que .items-checklist-header pero mas chico,
   para distinguir "encabezado de la lista" de "encabezado de un grupo". */
.items-checklist-group-title {
  padding: 5px 12px;
  background: var(--bg-secondary);
  border-bottom: 1px solid var(--border);
  font-size: 12px;
  font-weight: 600;
  color: var(--text-muted);
}

/* ── Dispatch groups (ADR-028 Fase 1 -- un despacho por destino) ──── */
.dispatch-group-card {
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 14px;
  margin-bottom: 14px;
}
.dispatch-group-title {
  font-size: 14px;
  font-weight: 700;
  color: var(--text-primary);
  margin-bottom: 8px;
}

/* ── Sticker preview (ADR-028 Fase 2 -- solo previsualizacion, sin impresion) ── */
.sticker-preview-card {
  border: 1px dashed var(--border);
  border-radius: var(--radius-md);
  padding: 12px 14px;
  background: var(--bg-secondary);
  max-width: 320px;
}
.sticker-preview-title {
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-muted);
  margin-bottom: 8px;
}
.sticker-preview-row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  font-size: 13px;
  padding: 3px 0;
}
.sticker-preview-row span { color: var(--text-muted); }

/* ── Inline alert ──────────────────────────────────────────── */
.alert-error { padding: 10px 14px; background: rgba(220,38,38,0.07); border: 1px solid rgba(220,38,38,0.25); border-radius: var(--radius-md); color: var(--color-danger); font-size: 13px; }
.alert-success { padding: 10px 14px; background: rgba(90,148,0,0.08); border: 1px solid rgba(90,148,0,0.25); border-radius: var(--radius-md); color: #4a7a00; font-size: 13px; }
/* Mismos valores de color que .badge-warning (ambar/naranja de la paleta) --
   advertencia, no error: "puedes continuar", por eso no reutiliza el rojo. */
.alert-warning { padding: 10px 14px; background: rgba(232,144,16,0.12); border: 1px solid rgba(232,144,16,0.3); border-radius: var(--radius-md); color: var(--orange-text-on-tint); font-size: 13px; }
/* Banner de comanda completa (ADR-028 Fase 2c) -- deliberadamente mas
   llamativo que .alert-success: es el disparador de una accion fisica
   (precintar el bulto), no puede leerse como un mensaje mas. */
.alert-complete { padding: 14px 18px; background: var(--brand-navy); border: 1px solid var(--brand-navy); border-radius: var(--radius-md); color: #FFFFFF; font-size: 15px; font-weight: 600; }

/* ── Detail page ───────────────────────────────────────────── */
.breadcrumb-bar { font-size: 13px; color: var(--text-muted); margin-bottom: 16px; }
.breadcrumb-bar a { color: var(--text-accent); text-decoration: none; }
.breadcrumb-bar a:hover { text-decoration: underline; }
.action-bar { display: flex; gap: 10px; align-items: center; }
.order-meta { display: flex; flex-wrap: wrap; gap: 20px; margin-top: 6px; }
.order-meta-item { display: flex; gap: 6px; align-items: center; font-size: 13px; color: var(--text-secondary); }
.order-meta-item strong { color: var(--text-primary); }
.detail-section { margin-top: 20px; }

/* ── Misc ──────────────────────────────────────────────────── */
.font-mono { font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.02em; }
.text-muted-sm { font-size: 12px; color: var(--text-muted); }

/* ── Arbol de zonas (ADR-024, Paso 2) — solo tipografia/espaciado, sin color de fondo (reservado al Paso 3) */
.tree-guide { font-family: var(--font-mono); font-size: 15px; letter-spacing: 0.5px; color: #0078A8; font-weight: 600; white-space: pre; }

/* ── Barra de contexto de SITIO (ADR-048) ──────────────────────
   🔴 Navy SOLIDO a proposito. Al volverse implicito el sitio, esta barra es la
   unica señal de contexto que le queda al usuario -- con el desplegable, el
   sabia donde estaba porque lo habia elegido. Tiene que ser imposible de
   confundir con un filtro: un contexto que se lee como filtro invita a
   cambiarlo, y no hay nada que cambiar.
   ⚠️ .tree-site-header quedo eliminada: era esta misma linea en gris. */
.site-context {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  background: var(--color-primary); color: var(--text-on-primary);
  border-radius: 6px; padding: 9px 14px; margin-bottom: 12px;
}
.site-context-icon { font-size: 15px; opacity: 0.85; }
/* El Code primero, en mono: es el prefijo de 7S-CARC-PDA-01 y lo que se teclea
   en soporte. El nombre largo es para leer; el codigo es para operar. */
.site-context-code {
  font-family: var(--font-mono); font-weight: 700; font-size: 13.5px;
  letter-spacing: 0.06em;
}
.site-context-name { font-weight: 600; font-size: 14px; }
.site-context-detail { margin-left: auto; font-size: 12.5px; opacity: 0.8; }
.site-context-warn {
  font-size: 11.5px; font-weight: 600; background: rgba(255,255,255,0.18);
  border-radius: 4px; padding: 2px 8px;
}

/* Variante de bajo peso para DENTRO de modales, donde el navy solido competiria
   con el titulo del modal. Misma informacion, otro peso. */
.site-context-compact {
  background: var(--bg-accent); color: var(--text-primary);
  border-left: 3px solid var(--brand-teal);
  border-radius: 4px; padding: 7px 12px; margin-bottom: 0;
}
.site-context-compact .site-context-icon { color: var(--brand-teal); opacity: 1; }
.site-context-compact .site-context-warn {
  background: rgba(0,120,168,0.12); color: var(--brand-teal);
}

/* ── Chip de color de clasificacion (ADR-024, Paso 3). Solido = color propio
   de la zona; punteado = heredado del ancestro mas cercano. El color real
   siempre viene por style inline (hex del catalogo del tenant) -- estas
   clases solo definen la forma/trazo, nunca inventan un color decorativo. */
.color-chip { display: inline-block; width: 12px; height: 12px; border-radius: 50%; margin-left: 8px; vertical-align: middle; }
.color-chip-own { border: 1px solid rgba(0,0,0,0.15); }
.color-chip-inherited { background: transparent; border-width: 2px; border-style: dashed; }

/* ── Blazor error UI ───────────────────────────────────────── */
#blazor-error-ui {
  color-scheme: light only;
  background: #fff3cd;
  border-top: 1px solid #ffc107;
  bottom: 0;
  box-sizing: border-box;
  display: none;
  left: 0;
  padding: 0.6rem 1.25rem 0.7rem 1.25rem;
  position: fixed;
  width: 100%;
  z-index: 2000;
  font-size: 13px;
}

#blazor-error-ui .dismiss {
  cursor: pointer;
  position: absolute;
  right: 0.75rem;
  top: 0.5rem;
}

/* `.reload` se usaba en `MainLayout` y NO estaba definida (barrido de `①h`,
   2026-08-25) — su hermana `.dismiss`, dos lineas arriba, si lo estaba.
   ⚠️ `color: inherit` en vez de un token de la paleta A PROPOSITO: esta barra
   aparece cuando el circuito de Blazor ya se cayo, y tiene que leerse aunque el
   resto de los estilos no hayan cargado. Hereda el color del propio aviso, que
   es lo unico garantizado sobre este amarillo. */
#blazor-error-ui .reload {
  color: inherit;
  text-decoration: underline;
  cursor: pointer;
}

/* ── Validation helpers ────────────────────────────────────── */
.valid.modified:not([type=checkbox]) { outline: 1px solid var(--color-success); }
.invalid { outline: 1px solid var(--color-danger); }
.validation-message { color: var(--color-danger); font-size: 12px; margin-top: 4px; }

.blazor-error-boundary {
  background: #b32121;
  padding: 1rem 1rem 1rem 3.7rem;
  color: white;
}

/* ── Catálogos ─────────────────────────────────────────────── */
.color-swatch {
  display: inline-block;
  width: 20px;
  height: 20px;
  border-radius: 4px;
  border: 1px solid rgba(0,0,0,0.12);
  flex-shrink: 0;
}
.color-swatch-empty {
  background: repeating-linear-gradient(45deg, #f0f0f0, #f0f0f0 3px, #ddd 3px, #ddd 6px);
}

.color-hex-row {
  display: flex;
  gap: 10px;
  align-items: center;
}
.color-picker-input {
  width: 44px;
  height: 38px;
  padding: 2px 3px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  cursor: pointer;
  flex-shrink: 0;
  background: transparent;
}

.form-hint {
  font-size: 11px;
  color: var(--text-muted);
  margin-top: 4px;
}

/* ══════════════════════════════════════════════════════════════════
   Pantallas operativas (Recepción / Clasificación / Retiro) — acento
   de color por proceso, aplicado con criterio: encabezado de página,
   ícono, borde inferior del botón primario, bordes de tarjeta/fila
   activa. El navy sigue siendo la estructura (nav, tipografía, texto);
   el acento nunca reemplaza fondos de texto completos. Embrión visual
   del kiosko táctil (ADR-013) -- sin construir el sistema de tiles.
   Clases compartidas por las 3 páginas, definidas una sola vez aquí.
   ══════════════════════════════════════════════════════════════════ */
/* ⭐⭐ OPERACIÓN — UN SOLO ACENTO PARA LAS CINCO PANTALLAS DE PISO
   (decisión de Manuel, 2026-07-31). Recepción, Clasificación, Despachos, Retiro
   y Preparar colecta comparten identidad: el operario trabaja en naranja.

   🔴 ANTES ERAN TRES ACENTOS DISTINTOS (verde / teal / naranja), uno por
   proceso. El corte ya no es "qué proceso es" sino "quién está usando la
   pantalla": operar vs. administrar. Es el mismo corte que el Kiosko va a
   necesitar (ADR-026), heredado en vez de inventado.

   ⚠️ El ícono usa #D4600E directo y no una variante oscura: con blanco encima
   da 3,83:1 — suficiente para un elemento gráfico de 44px con glifo de 20px
   (umbral 3:1), que es lo que es. El color está decidido; lo que se ajusta si
   hace falta es el texto, nunca el color. */
.op-page.accent-operation      { --op-accent: var(--orange-module); --op-accent-bg: rgba(212,96,14,0.10); --op-accent-icon-bg: var(--orange-module);    --op-accent-text: var(--orange-text-on-tint); }

/* ⚠️ accent-retiro SE CONSERVA y NO se toca: lo usan `lavado-externo` y
   `trazabilidad`, que viven en GESTIÓN, no en Operación. Redefinirlo las habría
   pintado de naranja de operación en silencio -- justo lo contrario de la
   decisión, que deja Gestión y Administración en navy. Siguen con el naranja
   SEMÁNTICO (#E89010) que ya tenían. */
.op-page.accent-retiro         { --op-accent: var(--brand-orange); --op-accent-bg: rgba(232,144,16,0.1);  --op-accent-icon-bg: var(--brand-orange-dark); --op-accent-text: var(--orange-text-on-tint); }

/* Administración/gestión -- mismo navy que ya es la estructura del resto
   de la app (nav, botones primarios). El acento aquí no distingue una
   pantalla de otra: distingue el ROL (operar vs. administrar). */
.op-page.accent-admin          { --op-accent: var(--brand-navy);   --op-accent-bg: rgba(32,64,128,0.07);  --op-accent-icon-bg: var(--brand-navy);        --op-accent-text: var(--brand-navy); }

/* Alertas -- caso aparte: es señal, no proceso ni administración. Se usa
   con restricción máxima (solo ícono + fondo tenue del encabezado, nunca
   repartido por la pantalla). Rojo solo si hay algo que señalar (alertas
   Activa); si no hay ninguna, la pantalla cae a navy como el resto de
   administración -- decidido en la propia página (Alerts.razor), acá solo
   se definen los dos juegos de variables. */
.op-page.accent-danger         { --op-accent: var(--color-danger); --op-accent-bg: rgba(220,38,38,0.08);  --op-accent-icon-bg: var(--color-danger);      --op-accent-text: var(--color-danger); }

/* Encabezado = banda de CONTEXTO ("estás en Recepción"), no una tarjeta
   clickeable -- fondo tenue del acento, sin borde de color (el fondo ya
   comunica el proceso, un borde encima era redundante). Las tarjetas de
   acción (.op-choice-card) se quedan blancas para "flotar" por contraste. */
.op-page-header {
  display: flex;
  align-items: center;
  gap: 14px;
  /* ⭐⭐ C (2026-08-25): 16/22 -> 10/14. Reportado por Manuel usando la
     pantalla: antes del primer campo util habia ~383 px, mas de media pantalla
     en su notebook, y esta cabecera aportaba 98. */
  padding: 10px 20px;
  margin-bottom: 14px;
  background: var(--op-accent-bg, var(--bg-primary));
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}
/* Ícono invertido: cuadrito SOLIDO del acento + glifo blanco -- ancla
   visual del encabezado. Retiro usa --brand-orange-dark (ya en la paleta)
   en vez de --brand-orange crudo: el naranja de marca con blanco encima
   no llega a un contraste comodo para un cuadrito de este tamaño. */
.op-page-icon {
  width: 44px; height: 44px;
  border-radius: var(--radius-md);
  display: flex; align-items: center; justify-content: center;
  font-size: 20px;
  flex-shrink: 0;
  background: var(--op-accent-icon-bg, var(--brand-navy));
  color: #fff;
}
.op-page-header .page-title { margin-bottom: 3px; }
.op-page-header .page-subtitle { margin-bottom: 0; }

/* Agrupa ícono + título/subtítulo y crece para empujar los botones de
   acción del encabezado (ej. "Nuevo") al borde derecho de la banda --
   solo hace falta en pantallas que tienen un boton ahi (la mayoria de
   Administración/Catálogos); Recepción/Clasificación/Retiro no lo usan
   porque no tienen boton en el encabezado. */
.op-page-header-main { display: flex; align-items: center; gap: 14px; flex: 1; min-width: 0; }

/* Respiro consistente entre bloques (identificación / lista / formulario) */
.op-page .table-card { margin-bottom: 20px; }
.op-page .table-card:last-child { margin-bottom: 0; }

/* Encabezado de sección con peso propio -- no se lee como texto corrido */
.op-section-title {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-secondary);
  margin-bottom: 10px;
}
.op-section-title .bi { color: var(--op-accent, var(--brand-navy)); font-size: 14px; }

/* Tarjeta donde vive la acción final de la pantalla (confirmar/clasificar/
   retirar) -- un borde superior con el acento marca "acá se cierra". */
.op-page .op-action-card { border-top: 3px solid var(--op-accent, var(--brand-navy)); }

/* ── Asistente por pasos (2026-08-04) ────────────────────────────────────────
   ⚠️ NO existía un stepper en el repo -- se buscó antes de escribirlo. Este es
   el mínimo que responde "¿en cuál voy?": una fila de chips donde el actual se
   marca y los ya recorridos quedan con su número lleno.

   ⭐ Toma `--op-accent`, así que hereda el color de la página: navy en
   `accent-admin`, y si mañana lo usa una pantalla operativa se pinta naranja
   sola, sin tocar esta regla. El gris queda para lo NO recorrido, que es lo
   inactivo -- no para la acción, que siempre lleva color. */
/* ⭐⭐ LA BARRA DEL ASISTENTE — pasos a la izquierda, navegación a la derecha
   (2026-08-04).

   🔴 Existe para que los botones NO CAMBIEN DE POSICIÓN entre pasos. Vivían al
   final del contenido, y como cada paso tiene distinta cantidad de campos, el
   botón se corría verticalmente: el clic de "Siguiente" caía sobre el campo que
   había quedado debajo. Anclarlos al stepper lo resuelve POR CONSTRUCCIÓN --el
   stepper muestra siempre los mismos tres chips, así que su alto no depende del
   paso.

   ⚠️ `flex-wrap` a propósito: en francés y portugués las etiquetas son largas
   ("Données opérationnelles"), y si no entran, la fila de botones baja a su
   propia línea. ⭐ Eso NO reintroduce el defecto: el stepper es idéntico en los
   tres pasos, así que si envuelve, envuelve igual en los tres -- la posición
   sigue siendo invariante. */
.wf-wizard-bar { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; margin-bottom: 18px; }
.wf-wizard-bar > .wf-steps { margin-bottom: 0; }
/* `margin-left:auto` empuja el grupo al borde derecho. ⭐ La acción que avanza
   queda pegada a ese borde y NO se mueve cuando "Atrás" aparece o desaparece a
   su izquierda -- que es la que se pulsa en los tres pasos. */
.wf-wizard-actions { display: flex; gap: 8px; margin-left: auto; flex-wrap: wrap; }

.wf-steps { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 18px; }
.wf-step {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 14px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--bg-secondary);
  color: var(--text-secondary); font-size: 13px; font-weight: 500;
}
.wf-step-num {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; border-radius: 50%;
  font-size: 11px; font-weight: 700;
  background: var(--border); color: var(--text-secondary);
}
.wf-step.is-current {
  border-color: var(--op-accent, var(--brand-navy));
  background: var(--op-accent-bg, rgba(32, 64, 128, 0.07));
  color: var(--op-accent-text, var(--brand-navy));
}
.wf-step.is-current .wf-step-num,
.wf-step.is-done .wf-step-num { background: var(--op-accent, var(--brand-navy)); color: #fff; }

/* Botón de acción primaria: se mantiene navy solido (contraste garantizado
   con texto blanco -- el verde y el naranja de marca NO pasan WCAG AA con
   texto blanco encima, ver discusión de accesibilidad) y suma el acento
   como borde inferior en vez de relleno. */
.op-page .btn-wf-primary { border-bottom: 3px solid var(--op-accent, var(--brand-navy)); }

/* ── Bifurcación de Recepción: dos caminos, no dos ítems de una lista ── */
.op-choice-grid { display: flex; gap: 16px; flex-wrap: wrap; }
.op-choice-card {
  flex: 1;
  min-width: 260px;
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 22px 24px;
  text-align: left;
  background: var(--bg-primary);
  border: 2px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  cursor: pointer;
  transition: border-color 0.15s, box-shadow 0.15s, transform 0.1s;
}
.op-choice-card:hover { box-shadow: var(--shadow-md); transform: translateY(-1px); }
.op-choice-icon {
  width: 56px; height: 56px;
  border-radius: var(--radius-md);
  display: flex; align-items: center; justify-content: center;
  font-size: 26px;
  flex-shrink: 0;
}
.op-choice-title { font-size: 17px; font-weight: 700; color: var(--text-primary); margin-bottom: 4px; }
.op-choice-subtitle { font-size: 12.5px; color: var(--text-muted); font-weight: 400; line-height: 1.4; }

/* Personal / Institucional -- dos matices dentro de la familia verde de
   Recepción (siguen siendo el mismo proceso, se gradúan, no se sacan). */
.op-choice-personal { border-color: rgba(90,148,0,0.45); }
.op-choice-personal:hover { border-color: var(--brand-green); }
.op-choice-personal .op-choice-icon { background: rgba(90,148,0,0.16); color: #4a7a00; }

.op-choice-institutional { border-color: rgba(90,148,0,0.22); }
.op-choice-institutional:hover { border-color: rgba(90,148,0,0.6); }
.op-choice-institutional .op-choice-icon { background: rgba(90,148,0,0.08); color: var(--brand-green); }

/* Zona (malla, ADR-039) -- tercer matiz de la MISMA familia verde: sigue
   siendo Recepción, no un proceso distinto. El matiz mas tenue de los tres,
   por ser el camino menos frecuente. */
.op-choice-zone { border-color: rgba(90,148,0,0.15); }
.op-choice-zone:hover { border-color: rgba(90,148,0,0.5); }
.op-choice-zone .op-choice-icon { background: rgba(90,148,0,0.06); color: var(--brand-green); }

/* ── ADR-039 R4 — jerarquía visual del modo Zona ──────────────────────────
   Tres pesos distintos para tres roles distintos: lo que el operador HACE,
   lo que solo CONFIRMA, y lo que puede IGNORAR. El objetivo es que en el
   camino normal el operador escanee y escriba un número — nada más. */

/* 1. Lo que el operador hace: destacado. */
.op-zone-primary {
    background: rgba(90,148,0,0.05);
    border: 1px solid rgba(90,148,0,0.25);
    border-radius: 8px;
    padding: 16px;
}
.op-zone-primary-label { font-size: 15px; font-weight: 600; }
/* Input grande: el operador lo teclea con guantes y apuro. */
.op-zone-count-input {
    font-size: 30px;
    font-weight: 600;
    height: 64px;
    max-width: 200px;
    text-align: center;
}

/* 2. Datos derivados: se leen, no se tocan. Atenuados a propósito. */
.op-zone-derived {
    background: var(--surface-muted, rgba(0,0,0,0.02));
    border-radius: 8px;
    padding: 12px 16px;
}
.op-zone-derived-title {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted);
    margin-bottom: 6px;
}
.op-zone-derived-row {
    display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap;
    font-size: 13.5px; padding: 2px 0;
}

/* 3. Opcional: <details> nativo, cerrado por default. Cero JS. */
.op-zone-optional > summary {
    cursor: pointer;
    font-size: 13px;
    color: var(--text-muted);
    padding: 6px 0;
    user-select: none;
}
.op-zone-optional > summary:hover { color: var(--brand-green); }

/* ── Fila tildada / incluida en el checklist -- se nota mas que el checkbox ── */
.check-label-item.is-checked {
  background: rgba(90,148,0,0.07);
  border-left: 3px solid var(--brand-green);
  padding-left: 9px;
}

/* ── Aviso que no bloquea (Amarillo #D4B800) -- ej. "esta prenda ya estaba
   clasificada". Clase nueva y separada de .alert-warning/.badge-warning
   (naranja, ya usadas en Clasificación/Despachos/Detalle de orden) para no
   reinterpretar su significado ahí -- ver gramática de color en CLAUDE.md. */
.alert-notice { padding: 10px 14px; background: rgba(212,184,0,0.13); border: 1px solid rgba(212,184,0,0.4); border-radius: var(--radius-md); color: #7a6800; font-size: 13px; }
.badge-notice { background: rgba(212,184,0,0.16); color: #7a6800; border: 1px solid rgba(212,184,0,0.4); }

/* ── Atención (Naranja #E89010) -- requiere una decisión del operador,
   no es una falla del sistema: prenda de otro dueño, estado incompatible. ── */
.alert-attention { padding: 10px 14px; background: rgba(232,144,16,0.1); border: 1px solid rgba(232,144,16,0.3); border-radius: var(--radius-md); color: var(--orange-text-on-tint); font-size: 13px; }

/* ═══════════════════════════════════════════════════════════════════════════
   ⭐⭐⭐ EL AVISO QUE **BLOQUEA**, separado del que solo INFORMA (2026-08-15).

   🔴 EL DEFECTO: en «Recibir de la lavandería» convivían cuatro avisos en el
   MISMO ámbar y con la MISMA forma —dos que impiden trabajar y dos que solo
   informan—. **El problema no era que uno se viera poco: era que cosas
   distintas se veían iguales**, y darle más color a uno solo habría dejado a
   los otros confundiéndose entre sí.

   🔴 NO SE USA EL ROJO, y es decisión de Manuel: `--color-danger` está
   reservado a ERROR, y acá no falló nada — falta un paso anterior. Gastar el
   rojo haría que signifique dos cosas, que es el defecto de la palabra
   "despacho" otra vez.

   ⭐ SE DISTINGUE POR GEOMETRÍA, que se ve en escala de grises: barra izquierda
   de 4 px, tinte un punto más denso y el ícono con más presencia. **Cero
   valores nuevos: el mismo ámbar de la paleta a otra opacidad, y la barra en
   `--orange-module`.**

   ⚠️ CONTRASTES CALCULADOS, no estimados (compuestos sobre blanco):
     · texto `#9A5A00` sobre el ámbar 0.16 → **4,75:1** ✅ AA (4,5)
     · barra `#D4600E` sobre el ámbar 0.16 → **3,33:1** ✅ AA gráfico (3:1)
     · el que informa conserva 0.10 → **5,02:1** ✅
   🔴 Y UNA MEDICIÓN QUE CAMBIÓ EL DISEÑO: bajar el texto del aviso informativo
   a `--text-muted` daba **3,68:1**, POR DEBAJO de AA. Por eso el que informa
   baja de peso por FORMA y conserva su color de texto.
   ═══════════════════════════════════════════════════════════════════════════ */
.alert-blocking {
  padding: 10px 14px 10px 12px;
  background: rgba(232,144,16,0.16);
  border: 1px solid rgba(232,144,16,0.45);
  border-left: 4px solid var(--orange-module);
  border-radius: var(--radius-md);
  color: var(--orange-text-on-tint);
  font-size: 13px;
  font-weight: 500;
}
/* El ícono con más presencia: es la otra mitad de la geometría. */
.alert-blocking .bi { font-size: 15px; }

/* ── Hub de Catálogos (/catalogos) -- tarjetas agrupadas en vez del
   submenú vertical de 12 ítems. El encabezado de PANTALLA sigue navy
   (accent-admin, heredado del wrapper .op-page): es administración. Cada
   GRUPO redefine --op-accent/--op-accent-bg/--op-accent-text localmente
   (las custom properties de CSS cascadean) -- el ícono de cada tarjeta
   toma el color de su grupo, no uno por tarjeta: acá el color agrupa
   categorías (información), no distingue proceso operativo (esa
   gramática -- entrada/intermedio/salida -- sigue exclusiva de
   Recepción/Clasificación/Retiro, no se extiende acá). Tarjetas blancas
   sin borde de color en reposo -- 12 bordes de color sería ruido. */
.catalog-hub-group { margin-bottom: 28px; }
.catalog-hub-group:last-child { margin-bottom: 0; }
.catalog-hub-group.group-attributes { --op-accent: var(--brand-teal);   --op-accent-bg: rgba(0,120,168,0.1);  --op-accent-text: #0078A8; }
.catalog-hub-group.group-processes  { --op-accent: var(--brand-green);  --op-accent-bg: rgba(90,148,0,0.1);   --op-accent-text: #4a7a00; }
/* ⭐⭐ ENTIDADES pasa al NARANJA DE OPERACIÓN (#D4600E, 2026-08-04).
   Antes usaba `--brand-orange` (#E89010), el ámbar de marca. El cambio NO es de
   matiz: las entidades de negocio --las dueñas de prendas, las que el operario
   toca en el mostrador-- son ENTORNO OPERATIVO, y ese entorno tiene un solo
   naranja, el mismo que Recepción, Clasificación y Retiro. Dos naranjas para la
   misma idea es la forma de que la gramática de color deje de significar algo. */
.catalog-hub-group.group-entities   { --op-accent: var(--orange-module); --op-accent-bg: rgba(212,96,14,0.10); --op-accent-text: var(--orange-text-on-tint); }
/* Tarjetas de CONFIGURACIÓN que viven dentro de Entidades: se quedan NAVY.
   ⭐ El color no sigue a la sección sino a la NATURALEZA de la caja: "Tipos de
   sitio" y "Tipos de dispositivo" se tocan una vez al instalar y no son de
   nadie. Redefinen las custom properties en la propia tarjeta, así que el ícono
   y el borde de hover las toman sin una sola regla extra. */
.catalog-hub-card.card-config { --op-accent: var(--brand-navy); --op-accent-bg: rgba(32,64,128,0.07); --op-accent-text: var(--brand-navy); }
/* ⭐ `card-unclassified` EXISTIÓ Y SE RETIRÓ (2026-08-04). Marcó durante un día a
   "Turnos de rotación" y "Clasificación de población" mientras no se sabía si
   eran negocio o configuración. Manuel las clasificó como NEGOCIO —se cuelgan de
   una persona, no de la instalación— así que heredan el naranja del grupo y la
   clase deja de existir. Se anota el paso para que no se reintroduzca como si
   fuera un color de diseño: era una marca temporal de decisión pendiente. */
/* Hub de Configuración (/configuracion) -- mismas clases .catalog-hub-*.
   Grupo "Infraestructura física" no redefine nada: hereda el navy de
   accent-admin, que ya es su color asignado. Grupo "Acceso y captura" sí
   redefine a teal. */
.catalog-hub-group.group-access     { --op-accent: var(--brand-teal);   --op-accent-bg: rgba(0,120,168,0.1);  --op-accent-text: #0078A8; }
/* Encabezado de grupo -- toma el color del grupo, sutil (mismo texto que
   ya usan los badges de esa familia, no el hex crudo de marca). */
.catalog-hub-group > .section-title { color: var(--op-accent-text, var(--text-primary)); }
.catalog-hub-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 14px;
  margin-top: 12px;
}
.catalog-hub-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 18px;
  box-shadow: var(--shadow-sm);
  text-decoration: none;
  color: inherit;
  transition: border-color 0.15s, box-shadow 0.15s, transform 0.1s;
}
.catalog-hub-card:hover {
  border-color: var(--op-accent, var(--brand-navy));
  box-shadow: var(--shadow-md);
  transform: translateY(-1px);
  text-decoration: none;
}
.catalog-hub-icon {
  width: 40px; height: 40px;
  border-radius: var(--radius-md);
  display: flex; align-items: center; justify-content: center;
  font-size: 18px;
  flex-shrink: 0;
  background: var(--op-accent-bg, var(--bg-accent));
  color: var(--op-accent, var(--brand-navy));
}
.catalog-hub-name { font-size: 14px; font-weight: 700; color: var(--text-primary); }
.catalog-hub-desc { font-size: 12px; color: var(--text-muted); line-height: 1.4; }

/* ═══════════════════════════════════════════════════════════════════════════
   ⭐⭐⭐ LOS TRES CICLOS DE OPERACION (frente 1u, 2026-08-14)

   El menu listaba OCHO funciones sueltas sin decir en que momento del ciclo
   ocurre cada una. "¿Cuando se verifica bolsa? Ya me perdi" -- lo dijo Manuel,
   que disenio el sistema. Ahora son TRES CICLOS en el orden en que ocurren.

   ⭐⭐ RECONCILIACION **VALIDADA POR MANUEL el 2026-08-14**, no una decision
   unilateral de quien la escribio. Tambien esta en `ESTADO-REAL-ADRS.md`, para
   que dentro de tres meses no se lea como una deriva.

   ── 🔴 COMO CONVIVE CON EL NARANJA UNICO DE OPERACION (decision del 31/07) ──

   Aquella decision retiro "tres acentos distintos, uno por proceso" porque el
   corte pasaba a ser QUIEN USA la pantalla (operar vs. administrar), no que
   proceso es. ⚠️ Reintroducir color por proceso seria volver atras.

   ⭐ NO SE VUELVE ATRAS, porque el color de ciclo vive en OTRO NIVEL:
     · las PANTALLAS de trabajo siguen en `.op-page.accent-operation` (naranja
       de rol). **No se toca ninguna.**
     · el color de CICLO vive solo en las TRES HOJAS de navegacion, que son un
       nivel que antes no existia.
   ⭐ El precedente esta construido y vivo: `.catalog-hub-group` agrupa con
   teal/verde/naranja DENTRO de Catalogos, que es navy. Mismo mecanismo.

   ── 🔴 CONTRASTES CALCULADOS, NO ESTIMADOS (2026-08-14) ─────────────────────

   Texto sobre el tinte del ciclo, con `--text-primary` #1A3060:
     tinte verde   #EEF4E6 -> 11,44:1   AA
     tinte naranja #FBEFE7 -> 11,37:1   AA
     tinte teal    #E6F2F6 -> 11,25:1   AA

   ⚠️ POR ESO EL TITULO NO VA EN EL COLOR DEL CICLO, y no es estetica:
   el teal de marca sobre su propio tinte da **4,33:1**, POR DEBAJO del 4,5:1
   que pide AA para texto normal -- el mismo caso ya registrado en CLAUDE.md
   para `--bg-accent`. El verde de marca sobre su tinte da 3,3:1, peor.
   🔴 Llevarlos a AA exigiria un teal #005E84 que NO EXISTE en la paleta, y los
   tokens no se inventan al pasar. ⭐ La salida usa lo que ya hay: el texto va
   en navy (11,2:1 en los tres) y **el color queda en lo GRAFICO** -- icono,
   borde y fondo -- donde el umbral es 3:1 y los tres pasan.

   ── LA REGLA DE CANTIDAD SE RESPETA ────────────────────────────────────────
   ⭐ Las tarjetas de ciclo son NAVEGACION, no accion: reusan `.op-choice-card`,
   que no es solida. Estas hojas NO agregan ni un solo `btn-wf-operation`.
   ═══════════════════════════════════════════════════════════════════════════ */

.op-page.accent-ciclo-recepcion { --op-accent: var(--brand-green);   --op-accent-bg: rgba(90,148,0,0.10);  --op-accent-icon-bg: var(--brand-green);   --op-accent-text: var(--text-primary); }
.op-page.accent-ciclo-lavandero { --op-accent: var(--orange-module); --op-accent-bg: rgba(212,96,14,0.10); --op-accent-icon-bg: var(--orange-module); --op-accent-text: var(--text-primary); }
.op-page.accent-ciclo-entrega   { --op-accent: var(--brand-teal);    --op-accent-bg: rgba(0,120,168,0.10); --op-accent-icon-bg: var(--brand-teal);   --op-accent-text: var(--text-primary); }

/* La banda de contexto de la hoja: fondo de tinte y una barra del color del
   ciclo a la izquierda. ⭐ El texto va en navy -- ver el calculo de arriba. */
.ciclo-banda {
  background: var(--op-accent-bg);
  border-left: 4px solid var(--op-accent);
  border-radius: 8px;
  padding: 14px 16px;
  margin-bottom: 20px;
}
.ciclo-banda-texto { font-size: 13.5px; color: var(--text-primary); line-height: 1.5; }

/* ⭐ El dato que NO es navegacion: se ve como texto, nunca como boton, para no
   invitar a un clic que no lleva a ninguna parte (el caso de Localizacion,
   que vive en la pistola). */
.ciclo-nota {
  display: flex; align-items: flex-start; gap: 8px;
  margin-top: 12px; padding-top: 12px;
  border-top: 1px dashed var(--border);
  font-size: 12.5px; color: var(--text-muted); line-height: 1.45;
}
.ciclo-nota .bi { color: var(--op-accent); flex-shrink: 0; margin-top: 1px; }

/* Las tarjetas del ciclo heredan `.op-choice-card`; solo se les da el color
   del ciclo en el icono y en el borde de hover. */
.ciclo-card .op-choice-icon { background: var(--op-accent-bg); color: var(--op-accent); }
.ciclo-card { border-color: var(--border); }
.ciclo-card:hover { border-color: var(--op-accent); }

/* ⭐ EL CONTADOR ES CONTENIDO, NO ACCION (punto ③ de la regla de cantidad):
   una cifra sobre tinte, nunca un boton. Solo aparece donde hay TRABAJO
   ACUMULADO -- ver el criterio en `CicloRecepcion.razor`. */
.ciclo-cola {
  display: inline-block; margin-top: 6px;
  padding: 2px 9px; border-radius: 999px;
  background: var(--op-accent-bg); color: var(--text-primary);
  font-size: 12px; font-weight: 700;
}

/* ═══════════════════════════════════════════════════════════════════════════
   ⭐⭐⭐ LOS TRES CICLOS COMO BLOQUES SOLIDOS EN EL MENU (2026-08-14)

   Tercera version, y las dos anteriores estan medidas: (1) icono de color sobre
   linea navy -- perdia el bloque del mockup. (2) tinte claro con texto oscuro --
   **se veia lavado sobre el navy**, dicho por Manuel mirandolo.
   ⭐ Esta invierte la relacion: **fondo del color FUERTE, texto BLANCO encima**.

   ── 🔴 LOS TRES TONOS SALEN DEL CALCULO, NO DEL GUSTO ──────────────────────

   Blanco sobre cada tono de la paleta (umbral 4,5:1 -- el menu es 13,5 px / 600,
   que **NO es texto grande**, asi que no aplica el 3:1):

     VERDE   #5A9400  --brand-green          3,70:1   ❌
     VERDE   #4A7A00  (ya usado en app.css)  5,15:1   ✅  <- ELEGIDO
     NARANJA #E89010  --brand-orange         2,49:1   ❌
     NARANJA #D4600E  --orange-module        3,83:1   ❌
     NARANJA #C86000  --brand-orange-dark    4,09:1   ❌
     NARANJA #9A5A00  --orange-text-on-tint  5,47:1   ✅  <- ELEGIDO
     TEAL    #0078A8  --brand-teal           4,94:1   ✅  <- ELEGIDO

   ⭐ Los tres elegidos YA EXISTEN: ninguno es un token inventado.
   ⚠️ Y notar que el verde y el naranja de MARCA no llegan: hubo que bajar al
   tono oscuro de cada familia. **El teal si llega con su valor de marca.**

   ── ⚠️ SEPARACION CONTRA EL NAVY, que es la contra de esta version ──────────

   Los bloques quedan entre **1,82:1 y 2,02:1** contra el navy del menu: son
   solidos, pero **poco despegados del fondo**. Por eso llevan borde izquierdo
   del tono BRILLANTE de su familia y un filo claro: la definicion del borde la
   dan ellos, no el contraste del fondo. 🔴 Subir el fondo para despegarlo del
   navy bajaria el contraste del texto blanco, que es lo que no se negocia.

   ── 🔴🔴 EXCEPCION DECLARADA A LA REGLA DE CANTIDAD DEL NARANJA ────────────

   La regla dice **un solo solido naranja visible a la vez**, y acá hay un bloque
   de menu con fondo naranja solido que convive con el `btn-wf-operation` de la
   pantalla. **Se declara acá, en el propio archivo, como la regla exige.**

   ⭐ COMO SE DISTINGUEN, y no es una excusa sino dos ejes medibles:
     · POR TONO: el de accion es `--orange-module` #D4600E (blanco encima:
       3,83:1); el del menu es #9A5A00 (5,47:1). El del menu es **notablemente
       mas oscuro y desaturado** -- no compite en brillo.
     · POR ZONA Y FORMA: el bloque vive en el CROMO PERSISTENTE (el menu, que no
       cambia entre pantallas) y ocupa el ancho con su icono; el solido de accion
       vive en el CONTENIDO y tiene forma de boton.

   ⚠️ LO QUE ESTO **NO** AUTORIZA: que una PANTALLA sume un segundo solido. La
   regla sigue valiendo entera dentro del contenido; lo que se declara es que el
   cromo del menu no cuenta contra ella, **porque es constante**: si contara, no
   habria pantalla que pudiera tener su propia accion.

   ⭐ VERIFICACION: el grep de la regla busca `btn-wf-operation` en las paginas.
   Estos bloques usan `.nav-ciclo` y NO aparecen en ese conteo -- por eso la
   excepcion se escribe acá y no se descubre contando.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── EL BORDE DE DEFINICION ────────────────────────────────────────────────
   ⭐ "Del mismo color que su fondo, pero mas fuerte" (Manuel, 2026-08-14). Se
   consigue con un NEGRO TRANSLUCIDO encima: oscurece EL PROPIO color de cada
   bloque, asi que sirve para los tres sin inventar tres tokens nuevos -- que es
   lo que ya se atajo una vez en este mismo bloque con el `#4FB3D9`.
   🔴 Y resuelve la contra medida de la version anterior: los bloques quedaban a
   1,82-2,02:1 del navy y se veian poco despegados. La definicion la da el borde. */
.nav-ciclo,
.nav-bloque {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 11px 12px;
  margin-bottom: 6px;
  border-radius: var(--radius-md);
  border: 1px solid rgba(0,0,0,0.32);
  border-left: 3px solid rgba(0,0,0,0.32);
  background: var(--ciclo-fondo);
  color: #fff;
  font-size: 13.5px;
  font-weight: 600;
  text-decoration: none;
  transition: filter 0.15s, border-left-width 0.12s;
}
.nav-ciclo:hover,
.nav-bloque:hover { filter: brightness(1.12); text-decoration: none; color: #fff; }

/* ── ⭐⭐⭐ EL SELECCIONADO — TRES SEÑALES, Y SOLO UNA ES DE COLOR ───────────
   🔴 EL REQUISITO, dicho por Manuel: que se note de verdad **y que no dependa
   solo del color, porque un operador daltonico no lo veria**.

   Por eso el activo cambia en TRES ejes independientes:
     ① FORMA    -- la barra izquierda pasa de 3 px a 7 px. Es geometria pura:
                   se ve en escala de grises y a un metro de distancia.
     ② PESO     -- 600 -> 700, y el chevron aparece a la derecha. El chevron es
                   un GLIFO: existe o no existe, no es un matiz.
     ③ LUMINANCIA -- barra y filo en BLANCO sobre el fondo del ciclo. No es
                   "otro color": es contraste de LUZ, que la vision con
                   deficiencia cromatica distingue igual.

   ⭐ Blanco sobre cada fondo, medido -- umbral 3:1 por ser elemento grafico:
        verde   #4A7A00  5,15:1     naranja #9A5A00  5,47:1
        teal    #0078A8  4,94:1
   Los tres pasan incluso el umbral de TEXTO (4,5:1), asi que el chevron y la
   barra se leen con margen.

   ⚠️ EL COLOR DE FONDO NO CAMBIA AL SELECCIONAR, a proposito: el color ES la
   identidad del ciclo. Cambiarlo diria "otro ciclo" en vez de "estas aca". */
.nav-ciclo.active,
.nav-bloque.active {
  border-left-width: 7px;
  border-left-color: #fff;
  border-color: rgba(255,255,255,0.9);
  font-weight: 700;
}
/* ⚠️ EL CHEVRON ES UN `<i class="bi bi-chevron-right">` EN EL MARKUP, NO UN
   `content: "\F285"` ACA. Se escribio primero con el codepoint y se corrigio
   antes de compilar: **los iconos vienen de un CDN** (`App.razor:10`), asi que
   el codepoint no se puede verificar contra el repo. 🔴 Si estuviera mal se
   veria un cuadradito y **no fallaria nada** -- la variante silenciosa de
   inventar un artefacto, en un lenguaje que no protesta. La clase es la API
   publica de la libreria y ya se usa en cincuenta lugares del repo. */
.nav-ciclo-flecha { margin-left: auto; font-size: 13px; color: #fff; }

/* ⚠️ El icono va en blanco y no en el tono brillante: sobre el fondo solido, el
   tono de la familia se pierde contra su propio color. */
.nav-ciclo .bi,
.nav-bloque .bi { color: #fff; font-size: 16px; flex-shrink: 0; }

/* ⚠️⚠️ EL BORDE ES BLANCO TRANSLUCIDO EN LOS TRES, Y NO EL TONO DE MARCA.

   🔴 La primera version de este bloque le puso a cada ciclo el tono brillante de
   su familia -- y para el teal eso pedia un `#4FB3D9` que **NO EXISTE en la
   paleta**. Era un token inventado al pasar, que es justo lo que la regla
   prohibe. Se corrigio antes de compilar.

   ⭐ Y al corregirlo quedo MEJOR: en esta version invertida **el fondo YA es el
   color fuerte**, asi que un borde del mismo color no despega nada. El blanco
   translucido da la definicion que al fondo le falta contra el navy (1,82-2,02:1)
   y es el mismo recurso que `.nav-item.active` ya usa. **Un token menos.** */
.nav-ciclo-recepcion { --ciclo-fondo: var(--nav-recepcion);  }
.nav-ciclo-lavandero { --ciclo-fondo: var(--nav-lavanderia); }
.nav-ciclo-entrega   { --ciclo-fondo: var(--nav-entrega);    }

/* ═══════════════════════════════════════════════════════════════════════════
   ⭐⭐⭐ GESTION Y ADMINISTRACION TAMBIEN SON BLOQUES (2026-08-15).

   ⭐ REUSAN EL MISMO SELECTOR, no una copia: `.nav-bloque` se suma a la regla de
   `.nav-ciclo` mas arriba. Cinco bloques con una sola definicion de forma --
   duplicar el CSS habria sido dos lugares donde el menu puede divergir.

   🔴 EL BORDE SE RESUELVE COMO YA ESTABA RESUELTO, y esto CONTRADICE UN DETALLE
   DEL MOCKUP a proposito. El mockup pedia bordes de tono (#A89600 y #E24B4A);
   este archivo ya tiene escrito por que no se hace: el borde es un NEGRO
   TRANSLUCIDO que oscurece el PROPIO fondo, "asi que sirve para los tres sin
   inventar tres tokens nuevos -- que es lo que ya se atajo una vez con el
   #4FB3D9".
   ⭐ Y la medicion lo respalda: #A89600 sobre #6E6200 da **2,06:1** y #E24B4A
   sobre #A32D2D da **1,8:1** -- separan poco, y costarian dos tokens que solo
   servirian de borde. Con el negro translucido los CINCO bloques quedan
   identicos de forma y el menu se lee como un sistema.
   ⚠️ Se declara acá y se reporta: si Manuel prefiere sus bordes, son dos lineas
   -- pero entonces los tres de Operacion tambien deberian cambiar, o el menu
   queda con dos idiomas de borde.

   ⚠️ SEPARACION CONTRA EL NAVY, medida como se midio la de los ciclos:
     #6E6200 vs navy 1,62:1  ·  #A32D2D vs navy 1,41:1  (control: verde 1,93:1)
   Quedan MENOS despegados que los tres de Operacion, lo que hace al borde MAS
   necesario, no menos.

   ⚠️ REGLA DE CANTIDAD: siguen siendo NAVEGACION, no accion. Se distinguen por
   los dos ejes que la excepcion ya declara -- viven en el CROMO PERSISTENTE (el
   menu) y no usan `.btn-wf`. ⭐ El grep de la regla busca `btn-wf-operation` en
   las paginas; estos usan `.nav-bloque` y no entran en ese conteo.
   ═══════════════════════════════════════════════════════════════════════════ */
.nav-bloque-gestion { --ciclo-fondo: var(--nav-gestion); }
.nav-bloque-admin   { --ciclo-fondo: var(--nav-admin);   }

/* ⚠️ Colapsado: se reduce al icono y la barra de color se mantiene, que es lo
   unico que sigue distinguiendo un ciclo de otro a 48 px de ancho. */
.sidebar-collapsed .nav-ciclo,
.sidebar-collapsed .nav-bloque { justify-content: center; padding: 11px 4px; }

/* ═══════════════════════════════════════════════════════════════════════════
   ⭐⭐⭐ LA VISTA DEL TICKET — frente `1v` (2026-08-15).

   🔴 QUE VINO A REEMPLAZAR, y era una MEDICION: el pop-up mostraba un PNG que
   renderiza Labelary (servicio externo) y ese endpoint esta APAGADO fuera de
   Development a proposito. En faena el modal caia a mostrar el ZPL crudo en un
   <pre>. Mientras el pop-up se abria a pedido eso se toleraba; desde `1v` sale
   SOLO EN CADA RECEPCION, con el cliente delante.

   ⭐ LA PROPORCION DEL PAPEL SE RESPETA, y no es estetica: el ticket tiene 536
   dots utiles y los cuerpos de letra estan CALCULADOS contra ese ancho
   (`TicketZplBuilder.FitFontSize`). Una vista mas ancha que el papel mostraria
   entrando texto que en la impresora se trunca -- que es exactamente el fallo
   que ese archivo ya tuvo dos veces (^PW812 y el largo supuesto del folio).

   ⚠️ POR ESO LA ESCALA ES UNA SOLA VARIABLE Y VA EN `calc()`: el cuerpo en dots
   sale del ZPL como ENTERO y se multiplica acá. Interpolar un decimal desde C#
   habria escrito "23,1px" bajo es-CL y roto la hoja en silencio.
   ═══════════════════════════════════════════════════════════════════════════ */
.ticket-vista { --tv-escala: 0.55px; --tv-ancho: calc(536 * var(--tv-escala)); }

/* Las dos etiquetas del envio, lado a lado cuando entran y apiladas cuando no.
   ⚠️ Son DOS papeles reales, no una etiqueta y su copia. */
.ticket-vista-lote { display: flex; flex-wrap: wrap; gap: 16px; justify-content: center; }

.ticket-vista-hoja {
  background: var(--bg-primary);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-sm);
  padding: 12px;
  width: calc(var(--tv-ancho) + 24px);
  text-align: center;
  color: var(--text-primary);
}

.ticket-vista-linea { word-break: break-word; line-height: 1.25; margin: 2px 0; }

/* La regla horizontal del ticket (^GB). Mismo papel: gris de borde, no de texto. */
.ticket-vista-regla { border-top: 1px solid var(--border-strong); margin: 8px 0; }

.ticket-vista-qr { margin: 10px 0 4px; }
/* ⚠️ `pixelated`: un QR reescalado con suavizado se ve borroso y parece mal
   impreso. Acá el simbolo es informativo, pero un QR borroso invita a pensar
   que el papel salio mal. */
.ticket-vista-qr img {
  width: calc(150 * var(--tv-escala)); height: calc(150 * var(--tv-escala));
  image-rendering: pixelated;
}

/* ⭐ QUE CODIFICA EL QR, EN TEXTO. Es el campo que el operador coteja contra el
   papel que el cliente ya tiene en la mano.
   🔴 Y es deliberado que se lea en vez de escanearse: leer un QR desde una
   pantalla de PC se midio el 2026-08-12 con el R3 y con la C72 y NO FUNCIONA
   --el brillo y el refresco le pelean al motor--. Un dato legible no manda a
   nadie a intentar el gesto que no anda. */
.ticket-vista-qr-dato { font-family: var(--font-mono); font-size: 11px; color: var(--text-muted); }

.ticket-vista-cap {
  font-size: 12px; color: var(--text-muted); text-align: center;
  margin-bottom: 6px; text-transform: uppercase; letter-spacing: 0.04em;
}

/* El detalle tecnico (ZPL y, si existe, el render de desarrollo) va COLAPSADO.
   ⭐ Sigue estando --es lo que sirve para diagnosticar una impresion torcida--
   pero cuesta cero clics en el flujo del mostrador. */
.ticket-vista-tecnico > summary {
  cursor: pointer; font-size: 12px; color: var(--text-muted); user-select: none;
}
.ticket-vista-tecnico > summary:hover { color: var(--text-accent); }

/* ⚠️ AVISO INFORMATIVO DEL TICKET — clase propia y NO `.alert-info`, que **no
   existe en esta hoja**. Se escribio primero como `.alert-info` y la
   verificacion la atajo antes de compilar: en CSS no hay compilador que
   proteste, la pantalla simplemente sale sin estilo.
   ⭐ El texto va NAVY sobre el tinte azul y no teal: sobre `--bg-accent` el teal
   da 4,35:1 --por debajo del 4,5:1 de AA-- y el navy da 8,8:1. Se ven casi
   igual y uno pasa y el otro no. */
.ticket-vista-aviso {
  padding: 10px 14px; background: var(--bg-accent);
  border: 1px solid var(--border-accent); border-radius: var(--radius-md);
  color: var(--color-primary); font-size: 13px;
}


/* ═══════════════════════════════════════════════════════════════════════════
   ⭐⭐⭐ PASOS Y CONSULTAS EN LA MISMA HOJA — 2026-08-15.

   🔴 LA JERARQUIA SE RESUELVE CON LA FORMA, NO CON EL COLOR (criterio de Manuel).
   Las dos cosas pertenecen al ciclo, asi que las dos llevan su tinte; lo que las
   separa es la FORMA:

     · PASO     -> numero, tarjeta BLANCA con borde, y su linea explicativa.
     · CONSULTA -> tinte del ciclo, SIN numero, en fila, y con menos peso.

   ⭐ Y el encabezado dice "CONSULTAS" a secas. NO dice "no son pasos": si la
   forma ya lo comunica, el texto seria una muleta -- y una muleta envejece
   igual que cualquier otra linea.
   ═══════════════════════════════════════════════════════════════════════════ */

/* El numero del paso. Es lo que convierte cuatro tarjetas sueltas en una
   SECUENCIA -- que es el problema entero que abrio el frente `1u`. */
.ciclo-paso-num {
  width: 26px; height: 26px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  border-radius: 999px;
  background: var(--op-accent); color: #fff;
  font-size: 13px; font-weight: 700;
  align-self: flex-start; margin-top: 2px;
}

/* ── La seccion de consultas ─────────────────────────────────────────────── */
/* ═══════════════════════════════════════════════════════════════════════════
   ⭐⭐ Y LA ZONA BAJA TIENE DOS INQUILINOS, NO UNO (2026-08-15).

   `.ciclo-apoyo` COMPARTE LA FORMA DE `.ciclo-consultas` Y NO SU NOMBRE, y la
   diferencia importa: una consulta NO ESCRIBE --dashboard, guias emitidas,
   trazabilidad-- y una herramienta de apoyo SI. Clasificacion escribe
   `ClassifiedAt`, enrola prendas y registra fallas.

   🔴 Meterla bajo el encabezado "CONSULTAS" seria decirle al operador que ahi
   no pasa nada, que es exactamente la clase de linea que este repo lleva una
   semana corrigiendo. Y darle una forma propia seria un tercer idioma visual
   en la misma hoja.

   ⭐ Entonces: MISMA forma (sin numero, en fila, menos peso) y OTRO encabezado.
   Las reglas se comparten en vez de duplicarse -- dos definiciones del mismo
   aspecto es como `radar.css` y `app.css` terminaron dependiendo del orden de
   carga de un `<link>`.
   ═══════════════════════════════════════════════════════════════════════════ */
.ciclo-consultas,
.ciclo-apoyo { margin-top: 22px; padding-top: 18px; border-top: 1px solid var(--border); }

.ciclo-consultas-titulo,
.ciclo-apoyo-titulo {
  font-size: 11.5px; font-weight: 700; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--text-muted);
  margin-bottom: 10px;
}

/* ⚠️ EN FILA, no en la grilla de los pasos: compartir la grilla les daria el
   mismo ancho y el mismo peso, y volveria a mezclar lo que este bloque separa. */
.ciclo-consultas-fila,
.ciclo-apoyo-fila { display: flex; flex-wrap: wrap; gap: 10px; }

.ciclo-consulta-card,
.ciclo-apoyo-card {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 14px;
  background: var(--op-accent-bg);
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  color: var(--text-primary);
  text-decoration: none;
  font-size: 13.5px;
  cursor: pointer;
  transition: border-color .12s ease;
}
.ciclo-consulta-card:hover,
.ciclo-apoyo-card:hover { border-color: var(--op-accent); color: var(--text-primary); }
.ciclo-consulta-card .bi,
.ciclo-apoyo-card .bi { color: var(--op-accent); font-size: 16px; flex-shrink: 0; }
.ciclo-consulta-nombre,
.ciclo-apoyo-nombre { font-weight: 600; }
.ciclo-consulta-desc,
.ciclo-apoyo-desc { color: var(--text-muted); font-size: 12.5px; }


/* ═══════════════════════════════════════════════════════════════════════════
   ⭐⭐⭐ EL SELECTOR DE MODO — NAVEGACION, NO ACCION (2026-08-15).

   🔴 EL DEFECTO MEDIDO: en `RecibirDelLavandero` la barra de entradas es SIEMPRE
   visible --esta fuera del `@if (_bundle is null)`--, asi que con un bulto
   abierto el selector activo (solido naranja) convivia con *Enrolar* (solido
   naranja). **Dos solidos a la vez, y la regla admite uno.**

   ⭐ LA DECISION DE MANUEL, y su argumento: **el selector PIERDE el solido.
   Enrolar es LA ACCION; el selector es NAVEGACION** -- misma regla que separa
   los bloques del menu de los botones de las pantallas.

   ── 🔴 PERO EL ACTIVO NO PUEDE QUEDAR SIN SEÑAL ───────────────────────────

   Se marca por FORMA y PESO, **exactamente el idioma que el menu ya usa para el
   ciclo seleccionado**, y por el mismo motivo que esta escrito alla: **que se
   note sin depender del color, porque un operador daltonico no lo veria**.

     ① FORMA  -- barra izquierda de 3 px. Es geometria pura: se ve en escala de
                 grises. (El menu usa 3 -> 7 px; aca es 0 -> 3, porque el boton
                 no tiene barra en reposo.)
     ② PESO   -- 600 -> 700.
     ③ GLIFO  -- aparece un check a la derecha. **Existe o no existe**, no es un
                 matiz -- mismo recurso que el chevron del menu.

   ⚠️ EL TINTE NO CAMBIA ENTRE ACTIVO E INACTIVO, a proposito: si el activo
   subiera de tinte volveriamos a distinguir por color, que es lo que este bloque
   viene a sacar.

   ⭐ CONTRASTE, CALCULADO -- el tinte rgba(212,96,14,0.10) compuesto sobre
   blanco da #FBEFE7:
     · texto  #9A5A00 sobre #FBEFE7 -> **4,85:1**  ✅ (umbral AA 4,5, texto 13 px)
     · barra  #D4600E sobre #FBEFE7 -> **3,40:1**  ✅ (umbral 3:1, elemento grafico)
   ⚠️ El texto ya era ese par en los tres botones inactivos: lo que se midio es
   que el ACTIVO, al pasar a tinte, no baja de umbral -- y que la barra que ahora
   carga la señal se ve por si sola.
   ═══════════════════════════════════════════════════════════════════════════ */
.btn-wf-selector {
  border-left: 3px solid transparent;
}
.btn-wf-selector.active {
  border-left-color: var(--orange-module);
  font-weight: 700;
}

/* ⭐⭐ C — TÍTULO Y SUBTÍTULO EN UNA SOLA FILA (2026-08-25).
   🔴 Reportado por Manuel USANDO la pantalla de recepción: con el cliente ya
   elegido, antes del primer campo útil había ~383 px —más de media pantalla en
   su notebook— y el scroll era obligado sin que hubiera nada que leer arriba.
   ⚠️ EL SUBTÍTULO NO SE BORRA: es la línea que dice qué pasa en esta pantalla,
   y eso es regla escrita del repo. Se compacta, no se quita.
   ⭐ El separador va en el MARKUP, no en `content:`: una `content` con escape
   unicode ya metió un byte nulo en este archivo al construirlo. */
/* 🔴 EL SEPARADOR «·» SE QUITO EL 2026-08-25, MEDIDO EN LA CC6000. Habia una
   regla `.op-page-sep` y un `<span>` en el markup. En escritorio la fila entra
   completa; en la tablet el ancho CSS es 800 px --densidad 160-- y el subtitulo
   se va a la linea de abajo, DEJANDO EL PUNTO COLGANDO al final del titulo.
   ⭐ El `gap` ya separa: el punto no aportaba y era lo unico que podia romperse.
   ⚠️ NO se resolvio con un `@media`: este archivo no tiene ni un punto de corte
   por ancho, y meter el primero para salvar un adorno es peor que el adorno. */
.op-page-heading {
  display: flex;
  align-items: baseline;
  gap: 14px;
  flex-wrap: wrap;
}
.op-page-heading .page-title { margin-bottom: 0; }
.op-page-heading .page-subtitle { margin-bottom: 0; }
