/*
  base.css — Mugi v2. Extensión de tokens (pasteles semánticos) + componentes base.
  Se carga DESPUÉS de tokens.css (Core literal). Sesión A, 2026-09-03.
  Reglas: neutros a chroma 0; color SOLO donde significa un dato; pasteles solo en chips/estados/
  franjas pequeñas; cortes rectos (excepciones: spinner y palanca on/off); sombra = hairline;
  dark por elevación; cero emojis; cifras en IBM Plex Mono.
  Contrastes texto-sobre-pastel calculados (WCAG): claro 4.51-6.81:1, oscuro 4.51-4.56:1.
*/

/* ---------- 1. Extensión de tokens (claro) ---------- */
:root{
  /* warn se libera a ámbar (en Mugi sí se acepta amarillo); info es nuevo */

  /* Etapas del cliente */
  --nuevo:        oklch(0.550 0.155 295); --nuevo-bg:        oklch(0.955 0.045 295); --nuevo-border:        oklch(0.850 0.095 295); --nuevo-text:        oklch(0.450 0.135 295);
  --conversacion: oklch(0.550 0.155 215); --conversacion-bg: oklch(0.955 0.045 215); --conversacion-border: oklch(0.850 0.095 215); --conversacion-text: oklch(0.450 0.135 215);
  --pedido:       oklch(0.550 0.155 40);  --pedido-bg:       oklch(0.955 0.045 40);  --pedido-border:       oklch(0.850 0.095 40);  --pedido-text:       oklch(0.450 0.135 40);
  --pagado:       oklch(0.550 0.155 165); --pagado-bg:       oklch(0.955 0.045 165); --pagado-border:       oklch(0.850 0.095 165); --pagado-text:       oklch(0.450 0.135 165);
  --entregado:    oklch(0.550 0.155 277); --entregado-bg:    oklch(0.955 0.045 277); --entregado-border:    oklch(0.850 0.095 277); --entregado-text:    oklch(0.450 0.135 277);

  /* Canales (identidad, no semáforo) */
  --whatsapp:  oklch(0.550 0.155 150); --whatsapp-bg:  oklch(0.955 0.045 150); --whatsapp-border:  oklch(0.850 0.095 150); --whatsapp-text:  oklch(0.450 0.135 150);
  --instagram: oklch(0.550 0.155 350); --instagram-bg: oklch(0.955 0.045 350); --instagram-border: oklch(0.850 0.095 350); --instagram-text: oklch(0.450 0.135 350);
  --messenger: oklch(0.550 0.155 258); --messenger-bg: oklch(0.955 0.045 258); --messenger-border: oklch(0.850 0.095 258); --messenger-text: oklch(0.450 0.135 258);

  /* Layout */
  --sidebar-w: 232px; --ficha-w: 340px; --lista-w: 320px; --header-h: 52px;
  --overlay: oklch(0 0 0 / .45);
  --focus: 0 0 0 2px var(--bg), 0 0 0 4px var(--ink);
}

/* ---------- 2. Extensión de tokens (oscuro, elevación) ---------- */
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]){
    --nuevo:        oklch(0.780 0.135 295); --nuevo-bg:        oklch(0.280 0.055 295); --nuevo-border:        oklch(0.420 0.090 295); --nuevo-text:        oklch(0.660 0.130 295);
    --conversacion: oklch(0.780 0.135 215); --conversacion-bg: oklch(0.280 0.055 215); --conversacion-border: oklch(0.420 0.090 215); --conversacion-text: oklch(0.640 0.130 215);
    --pedido:       oklch(0.780 0.135 40);  --pedido-bg:       oklch(0.280 0.055 40);  --pedido-border:       oklch(0.420 0.090 40);  --pedido-text:       oklch(0.660 0.130 40);
    --pagado:       oklch(0.780 0.135 165); --pagado-bg:       oklch(0.280 0.055 165); --pagado-border:       oklch(0.420 0.090 165); --pagado-text:       oklch(0.640 0.130 165);
    --entregado:    oklch(0.780 0.135 277); --entregado-bg:    oklch(0.280 0.055 277); --entregado-border:    oklch(0.420 0.090 277); --entregado-text:    oklch(0.655 0.130 277);
    --whatsapp:  oklch(0.780 0.135 150); --whatsapp-bg:  oklch(0.280 0.055 150); --whatsapp-border:  oklch(0.420 0.090 150); --whatsapp-text:  oklch(0.640 0.130 150);
    --instagram: oklch(0.780 0.135 350); --instagram-bg: oklch(0.280 0.055 350); --instagram-border: oklch(0.420 0.090 350); --instagram-text: oklch(0.665 0.130 350);
    --messenger: oklch(0.780 0.135 258); --messenger-bg: oklch(0.280 0.055 258); --messenger-border: oklch(0.420 0.090 258); --messenger-text: oklch(0.650 0.130 258);
    --overlay: oklch(0 0 0 / .6);
  }
}
:root[data-theme="dark"]{
  --nuevo:        oklch(0.780 0.135 295); --nuevo-bg:        oklch(0.280 0.055 295); --nuevo-border:        oklch(0.420 0.090 295); --nuevo-text:        oklch(0.660 0.130 295);
  --conversacion: oklch(0.780 0.135 215); --conversacion-bg: oklch(0.280 0.055 215); --conversacion-border: oklch(0.420 0.090 215); --conversacion-text: oklch(0.640 0.130 215);
  --pedido:       oklch(0.780 0.135 40);  --pedido-bg:       oklch(0.280 0.055 40);  --pedido-border:       oklch(0.420 0.090 40);  --pedido-text:       oklch(0.660 0.130 40);
  --pagado:       oklch(0.780 0.135 165); --pagado-bg:       oklch(0.280 0.055 165); --pagado-border:       oklch(0.420 0.090 165); --pagado-text:       oklch(0.640 0.130 165);
  --entregado:    oklch(0.780 0.135 277); --entregado-bg:    oklch(0.280 0.055 277); --entregado-border:    oklch(0.420 0.090 277); --entregado-text:    oklch(0.655 0.130 277);
  --whatsapp:  oklch(0.780 0.135 150); --whatsapp-bg:  oklch(0.280 0.055 150); --whatsapp-border:  oklch(0.420 0.090 150); --whatsapp-text:  oklch(0.640 0.130 150);
  --instagram: oklch(0.780 0.135 350); --instagram-bg: oklch(0.280 0.055 350); --instagram-border: oklch(0.420 0.090 350); --instagram-text: oklch(0.665 0.130 350);
  --messenger: oklch(0.780 0.135 258); --messenger-bg: oklch(0.280 0.055 258); --messenger-border: oklch(0.420 0.090 258); --messenger-text: oklch(0.650 0.130 258);
  --overlay: oklch(0 0 0 / .6);
}

/* ---------- 3. Reset y base ---------- */
*,*::before,*::after{ box-sizing:border-box; }
html{ -webkit-text-size-adjust:100%; }
body{ margin:0; background:var(--bg); color:var(--ink); font-family:var(--font-body); font-size:13.5px; line-height:1.45; -webkit-font-smoothing:antialiased; }
h1,h2,h3,h4{ margin:0; font-family:var(--font-display); font-weight:600; color:var(--ink); }
h1{ font-size:22px; line-height:1.2; letter-spacing:-.02em; }
h2{ font-size:18px; line-height:1.25; letter-spacing:-.015em; }
h3{ font-size:14px; line-height:1.3; }
p{ margin:0; }
a{ color:inherit; text-decoration:none; }
button,input,select,textarea{ font:inherit; color:inherit; }
svg{ display:block; }
:focus-visible{ outline:none; box-shadow:var(--focus); }
.mono{ font-family:var(--font-mono); font-variant-numeric:tabular-nums; }
.suave{ color:var(--ink-soft); } .tenue{ color:var(--ink-faint); }
.eyebrow{ font-size:10.5px; font-weight:600; letter-spacing:.08em; text-transform:uppercase; color:var(--ink-faint); }
.oculto{ display:none !important; }
[hidden]{ display:none !important; } /* gana a .btn y a cualquier display de componente (hallazgo QA C10) */
.sr-only{ position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; }

/* ---------- 4. Botones ---------- */
/* Manual de diseño (II.2, fallo 15): 40 px mínimo en escritorio; 44 px de área de toque en dispositivos táctiles (pointer: coarse). */
.btn{ display:inline-flex; align-items:center; justify-content:center; gap:7px; height:40px; padding:0 14px; border:1px solid var(--border-strong); background:var(--surface); color:var(--ink); font-size:13px; font-weight:600; border-radius:var(--radius-md); cursor:pointer; white-space:nowrap; transition:background .12s, transform var(--dur-1) var(--ease-out); }
.btn:hover{ background:var(--surface-hover); }
.btn:active{ transform:scale(0.97); }
.btn:disabled{ opacity:.45; cursor:not-allowed; }
.btn svg{ width:15px; height:15px; }
.btn.primario{ background:var(--cta-bg); color:var(--cta-fg); border-color:var(--cta-bg); }
.btn.primario:hover{ background:var(--cta-hover); border-color:var(--cta-hover); }
/* .btn:disabled (arriba) solo baja la opacidad a 45% — en un botón SÓLIDO (primario) eso todavía
   se ve como un CTA azul activo, no como deshabilitado de verdad (hallazgo C-10, ronda 2 de la
   cacería, 2026-09-03: "Confirmar importación" deshabilitado parecía clicable). Gris neutro en vez
   de azul desvanecido, aplica a cualquier .btn.primario:disabled de toda la app. */
.btn.primario:disabled{ background:var(--surface-2); color:var(--ink-faint); border-color:var(--border); opacity:1; }
.btn.fantasma{ border-color:transparent; background:transparent; }
.btn.fantasma:hover{ background:var(--surface-hover); }
.btn.peligro{ color:var(--bad-text); border-color:var(--bad-border); }
.btn.peligro:hover{ background:var(--bad-bg); }
.btn.chico{ height:32px; padding:0 10px; font-size:12px; }
@media (pointer: coarse){ .btn, .btn.chico{ min-height:44px; } .btn.icono, .btn.icono.chico{ min-width:44px; } }
.btn.icono{ width:34px; padding:0; }
.btn.icono.chico{ width:28px; }

/* ---------- 5. Formularios ---------- */
.campo{ display:flex; flex-direction:column; gap:6px; }
.campo > label{ font-size:12.5px; font-weight:600; color:var(--ink); }
.campo .ayuda{ font-size:12px; color:var(--ink-faint); }
.campo .error{ font-size:12px; color:var(--bad-text); }
.input, .campo input:not([type=checkbox]):not([type=radio]), .campo select, .campo textarea{
  width:100%; min-height:36px; padding:7px 10px; border:1px solid var(--border); background:var(--surface); color:var(--ink); border-radius:var(--radius-md); font-size:13.5px; }
.campo textarea{ min-height:96px; resize:vertical; line-height:1.45; border-radius:var(--radius-md); }
.campo input:focus, .campo select:focus, .campo textarea:focus, .input:focus{ border-color:var(--accent) !important; box-shadow:0 0 0 2px var(--bg), 0 0 0 4px var(--accent) !important; outline:none; } /* accesibilidad (C26): anillo de acento visible (≥ 3:1) en claro y oscuro; !important porque varios módulos anulaban la sombra */
.campo.invalido input, .campo.invalido textarea{ border-color:var(--bad); }
.fila-campos{ display:grid; grid-template-columns:repeat(auto-fit, minmax(220px,1fr)); gap:14px; }
/* palanca on/off: única excepción de radio (decisión de Nestor 31-ago-2026) */
.switch{ position:relative; width:38px; height:22px; flex:none; background:var(--neutral-border); border-radius:999px; cursor:pointer; transition:background var(--dur-1) var(--ease-out); border:0; padding:0; }
.switch::after{ content:""; position:absolute; top:3px; left:3px; width:16px; height:16px; background:var(--surface); border-radius:50%; transition:transform var(--dur-1) var(--ease-out); box-shadow:0 0 0 1px var(--border); }
.switch[aria-checked="true"]{ background:var(--accent); }
.switch[aria-checked="true"]::after{ transform:translateX(16px); }
.check{ display:inline-flex; align-items:center; gap:9px; cursor:pointer; font-size:13.5px; }
.check input{ appearance:none; width:16px; height:16px; margin:0; border:1px solid var(--border-strong); background:var(--surface); border-radius:var(--radius-sm); display:grid; place-content:center; }
.check input::before{ content:""; width:8px; height:8px; background:var(--accent); transform:scale(0); transition:transform var(--dur-1) var(--ease-out); }
.check input:checked{ border-color:var(--accent); background:var(--accent-soft); }
.check input:checked::before{ transform:scale(1); }
.segmentado{ display:inline-flex; border:1px solid var(--border); border-radius:var(--radius-md); overflow:hidden; }
.segmentado button{ height:30px; padding:0 12px; border:0; background:transparent; font-size:12.5px; font-weight:600; color:var(--ink-soft); cursor:pointer; border-right:1px solid var(--border); }
.segmentado button:last-child{ border-right:0; }
.segmentado button[aria-pressed="true"]{ background:var(--accent-soft); color:var(--accent); box-shadow:inset 0 0 0 1px var(--accent-soft-border); } /* activo = elevación/acento, nunca invertir (cacería, regla de Nestor para el oscuro) */

/* ---------- 6. Chips ---------- */
.chip{ display:inline-flex; align-items:center; gap:5px; padding:3px 9px; font-size:11px; font-weight:600; letter-spacing:.01em; white-space:nowrap; border:1px solid var(--neutral-border); background:var(--neutral-bg); color:var(--ink-soft); border-radius:var(--radius-pill, 0px); }
.chip svg{ width:11px; height:11px; }
.chip.ok{ background:var(--ok-bg); border-color:var(--ok-border); color:var(--ok-text); }
.chip.warn{ background:var(--warn-bg); border-color:var(--warn-border); color:var(--warn-text); }
.chip.bad{ background:var(--bad-bg); border-color:var(--bad-border); color:var(--bad-text); }
.chip.info{ background:var(--info-bg); border-color:var(--info-border); color:var(--info-text); }
.chip.nuevo{ background:var(--nuevo-bg); border-color:var(--nuevo-border); color:var(--nuevo-text); }
.chip.conversacion{ background:var(--conversacion-bg); border-color:var(--conversacion-border); color:var(--conversacion-text); }
.chip.pedido{ background:var(--pedido-bg); border-color:var(--pedido-border); color:var(--pedido-text); }
.chip.pagado{ background:var(--pagado-bg); border-color:var(--pagado-border); color:var(--pagado-text); }
.chip.entregado{ background:var(--entregado-bg); border-color:var(--entregado-border); color:var(--entregado-text); }
.chip.whatsapp{ background:var(--whatsapp-bg); border-color:var(--whatsapp-border); color:var(--whatsapp-text); }
.chip.instagram{ background:var(--instagram-bg); border-color:var(--instagram-border); color:var(--instagram-text); }
.chip.messenger{ background:var(--messenger-bg); border-color:var(--messenger-border); color:var(--messenger-text); }
/* punto de estado (8px) para semáforos discretos */
/* Luces de estado (decisión de Nestor 3-sep 23:12: nada de cuadrados Core; puntos redondos con halo,
   como una luz roja/naranja/verde). El halo usa los tokens *-bg/*-border de cada estado, así funciona
   en claro y oscuro sin color-mix. */
.punto{ display:inline-block; width:9px; height:9px; border-radius:50%; background:var(--neutral); flex:none; box-shadow:0 0 0 3px var(--surface-2); }
.punto.ok{ background:var(--ok); box-shadow:0 0 0 3px var(--ok-bg), 0 0 8px 1px var(--ok); }
.punto.warn{ background:var(--warn); box-shadow:0 0 0 3px var(--warn-bg), 0 0 8px 1px var(--warn); }
.punto.bad{ background:var(--bad); box-shadow:0 0 0 3px var(--bad-bg), 0 0 8px 1px var(--bad); }
.punto.info{ background:var(--info); box-shadow:0 0 0 3px var(--info-bg, var(--surface-2)), 0 0 8px 1px var(--info); }

/* ---------- 7. Tarjetas, paneles, tablas ---------- */
.tarjeta{ background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-lg); }
.tarjeta > .cabecera{ display:flex; align-items:center; justify-content:space-between; gap:12px; padding:12px 16px; border-bottom:1px solid var(--border); }
.tarjeta > .cuerpo{ padding:16px; }
.kpi{ padding:14px 16px; border:1px solid var(--border); background:var(--surface); border-radius:var(--radius-lg); }
.kpi .valor{ font-family:var(--font-mono); font-variant-numeric:tabular-nums; font-size:24px; font-weight:600; line-height:1.1; margin-top:6px; }
.kpi .delta{ font-size:12px; margin-top:4px; color:var(--ink-faint); }
.kpi .delta.sube{ color:var(--ok-text); } .kpi .delta.baja{ color:var(--bad-text); }
.tabla{ width:100%; border-collapse:collapse; font-size:13px; }
.tabla th{ text-align:left; font-size:10.5px; font-weight:600; letter-spacing:.06em; text-transform:uppercase; color:var(--ink-faint); padding:9px 12px; border-bottom:1px solid var(--border); background:var(--surface); position:sticky; top:0; z-index:2; }
.tabla td{ padding:10px 12px; border-bottom:1px solid var(--border); vertical-align:middle; }
.tabla tbody tr:hover{ background:var(--surface-hover); }
.tabla tr.seleccionada{ background:var(--accent-soft); }
.tabla td.num, .tabla th.num{ text-align:right; font-family:var(--font-mono); font-variant-numeric:tabular-nums; white-space:nowrap; } /* F-6, ronda 2 de la cacería: "S/ 160" se partía en 2 líneas ("S/" arriba, "160" abajo) en columnas angostas — un monto nunca debería envolver */
.tabla-scroll{ overflow-x:auto; }
/* El scroll horizontal siempre funcionó (overflow-x:auto), pero nada avisaba que había más
   columnas fuera de la pantalla — en Pedidos, la columna Estado quedaba invisible y nadie
   descubría que podía deslizar para verla (hallazgo de la cacería, 2026-09-03). Aviso fijo y
   simple en vez de un degradado ligado al scroll (más frágil de mantener entre navegadores). */
.tabla-scroll-aviso{ display:none; }
@media (max-width:820px){
  .tabla-scroll-aviso{ display:flex; align-items:center; gap:4px; font-size:11px; color:var(--ink-faint); margin-bottom:6px; }
}
.tabs{ display:flex; gap:0; border-bottom:1px solid var(--border); }
.tabs button{ height:38px; padding:0 14px; border:0; border-bottom:2px solid transparent; margin-bottom:-1px; background:transparent; font-size:13px; font-weight:600; color:var(--ink-soft); cursor:pointer; }
.tabs button[aria-selected="true"]{ color:var(--ink); border-bottom-color:var(--ink); }
.lista-definicion{ display:grid; grid-template-columns:minmax(110px,max-content) 1fr; gap:6px 14px; font-size:13px; }
.lista-definicion dt{ color:var(--ink-faint); } .lista-definicion dd{ margin:0; }

/* ---------- 8. Chat ---------- */
.msg{ max-width:72%; padding:9px 12px; font-size:13.5px; line-height:1.45; border-radius:var(--radius-lg); word-wrap:break-word; }
.msg.entrante{ background:var(--surface-2); border:1px solid var(--border); color:var(--ink); align-self:flex-start; }
.msg.saliente{ background:var(--accent-soft); border:1px solid var(--accent-soft-border); color:var(--ink); align-self:flex-end; } /* respond.io: saliente en azul suave, no tinta */
.msg.bot{ background:var(--surface); border:1px solid var(--border-strong); color:var(--ink); align-self:flex-end; }
.msg.nota{ background:var(--warn-bg); border:1px solid var(--warn-border); color:var(--warn-text); align-self:center; max-width:88%; font-size:12.5px; }
.msg .hora{ display:block; margin-top:4px; font-family:var(--font-mono); font-size:10.5px; color:var(--ink-faint); }
.msg.saliente .hora{ color:var(--ink-faint); }
.avatar{ width:34px; height:34px; flex:none; display:grid; place-content:center; background:var(--surface-2); border:1px solid var(--border); font-size:12px; font-weight:600; color:var(--ink-soft); overflow:hidden; border-radius:var(--radius-avatar, 0px); }
.avatar img{ width:100%; height:100%; object-fit:cover; }
.avatar.chico{ width:26px; height:26px; font-size:10px; }

/* ---------- 9. Checklist de puesta en marcha ---------- */
.onboarding{ border:1px solid var(--border); background:var(--surface); }
.onb-item{ display:flex; align-items:center; gap:12px; padding:14px 16px; border-bottom:1px solid var(--border); }
.onb-item:last-child{ border-bottom:0; }
/* Casilla redonda (no cuadrada Core); hecho = verde de estado, no negro. */
.onb-check{ width:22px; height:22px; flex:none; border:1.5px solid var(--border-strong); border-radius:50%; display:grid; place-content:center; background:var(--surface); transition:background .15s, border-color .15s; }
.onb-check svg{ width:12px; height:12px; stroke:var(--bg); stroke-width:2.5; fill:none; opacity:0; }
.onb-item.hecho .onb-check{ background:var(--ok); border-color:var(--ok); }
.onb-item.hecho .onb-check svg{ stroke:#fff; }
.onb-item.hecho .onb-check svg{ opacity:1; }
.onb-item.hecho .onb-texto{ color:var(--ink-faint); text-decoration:line-through; }
.onb-texto{ font-size:13.5px; flex:1; }
.onb-cta{ font-size:12px; font-weight:600; color:var(--accent-strong); }
.progreso{ height:4px; background:var(--surface-2); border:1px solid var(--border); }
.progreso > span{ display:block; height:100%; background:var(--ink); }

/* ---------- 10. Modales, hojas, toasts, estados ---------- */
/* z-index de .overlay/.hoja subido de 60/61 a 85/86 (hallado armando el recorrido visual de
   Boletas para Nestor, 2026-09-04): con .mnav a z-index:80 (shell.css, la barra inferior fija de
   móvil), CUALQUIER modal o bottom-sheet de la app cuyo contenido llegara a los últimos ~60px de
   pantalla quedaba con su pie (los botones de acción) tapado por esa barra — no un problema de una
   pantalla puntual, afectaba a todo modal largo en móvil, en toda la app. .toasts sube de 80 a 90
   (por encima del nuevo z-index del modal): un toast disparado desde DENTRO de un modal abierto
   (ej. "Corregir campo" en Boletas) tiene que seguir viéndose encima de él — con el .overlay ahora
   en 85, dejar el toast en 80 lo habría escondido DETRÁS del modal, rompiendo ese caso. */
/* Entrada/salida (plan 002, Emil Kowalski): los modales son la EXCEPCIÓN de origen — se quedan
   centrados (transform-origin:center), a diferencia de los desplegables (plan 003), que nacen de
   su disparador. .entra/.sale las pone montarConEntrada()/quitarConSalida() de ui.js — transition,
   no @keyframes, para que Escape a mitad de la entrada revierta sin salto (interrumpible). Salida
   más rápida que la entrada (--dur-1 vs --dur-3): "asimétrico" — entrar despacio y deliberado,
   salir rápido, como pide Emil. */
.overlay{ position:fixed; inset:0; background:var(--overlay); z-index:85; display:flex; align-items:center; justify-content:center; padding:20px; opacity:0; transition:opacity var(--dur-3) var(--ease-out); }
.overlay.entra{ opacity:1; }
.overlay.sale{ opacity:0; transition-duration:var(--dur-1); }
/* Apertura por atajo de teclado (Ctrl/Cmd+K): sin animación, aparece y desaparece de una (regla de Emil). */
.overlay.instantaneo, .overlay.instantaneo .modal{ transition:none !important; }
.modal{ width:min(560px,100%); max-height:92vh; overflow:auto; background:var(--surface); border:1px solid var(--border-strong); box-shadow:var(--shadow-2); border-radius:var(--radius-lg); transform:scale(0.96); opacity:0; transform-origin:center; transition:transform var(--dur-3) var(--ease-out), opacity var(--dur-3) var(--ease-out); }
.overlay.entra .modal{ transform:scale(1); opacity:1; }
.overlay.sale .modal{ transform:scale(0.98); opacity:0; transition-duration:var(--dur-1); }
.modal > .cabecera, .modal > form > .cabecera{ display:flex; align-items:center; justify-content:space-between; padding:14px 18px; border-bottom:1px solid var(--border); }
.modal > .cuerpo, .modal > form > .cuerpo{ padding:18px; } .modal > .pie, .modal > form > .pie{ display:flex; justify-content:flex-end; gap:8px; padding:12px 18px; border-top:1px solid var(--border); }
/* Entrada/salida (plan 006, Emil Kowalski): desliza desde su borde — a la derecha en escritorio,
   curva de Vaul (rápida al inicio, suave al final); en móvil sube desde abajo (ver el override en
   el bloque "12. Móvil" más abajo, mismo criterio que .mas-panel). Sin usuario todavía (ningún
   módulo crea un .hoja hoy, 2026-09-04 — ver LISTA-B.md), pero queda lista para cuando se use: el
   z-index/reduced-motion de esta clase ya la trataban como un panel real (Bloque 24 de esta
   sesión, y plan 001). */
/* --dur-5 (500ms, no --dur-3): pedido de A2 2026-09-04, alineado con
   EMIL-KOWALSKI-PRINCIPIOS.md §5 — Vaul usa una sola duración (500ms) para abrir/cerrar/
   snap-back de un drawer/bottom sheet grande, distinta de la pareja entrada-lenta/salida-rápida
   que sí aplica al resto de la app (modales, popovers). La salida se queda en --dur-2 (más rápida
   que la entrada) porque acá no hay drag/snap-back real que replicar — es la única pieza del
   patrón de Vaul que no aplica tal cual. */
.hoja{ position:fixed; right:0; top:0; bottom:0; width:min(480px,100%); background:var(--surface); border-left:1px solid var(--border-strong); z-index:86; display:flex; flex-direction:column; transform:translateX(100%); transition:transform var(--dur-5) var(--ease-drawer); }
.hoja.entra{ transform:translateX(0); }
.hoja.sale{ transform:translateX(100%); transition-duration:var(--dur-2); }
.toasts{ position:fixed; right:16px; bottom:16px; display:flex; flex-direction:column; gap:8px; z-index:90; }
/* Entrada/salida (plan 004, Emil Kowalski): sube desde abajo y sale por donde entró —
   translateY(100%) es relativo al alto del propio toast, no un valor en px a mano. "ease" (no
   ease-out): Sonner usa ease a propósito, se siente más elegante para este componente que el
   ease-out más "de golpe" del resto de la UI. Transiciones, no @keyframes: los toasts se disparan
   en ráfaga (varios seguidos) y una transición se puede reapuntar a mitad de camino sin reiniciar. */
.toast{ min-width:240px; max-width:380px; padding:10px 14px; background:var(--surface); border:1px solid var(--border-strong); font-size:13px; box-shadow:var(--shadow-1); border-radius:var(--radius-md); transform:translateY(100%); opacity:0; transition:transform var(--dur-2) ease, opacity var(--dur-2) ease; }
.toast.entra{ transform:translateY(0); opacity:1; }
.toast.sale{ transform:translateY(100%); opacity:0; transition-duration:var(--dur-1); }
.toast.ok{ border-color:var(--ok-border); border-left:3px solid var(--ok); }
.toast.bad{ border-color:var(--bad-border); border-left:3px solid var(--bad); }
.toast.warn{ border-color:var(--warn-border); border-left:3px solid var(--warn); }
.toast.info{ border-color:var(--info-border); border-left:3px solid var(--info); }
/* Toast con acción (Deshacer): texto + botón en una fila; el botón es un enlace de acento, 44 px de alto táctil. */
.toast{ display:flex; align-items:center; gap:12px; }
.toast-texto{ flex:1 1 auto; }
.toast-accion{ flex:none; min-height:32px; padding:0 8px; border:none; background:transparent; color:var(--accent); font:inherit; font-weight:600; cursor:pointer; border-radius:var(--radius-sm); }
.toast-accion:hover{ background:var(--surface-hover); }
.toast-accion:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; }
/* F-MOVIL-4 (5-sep, A2): los toasts tienen z-index:90, la barra inferior (.mnav) z-index:80 —
   con "bottom:12px" el toast quedaba ENCIMA de la barra (la tapaba), no arriba de ella. La barra
   mide ~58px (4px + min-height:50px del ítem + 4px, antes del safe-area) — 70px deja un respiro
   de 12px entre el toast y la barra, igual que el margen que ya tenía. */
@media (max-width:820px){ .toasts{ left:12px; right:12px; bottom:calc(70px + env(safe-area-inset-bottom)); } .toast{ max-width:none; } .toast-accion{ min-height:44px; padding:0 12px; } }
.vacio{ display:flex; flex-direction:column; align-items:center; justify-content:center; gap:10px; padding:48px 20px; text-align:center; color:var(--ink-soft); }
.vacio svg{ width:36px; height:36px; stroke:var(--ink-faint); stroke-width:1.5; fill:none; }
.vacio h3{ color:var(--ink); } .vacio p{ max-width:380px; font-size:13px; }
.aviso{ display:flex; gap:10px; align-items:flex-start; padding:10px 12px; border:1px solid var(--border); border-left:3px solid var(--ink); background:var(--surface); font-size:13px; border-radius:var(--radius-md); }
.aviso.warn{ border-left-color:var(--warn); } .aviso.bad{ border-left-color:var(--bad); } .aviso.ok{ border-left-color:var(--ok); } .aviso.info{ border-left-color:var(--info); }
.spinner{ width:18px; height:18px; border:2px solid var(--border); border-top-color:var(--ink); border-radius:50%; animation:girar .8s linear infinite; }
@keyframes girar{ to{ transform:rotate(360deg); } }
.esqueleto{ background:linear-gradient(90deg, var(--surface-2) 25%, var(--surface-hover) 50%, var(--surface-2) 75%); background-size:200% 100%; animation:brillo 1.2s infinite; min-height:14px; }
@keyframes brillo{ to{ background-position:-200% 0; } }
kbd{ font-family:var(--font-mono); font-size:11px; padding:1px 5px; border:1px solid var(--border); background:var(--surface-2); }

/* ---------- 11. Recorrido interactivo (Driver.js con piel propia) ---------- */
.driver-popover.mugi{ background:var(--surface); color:var(--ink); border:1px solid var(--border-strong); border-radius:var(--radius-lg); box-shadow:var(--shadow-2); padding:16px; max-width:340px; font-family:var(--font-body); }
.driver-popover.mugi .driver-popover-title{ font-size:14px; font-weight:600; margin-bottom:6px; }
.driver-popover.mugi .driver-popover-description{ font-size:13px; color:var(--ink-soft); line-height:1.45; }
.driver-popover.mugi .driver-popover-progress-text{ font-family:var(--font-mono); font-size:11px; color:var(--ink-faint); }
.driver-popover.mugi button{ border-radius:var(--radius-md); text-shadow:none; font-weight:600; font-size:12.5px; padding:6px 12px; background:var(--surface); color:var(--ink); border:1px solid var(--border-strong); }
.driver-popover.mugi .driver-popover-next-btn{ background:var(--cta-bg); color:var(--cta-fg); border-color:var(--cta-bg); }
.driver-popover.mugi .driver-popover-arrow{ border-color:var(--border-strong); }

/* ---------- 12. Móvil ---------- */
@media (max-width:820px){
  :root{ --sidebar-w:0px; }
  /* Un solo patrón de "ventanita" (manual II.5, fallo 17): en móvil todo diálogo sube desde abajo como hoja
     inferior (igual que la ficha y "Más"); en escritorio, diálogo centrado y la ficha en panel lateral (.hoja). */
  .overlay{ align-items:flex-end; padding:0; }
  /* En móvil el modal es una hoja inferior de verdad: entra deslizando desde abajo (curva de
     Vaul), no creciendo desde el centro — mismo criterio que .mas-panel del plan 001. La salida
     usa --dur-2 (más lenta que el --dur-1 de escritorio): a 100% del ancho, un cierre de 120ms se
     ve como un corte seco, no como un deslizar hacia abajo. */
  .modal{ width:100%; max-height:92vh; border-radius:var(--radius-lg) var(--radius-lg) 0 0; border-bottom:none; transform:translateY(100%); opacity:1; transition:transform var(--dur-3) var(--ease-drawer); }
  .overlay.entra .modal{ transform:translateY(0); }
  .overlay.sale .modal{ transform:translateY(100%); opacity:1; transition-duration:var(--dur-2); }
  /* .hoja en móvil: mismo criterio que el modal de arriba — sube desde abajo, no desde la
     derecha (no hay "borde derecho" que respete en una pantalla de 390px de ancho). */
  .hoja{ right:0; left:0; width:100%; transform:translateY(100%); }
  .hoja.entra{ transform:translateY(0); }
  .hoja.sale{ transform:translateY(100%); }
  .fila-campos{ grid-template-columns:1fr; }
  .msg{ max-width:86%; }
  /* Safari de iOS hace zoom automático al enfocar un input con font-size menor a 16px — a los
     13.5px de siempre en desktop, cada campo disparaba ese zoom en el celular (hallazgo de la
     cacería, 2026-09-03). Solo en este breakpoint: en desktop se queda la densidad de siempre. */
  .input, .campo input:not([type=checkbox]):not([type=radio]), .campo select, .campo textarea, .buscador{
    font-size:16px;
  }
  /* D-MOVIL-QA ciclo 1 (5-sep, hallazgo #5): selects e inputs quedaban en 36-41px de alto en
     móvil, bajo los 44px de área táctil — el fix de arriba solo evitaba el zoom de iOS, no tocaba
     la altura. */
  .input, .campo input:not([type=checkbox]):not([type=radio]), .campo select, .campo textarea{
    min-height:44px;
  }
}
/* reduced-motion correcto (plan 001, Emil Kowalski): apagar TODO (incluida la opacidad) rompe la
   comprensión de un cambio de estado — la regla correcta es quitar el DESPLAZAMIENTO y conservar
   la opacidad/color. Los overlays/paneles con transform de entrada pasan a animar solo opacidad. */
@media (prefers-reduced-motion: reduce){
  *{ animation-duration:.01ms !important; }
  .overlay, .modal, .hoja, .toast, .bnd-popover-generico, .cuenta-menu, .nt-panel, .bnd-blk-menu-pop, .bnd-qr-popover, .tour-panel, .mas-panel{ transition-property:opacity !important; transition-duration:var(--dur-1) !important; transform:none !important; }
  /* .vd-sec-cuerpo-wrap (plan 005): grid-template-rows no es transform/opacity, así que no entra
     en la regla de arriba — es la excepción de acordeón, y ahí la animación ES el movimiento de
     verdad (la página crece/encoge), justo lo que reduced-motion pide quitar. Instantáneo, no
     "solo opacidad" (no hay nada sensato que fundir en un cambio de alto). */
  .vd-sec-cuerpo-wrap{ transition-duration:.01ms !important; }
}

/* ---------- 13. Buscador global (busqueda.js) ---------- */
.bq-overlay{ align-items:flex-start; padding-top:10vh; }
.bq{ width:min(640px,100%); max-height:70vh; display:flex; flex-direction:column; }
.bq-cab{ display:flex; align-items:center; gap:10px; padding:10px 12px; border-bottom:1px solid var(--border); }
.bq-cab .input{ flex:1; border:0; min-height:36px; font-size:15px; background:transparent; }
.bq-cab .input:focus{ box-shadow:0 0 0 2px var(--bg), 0 0 0 4px var(--accent); }
/* F-MOVIL-3 (5-sep, A2): #bq-input medía 36px en el celular, bajo los 44px de área táctil. Va
   DESPUÉS de la regla de arriba a propósito — misma especificidad (".bq-cab .input"), y en un
   empate de especificidad gana la que aparece último en el archivo, sin importar el media query
   (primer intento lo puse antes y no hacía nada, ver auditoría). */
@media (max-width:820px){ .bq-cab .input{ min-height:44px; } }
/* Fallo 2 del video de Nestor (7-sep-2026): la pista de teclado "Esc" no tiene sentido en un
   teléfono ("acá no hay el botón de escape") y encima era la señal que delataba el zoom. En su
   lugar, un botón "Cancelar" visible y tocable — la salida que un usuario de móvil busca primero,
   junto con el gesto atrás (busqueda.js). En escritorio no cambia nada: ahí manda el <kbd>. */
.bq-cancelar{ display:none; }
@media (max-width:820px){
  /* Fallo 2 del video de Nestor, la parte del "se descuadra todo": en el celular la paleta
     colgaba a 10vh del borde superior (.bq-overlay), con las esquinas redondeadas y la animación
     de una hoja INFERIOR — o sea entraba deslizando desde abajo para quedarse flotando a media
     pantalla, cortada en seco. Ni hoja ni pantalla. Pasa a ser una PANTALLA de búsqueda completa,
     que es el mismo patrón que ya usa "Más" por pedido explícito de Nestor (shell.css) y el que
     usan Spotlight y los buscadores de las apps de mensajería: campo arriba, resultados abajo,
     teclado al fondo. Se respeta el área segura arriba y abajo. En escritorio no cambia nada. */
  .bq-overlay{ align-items:stretch; padding-top:0; }
  .bq{ width:100%; max-height:none; height:100vh; height:100dvh; border:0; border-radius:0; }
  .bq-cab{ padding-top:calc(10px + env(safe-area-inset-top,0px)); }
  .bq-res{ flex:1; padding-bottom:env(safe-area-inset-bottom,0px); }
  .bq-cab kbd{ display:none; }
  .bq-cancelar{ display:inline-flex; align-items:center; justify-content:center; flex:none; min-height:44px; padding:0 10px; border:0; background:none; color:var(--accent-strong); font:inherit; font-size:15px; font-weight:600; cursor:pointer; -webkit-tap-highlight-color:transparent; }
}
.bq-res{ overflow:auto; }
.bq-fila{ width:100%; display:flex; align-items:center; gap:12px; padding:10px 14px; border:0; border-bottom:1px solid var(--border); background:transparent; text-align:left; font:inherit; color:var(--ink); cursor:pointer; }
.bq-fila:hover, .bq-fila:focus-visible{ background:var(--surface-hover); }
.bq-txt{ flex:1; display:flex; flex-direction:column; min-width:0; }
.bq-txt span{ white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.bq-pie{ padding:8px 14px; border-top:1px solid var(--border); font-size:11px; }

/* ---------- Popovers anclados (plan 003, Emil Kowalski, 2026-09-04) ----------
   Nace desde la esquina pegada a su disparador, no desde el centro ni de la nada — "los
   desplegables se abren en menos de un microsegundo y no sé de dónde provienen" (Nestor). El
   origen exacto (--origen) lo calcula origenDesde() de ui.js según dónde quede el popover
   respecto a su ancla; se aplica ADEMÁS de la clase propia de cada popover (.bnd-popover-generico,
   .cuenta-menu, .nt-panel, .bnd-blk-menu-pop, .bnd-qr-popover), nunca la reemplaza. */
.pop-anclado{ transform-origin:var(--origen, top left); transform:scale(0.96); opacity:0; transition:transform var(--dur-2) var(--ease-out), opacity var(--dur-2) var(--ease-out); }
.pop-anclado.entra{ transform:scale(1); opacity:1; }
.pop-anclado.sale{ transform:scale(0.98); opacity:0; transition-duration:var(--dur-1); }
/* Paleta de comandos (Ctrl/Cmd+.): acción de TECLADO — regla de Emil, nunca animarla (se repite
   cientos de veces al día). Le faltaba un origen visible, no movimiento: en vez de crecer, aparece
   al instante con una flechita (::before) apuntando a su disparador. --flecha-x la fija el JS al
   posicionar (centro horizontal del botón de acciones de la cabecera del hilo). */
.pop-instantaneo{ transition:none !important; transform:none !important; opacity:1 !important; }
.pop-instantaneo::before{ content:""; position:absolute; top:-5px; left:var(--flecha-x, 16px); width:8px; height:8px; background:var(--surface); border:1px solid var(--border-strong); border-right:none; border-bottom:none; transform:rotate(45deg); }

/* ---------- 14. Notificaciones (notificaciones.js) ---------- */
.nt-badge{ position:absolute; top:-4px; right:-4px; min-width:16px; height:16px; padding:0 4px; border-radius:var(--radius-pill, 0px); background:var(--ink); color:var(--bg); font-family:var(--font-mono); font-size:10px; font-weight:600; display:grid; place-content:center; }
.nt-badge.urgente{ background:var(--bad); color:#fff; }
.nt-panel{ position:fixed; width:min(380px, calc(100vw - 16px)); max-height:70vh; display:flex; flex-direction:column; background:var(--surface); border:1px solid var(--border-strong); box-shadow:var(--shadow-2); border-radius:var(--radius-lg); z-index:70; overflow:hidden; }
.nt-cab{ display:flex; align-items:center; justify-content:space-between; gap:10px; padding:12px 14px; border-bottom:1px solid var(--border); }
.nt-cab h3{ font-size:14px; }
.nt-lista{ overflow:auto; }
.nt-item{ width:100%; display:flex; align-items:center; gap:10px; padding:10px 14px; border:0; border-bottom:1px solid var(--border); background:transparent; text-align:left; font:inherit; color:var(--ink); cursor:pointer; }
.nt-item:hover{ background:var(--surface-hover); }
.nt-item.vista{ opacity:.6; }
.nt-txt{ flex:1; display:flex; flex-direction:column; min-width:0; font-size:13px; }
.nt-txt span{ color:var(--ink-soft); font-size:12px; }

/* ---------- 15. Diálogos propios (ui.js) ---------- */
.ui-dialogo{ width:min(440px,100%); }
.ui-dialogo .cabecera h3{ font-size:15px; }
.ui-form .cuerpo.fila-campos{ display:grid; gap:12px; grid-template-columns:1fr; }

/* Estado de error único (cacería): humano primero, técnico plegado */
.error-carga details{ margin-top:14px; font-size:12px; }
.error-carga summary{ cursor:pointer; color:var(--ink-faint); }
.error-carga code{ display:block; margin-top:6px; padding:8px 10px; background:var(--surface-2, var(--surface)); border:1px solid var(--border); border-radius:var(--radius-sm); font-size:11.5px; word-break:break-all; text-align:left; }

/* Pista visual de que hay más a la derecha (re-verificación 2026-09-03): degradado en el borde derecho de tablas y filas de
   pestañas desplazables. Solo decorativo; no bloquea el toque. */
.tabla-scroll, .tabs{ position:relative; }
.tabla-scroll::after, .tabs.scrollable::after{ content:""; position:absolute; top:0; right:0; bottom:0; width:28px; pointer-events:none; background:linear-gradient(to right, transparent, var(--surface)); opacity:0; transition:opacity .2s; }
.tabla-scroll.hay-mas::after, .tabs.scrollable.hay-mas::after{ opacity:1; }
/* F-5, ronda 2 de la cacería (2026-09-03): en una fila de PESTAÑAS (38-44px de alto) el degradado
   solo se percibía muy sutil — le sobra espacio a una tabla alta para que se note, no a esta fila
   angosta. Una flechita chica encima del degradado, mismo fade-in, sin agregar otro mecanismo. */
.tabs.scrollable::before{ content:""; position:absolute; top:50%; right:8px; width:6px; height:6px; border-top:2px solid var(--ink-faint); border-right:2px solid var(--ink-faint); transform:translateY(-50%) rotate(45deg); opacity:0; transition:opacity .2s; pointer-events:none; z-index:1; }
.tabs.scrollable.hay-mas::before{ opacity:1; }
/* Hallazgo D-7 (5-sep-2026): el degradado de arriba avisa "hay más pestañas" corriendo el scroll
   para que la pestaña ACTIVA entre completa (marcarScroll() en ui.js) — pero si esa pestaña es
   tan larga que ni corriendo el scroll al máximo alcanza a despejar los 28px del degradado (la
   siguiente pestaña le pisa los talones sin dejar margen de sobra), el degradado quedaba pintado
   ENCIMA de las últimas letras de lo que el usuario YA tiene seleccionado. marcarScroll() marca
   esta clase en ese caso puntual — se pierde el "asomo" de que hay una pestaña más, pero nunca se
   tapa el nombre de la pestaña activa. */
.tabs.scrollable.tabs-activa-bajo-fade::after, .tabs.scrollable.tabs-activa-bajo-fade::before{ opacity:0 !important; }
/* Hallazgo D-10, causa 2 (5-sep-2026): el degradado (::after) y el chevron (::before) eran hijos
   ABSOLUTOS del mismo elemento que hace scroll, así que viajaban con el contenido: al alinear la
   pestaña activa (scrollLeft 69) la mancha quedaba en 368−28−69 ≈ 271..299, en mitad de la pestaña.
   Ahora son ítems flex STICKY pegados al borde derecho del área visible (right:0 / right:8px): la
   caja visible los ancla, no el contenido. `order` los manda al final de la fila (el chevron es
   ::before, pero como ítem flex puede ir último); el margen negativo evita que sumen ancho. */
.tabs.scrollable::after{ position:sticky; top:auto; bottom:auto; right:0; order:98; flex:0 0 28px; margin-left:-28px; align-self:stretch; }
.tabs.scrollable::before{ position:sticky; top:auto; right:8px; order:99; flex:0 0 6px; margin-left:-6px; align-self:center; transform:rotate(45deg); z-index:1; }
/* Secuela (D, 05:05): con margen -14px el chevron RESTABA 8px al ancho intrínseco de las franjas de
   ancho automático (clientWidth 253 vs scrollWidth 261) y encendía hay-mas sin nada a la derecha.
   Margen -6px = ancho neto cero; el chevron sigue pegado a right:8px por el sticky. */

@media (max-width:820px){ .tabs button{ min-height:44px; } .segmentado button{ min-height:44px; } } /* objetivos táctiles (auditoría) — 40px no llegaba a los 44px que pide el manual de diseño */
/* F-7, ronda 2 de la cacería (2026-09-03): ".btn.chico" (28px) es el botón secundario más usado de
   toda la app — antes se venía subiendo a 44px módulo por módulo (Bandeja, Contactos, Equipo) cada
   vez que un audit lo encontraba de nuevo en OTRO módulo (Difusiones, Automatizaciones,
   Integraciones seguían en 28px). Una sola regla en el componente base para que no haga falta
   repetirla nunca más — las reglas puntuales que ya existían no estorban, quedan redundantes. */
@media (max-width:820px){ .btn.chico{ min-height:44px; } }
/* Cierre de la cacería nocturna (5-sep-2026): el ".btn" BASE (sin ".chico", 40px) tenía el mismo
   agujero que ya se cerró para ".chico" — "Recorrido de 3 minutos" (Inicio) y "Elegir
   destinatarios" (Difusiones) lo encontró el nuevo humo móvil de qa/smoke_prod.py --movil, primera
   vez que alguien corrió ese chequeo contra un ".btn" normal en vez de uno ".chico". Misma regla,
   mismo criterio: una sola vez en el componente base, no módulo por módulo. Los ".btn" con su
   propio ajuste puntual (p.ej. ".bnd-hilo-cab-acciones .btn" en 36px con área ampliada por
   ::before) ganan igual por especificidad — este mínimo no les toca nada. */
@media (max-width:820px){ .btn{ min-height:44px; } }
/* Hallazgo del humo móvil de producción (C-GIT-SYNC-3, 5-sep-2026): ".btn.icono" (34px de ancho,
   p.ej. "Más acciones" de Contactos móvil) solo tenía su min-width:44px gateado por
   "@media(pointer:coarse)" (más arriba en este archivo) — ese media no está matcheando en el
   entorno de qa/smoke_prod.py --movil, dejando el botón en 34px real pese a la regla. Mismo
   criterio que la línea de arriba para ".btn": el gate por ancho de viewport (max-width:820px)
   es el que de verdad dispara en el humo, así que el mínimo se repite aquí también. */
@media (max-width:820px){ .btn.icono, .btn.icono.chico{ min-width:44px; } }
/* Pulido móvil (programa nocturno 5-sep-2026): el track visual de .switch (38x22, tamaño
   estándar de un toggle iOS/Android — no se toca el dibujo) es más chico que el objetivo táctil
   de 44px. Mismo criterio que .bnd-tag-quitar (ficha.css): el ÁREA de toque crece con un
   ::before invisible, el dibujo del componente no cambia de tamaño. */
@media (max-width:820px){ .switch{ position:relative; } .switch::before{ content:""; position:absolute; inset:-11px -3px; } }
/* Pulido móvil (programa nocturno 5-sep-2026, hallazgo de D): la casilla de selección (Contactos
   y donde se reuse ".check") mide 16x16 — el dibujo del check ya usa ::before, así que el área de
   toque va en un ::after nuevo del <input>, mismo criterio que .switch arriba. */
@media (max-width:820px){ .check input{ position:relative; } .check input::after{ content:""; position:absolute; inset:-14px; } }

/* Pase final "hiperpulido" (sesión C, 5-sep-2026): TODOS los <select> de la app (".campo select",
   min-height:36px de la regla base de arriba) medían 25px reales en WebKit/Safari — confirmado con
   Playwright WebKit+iPhone13 en 4 módulos distintos (Vendedor IA, Contactos, Pedidos›Despacho,
   Reportes), o sea que es un problema del ELEMENTO, no de un módulo puntual. Causa (probada en
   vivo, no supuesta): un <select> con su apariencia nativa (appearance:auto, la de por defecto)
   IGNORA min-height/padding/font-size de autor en WebKit — el getComputedStyle de la cascada SÍ
   muestra los valores de ".campo select", pero la caja RENDERIZADA usa el tamaño intrínseco nativo
   igual; agregar solo "min-height:44px !important" sin tocar appearance no cambia nada, agregarlo
   JUNTO con appearance:none sí (probado inyectando ambas variantes contra el mismo elemento).
   Chromium no tiene este bug — por eso nunca apareció en los ciclos de auditoría anteriores, todos
   corridos en Chromium. Fix: appearance:none le devuelve el control del tamaño a esta regla; la
   flechita nativa perdida se repone con dos gradientes en forma de "v" (mismo criterio sin SVG ni
   color pegado a fuego que .tabs.scrollable::before, que ya arma una flecha con bordes+rotate). */
@media (max-width:820px){
  .campo select, select.input{
    appearance:none; -webkit-appearance:none; min-height:44px; padding:10px 34px 10px 10px;
    background-image:
      linear-gradient(45deg, transparent 50%, var(--ink-faint) 50%),
      linear-gradient(135deg, var(--ink-faint) 50%, transparent 50%);
    background-position: calc(100% - 20px) center, calc(100% - 15px) center;
    background-size: 5px 5px, 5px 5px;
    background-repeat: no-repeat;
  }
}

@media (max-width:820px){ .bq-pie{ display:none; } } /* A-10: el atajo Ctrl+K no aplica en el celular */

/* ============================================================
   iOS: CERO ZOOM AL ENFOCAR UN CAMPO (fallo 2 del video de Nestor, 7-sep-2026)
   ============================================================
   "Cuando le doy clic acá a Buscar en Mugi como que se hace zoom... y se descuadra todo".
   WebKit en iPhone amplía la página automáticamente al enfocar cualquier control de formulario
   cuyo tamaño de letra sea MENOR a 16px, y al salir no siempre devuelve la escala: de ahí el
   descuadre al cerrar. Los campos de Mugi estaban en 13,5px (.input, .campo) y 15px (la paleta),
   todos por debajo del umbral.
   La otra salida sería "user-scalable=no" en el meta viewport, pero eso le quita al usuario el
   pellizco para ampliar (WCAG 1.4.4) — no se toca el meta, se suben los campos.
   Solo aplica bajo 820px: en escritorio no cambia ni un píxel. Afecta a lo que se ESCRIBE
   (input/textarea/select), no a botones, chips ni etiquetas. */
@media (max-width:820px){
  .input,
  .bq-cab .input,
  .buscador,
  input:not([type=checkbox]):not([type=radio]):not([type=range]),
  select,
  textarea{ font-size:16px; }
}

.switch:disabled{ opacity:.45; cursor:not-allowed; } /* D-8 */
/* Recorrido guiado (driver.js) en móvil: "Omitir" y "Atrás/Siguiente" medían menos de 44 px y el humo móvil rechazaba entregas (5-sep-2026). Tamaño real, no pseudoelemento. */
@media (max-width:820px){ .driver-popover .driver-popover-close-btn, .driver-popover .driver-popover-navigation-btns button{ min-height:44px; min-width:44px; box-sizing:border-box; } }
/* Botón "← Atrás/Menú" de la sub-barra móvil (.movil-subnav-btn, 58×30) también medía menos de 44 px. */
@media (max-width:820px){ .movil-subnav-btn{ min-height:44px; box-sizing:border-box; } }
