/*
  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{ 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; }
@media (max-width:820px){ .toasts{ left:12px; right:12px; bottom:calc(12px + 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;
  }
}
/* 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); }
.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; }

@media (max-width:820px){ .tabs button{ min-height:44px; } .segmentado button{ min-height:40px; } } /* objetivos táctiles (auditoría) */
/* 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; } }

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

.switch:disabled{ opacity:.45; cursor:not-allowed; } /* D-8 */
