/* =====================================================
   SURFIA — Panel del negocio
   Estética: marino/océano/aqua, tipografía Sora + IBM Plex Mono.
   Claro y oscuro desde el día 1 (DASHBOARD-SPEC §6).
   ============================================================ */

/* Tipografías propias (épico #404, PR 9b). Antes venían de Google Fonts: sin
   señal el panel cambiaba de letra y la bienvenida esperaba a otro servidor.
   Subconjunto latino en woff2 (~55 KB en total); Sora es variable (400-700).
   URLs absolutas bajo /assets/fonts/: la release copia frontend/ entero y el
   builder solo fija los assets del index, no los del CSS. */
@font-face {
  font-family: 'Sora'; font-style: normal; font-weight: 400 700; font-display: swap;
  src: url(/assets/fonts/sora-latin.woff2) format('woff2');
}
@font-face {
  font-family: 'IBM Plex Mono'; font-style: normal; font-weight: 500; font-display: swap;
  src: url(/assets/fonts/ibm-plex-mono-500-latin.woff2) format('woff2');
}
@font-face {
  font-family: 'IBM Plex Mono'; font-style: normal; font-weight: 600; font-display: swap;
  src: url(/assets/fonts/ibm-plex-mono-600-latin.woff2) format('woff2');
}
@font-face {
  font-family: 'IBM Plex Mono'; font-style: normal; font-weight: 700; font-display: swap;
  src: url(/assets/fonts/ibm-plex-mono-700-latin.woff2) format('woff2');
}

:root {
  /* marca — mismos valores que el logo Flujo v2 */
  --marino: #0A1628;
  --brand: #0284C7;        /* océano */
  --brand-deep: #0E7490;   /* cian-marino */
  --aqua: #22D3EE;
  --aqua-soft: rgba(34, 211, 238, .12);
  --brand-grad: linear-gradient(135deg, #0284C7, #22D3EE);

  /* Las tres corrientes del logo. En claro NO pueden ser los colores de marca:
     el aqua da 1,7:1 contra el fondo y la corriente de arriba desaparece. Esta
     escala baja un paso y deja las tres sobre 3:1 sin perder la profundidad. */
  --logo-1: #0891B2;
  --logo-2: #0369A1;
  --logo-3: #0C4A6E;

  /* El marco de la loseta «Cresta». No cambia con el tema a propósito: no es un
     color de fondo, es el aviso de que al tocarla el panel se pone blanco. */
  --cresta-marco: #FFFFFF;

  /* El plato bajo el logo del negocio en la barra. Tampoco cambia con el tema,
     y por la misma clase de razón: es el MISMO archivo que se imprime sobre el
     blanco de su cotización. Sobre el degradado de marca un logo transparente
     se pierde, y sobre el --card oscuro desaparece uno de tinta negra. */
  --logo-plate: #FFFFFF;

  --bg: #F2F6FA;
  --bg-glow: radial-gradient(1200px 600px at 85% -10%, rgba(34, 211, 238, .14), transparent 60%),
             radial-gradient(900px 500px at -10% 110%, rgba(2, 132, 199, .10), transparent 55%);
  --card: #FFFFFF;
  --card-2: #F7FAFC;
  --ink: #0A1628;
  --ink-2: #3B4B61;
  --ink-3: #7C8BA1;
  --line: #E3EAF2;
  --line-2: #EDF2F7;

  /* semántico — independiente de la marca, a propósito */
  --ok: #0E9F6E;   --ok-soft: #E6F6F0;
  --warn: #C98A2B; --warn-soft: #FBF3E4;
  --sobre-marino: #E9F1F9;   /* tinta clara sobre --marino (toast, tooltip): igual en los dos temas */
  --bad: #D64545;  --bad-soft: #FBEAEA;
  --bad-ink: #FFFFFF;   /* tinta legible ENCIMA de --bad (el contador de pendientes) */
  /* tinta legible sobre los fondos suaves (el --warn puro da 2.66:1 en claro) */
  --warn-ink: #8A5A14;
  --hl-ink: #0E7490;

  /* canales */
  --wa: #1FAF5A;   --wa-soft: #E7F6EC;
  --ig: #DD2A7B;   --ig-soft: #FBE9F2;
  --ig-grad: linear-gradient(135deg, #F58529, #DD2A7B, #8134AF);

  --shadow: 0 1px 2px rgba(10, 22, 40, .04), 0 8px 24px -12px rgba(2, 132, 199, .12);
  --shadow-lift: 0 2px 4px rgba(10, 22, 40, .05), 0 16px 40px -16px rgba(2, 132, 199, .22);
  --r: 16px;
  --r-sm: 12px;      /* controles: botones, campos, alertas */
  --r-pill: 999px;   /* todo lo que es una etiqueta: cápsula, sin excepción */

  /* Movimiento: dos duraciones y una curva para toda la hoja. Antes había
     ocho combinaciones distintas y la interfaz se sentía de varias manos. */
  --t-fast: .15s; --t-med: .3s; --ease: cubic-bezier(.2, .8, .2, 1);

  /* Acentos translúcidos con nombre: estaban escritos crudos en ~20 sitios. */
  --aqua-25: rgba(34, 211, 238, .25);
  --aqua-35: rgba(34, 211, 238, .35);

  /* Sombras que no dependen del tema claro. La de la barra inferior y la de
     los flotantes iban en rgba(10,22,40): sobre el marino son invisibles. */
  --shadow-up: 0 -8px 24px -12px rgba(10, 22, 40, .15);
  --shadow-pop: 0 12px 32px -8px rgba(10, 22, 40, .55);

  --font: Sora, "Avenir Next", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, monospace;
}

/* ⚠️ Este bloque y el `[data-theme="dark"]` de abajo son GEMELOS y hay que
   mantenerlos a la vez: son la misma lista de variables escrita dos veces,
   porque CSS no deja compartir un bloque entre una media query y un selector.
   Llegué a borrar este por parecer código muerto —hoy no se evalúa, ya que el
   HTML fija `data-theme="dark"`— y el eval `panel-entrada.test.js` lo cazó:
   es el que hace que el panel siga el tema del sistema si algún día se quita
   ese atributo. Si tocas un color aquí, tócalo también abajo. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    /* sobre el marino sí lucen los colores de marca */
    --logo-1: #22D3EE; --logo-2: #0284C7; --logo-3: #0E7490;
    --bg: #07101E;
    --bg-glow: radial-gradient(1200px 600px at 85% -10%, rgba(34, 211, 238, .08), transparent 60%),
               radial-gradient(900px 500px at -10% 110%, rgba(2, 132, 199, .07), transparent 55%);
    --card: #0C1930; --card-2: #0A1526;
    --ink: var(--sobre-marino); --ink-2: #B4C4D8; --ink-3: #7C90AB;
    --line: #1A2C46; --line-2: #14243B;
    /* Sobre el marino, el azul, el rojo y el verde de marca tienen que subir un
       paso — el mismo motivo por el que suben --logo-1/2/3, solo que al revés.
       Con los valores del tema claro daban 4,28 y 4,01 sobre la tarjeta: por
       debajo del 4,5 que exige un texto pequeño. Ahora dan 8,19 y 6,34.
       Se puede cambiar --brand sin miedo porque en toda la hoja NO se usa ni
       una vez como fondo: los rellenos son --brand-grad. */
    --brand: #38BDF8;
    --bad: #F87171;
    --bad-ink: #0A1628;   /* el rojo del tema oscuro es claro: la tinta va oscura */
    --ok: #34D399;
    --aqua-soft: rgba(34, 211, 238, .10);
    --ok-soft: rgba(14, 159, 110, .14);
    --warn-soft: rgba(201, 138, 43, .14);
    --bad-soft: rgba(214, 69, 69, .14);
    --wa-soft: rgba(31, 175, 90, .13);
    --ig-soft: rgba(221, 42, 123, .13);
    --warn-ink: #DFAF63;
    --hl-ink: #22D3EE;
    --shadow: 0 1px 2px rgba(0, 0, 0, .2), 0 8px 24px -12px rgba(0, 0, 0, .4);
    --shadow-lift: 0 2px 4px rgba(0, 0, 0, .25), 0 16px 40px -16px rgba(34, 211, 238, .15);
  }
}

:root[data-theme="dark"] {
  /* sobre el marino sí lucen los colores de marca */
  --logo-1: #22D3EE; --logo-2: #0284C7; --logo-3: #0E7490;
  --bg: #07101E;
  --bg-glow: radial-gradient(1200px 600px at 85% -10%, rgba(34, 211, 238, .08), transparent 60%),
             radial-gradient(900px 500px at -10% 110%, rgba(2, 132, 199, .07), transparent 55%);
  --card: #0C1930; --card-2: #0A1526;
  --ink: var(--sobre-marino); --ink-2: #B4C4D8; --ink-3: #7C90AB;
  --line: #1A2C46; --line-2: #14243B;
  /* ver la nota de contraste en el bloque de arriba */
  --brand: #38BDF8;
  --bad: #F87171;
  --bad-ink: #0A1628;   /* el rojo del tema oscuro es claro: la tinta va oscura */
  --ok: #34D399;
  --aqua-soft: rgba(34, 211, 238, .10);
  --ok-soft: rgba(14, 159, 110, .14);
  --warn-soft: rgba(201, 138, 43, .14);
  --bad-soft: rgba(214, 69, 69, .14);
  --wa-soft: rgba(31, 175, 90, .13);
  --ig-soft: rgba(221, 42, 123, .13);
  --warn-ink: #DFAF63;
  --hl-ink: #22D3EE;
  --shadow: 0 1px 2px rgba(0, 0, 0, .2), 0 8px 24px -12px rgba(0, 0, 0, .4);
  --shadow-lift: 0 2px 4px rgba(0, 0, 0, .25), 0 16px 40px -16px rgba(34, 211, 238, .15);
  --shadow-up: 0 -8px 24px -12px rgba(0, 0, 0, .55);
  --shadow-pop: 0 12px 32px -8px rgba(0, 0, 0, .7);
}

* { box-sizing: border-box; margin: 0; padding: 0 }

/* `hidden` tiene que ganarle a cualquier `display` que declaremos después: si
   no, una regla como `.side .foot button { display:block }` revive un botón ya
   marcado como oculto. Pasó con "Salir" y con el banner de negocio pendiente. */
[hidden] { display: none !important }
html, body { height: 100% }
body {
  font-family: var(--font);
  background: var(--bg); color: var(--ink); line-height: 1.45;
  -webkit-font-smoothing: antialiased;
}
body::before { content: ""; position: fixed; inset: 0; background: var(--bg-glow); pointer-events: none; z-index: 0 }
button { font: inherit; color: inherit; background: none; border: none; cursor: pointer }
input { font: inherit }

/* En el teléfono ningún campo de texto baja de 16px. iOS amplía la página
   entera al enfocar un input/textarea/select más pequeño —y no la vuelve a
   encoger al salir—: el hilo se veía ampliado ~1,2× con «Atiendo yo» y
   «Enviar» cortados por la derecha (captura de Luis, 2-sep-2026). Es una regla
   del dispositivo, no de un componente, y por eso lleva !important: tiene que
   ganarle a cualquier tamaño que declare una hoja que carga después
   (thread-mobile.css, fuentes.css) y a cualquier componente futuro. Ojo: también
   es un techo — un control móvil que quiera MÁS de 16px lo declara con
   !important. La otra salida, maximum-scale=1 en el viewport, deja sin
   pellizco a Android y se descarta. */
@media (max-width: 820px) {
  input, textarea, select { font-size: 16px !important }
}

.app { position: relative; z-index: 1; display: grid; grid-template-columns: 232px minmax(0, 1fr); min-height: 100vh }
.main { min-width: 0; padding: 20px 26px 90px; max-width: 1060px; width: 100%; margin: 0 auto }

/* ---------- logo (Flujo v2) ---------- */
.logo { display: flex; align-items: center; gap: 10px; padding: 0 8px }
.logo .mark { width: 34px; height: 30px; display: grid; place-items: center }
.logo .mark svg { width: 32px; height: 28px }
.logo .word { font-size: 20px; font-weight: 700; letter-spacing: -.03em }

/* ---------- sidebar ---------- */
.side {
  padding: 22px 14px; border-right: 1px solid var(--line);
  display: flex; flex-direction: column; gap: 26px; position: sticky; top: 0; height: 100vh;
}
.nav { display: flex; flex-direction: column; gap: 2px }
.nav button {
  display: flex; align-items: center; gap: 11px; padding: 10px 12px; border-radius: 10px;
  font-size: 14.5px; font-weight: 500; color: var(--ink-2); text-align: left; transition: all .15s;
}
.nav button svg { width: 18px; height: 18px; opacity: .75; flex: none }
/* «Mi Surfia» lleva el logo, no un icono de línea, y el logo no juega con las
   mismas reglas: su viewBox es 52×46 —no cuadrado— y sus trazos salen de
   --logo-1/2/3, no de currentColor. Se le conserva el ANCHO de 18px para que
   el texto del menú siga alineado en columna, y opacidad plena: al .75 del
   resto las tres corrientes se empastan y el logo se lee como una mancha. */
.nav button[data-screen="probar"] svg { width: 18px; height: 16px; opacity: 1 }
.nav button:hover { background: var(--card-2); color: var(--ink) }
.nav button.on { background: var(--aqua-soft); color: var(--brand); font-weight: 600 }
.nav button.on svg { opacity: 1 }
.nav .badge {
  margin-left: auto; background: var(--bad); color: var(--bad-ink); font-size: 10.5px; font-weight: 700;
  min-width: 17px; height: 17px; border-radius: 9px; display: grid; place-items: center; padding: 0 5px;
}
.side .foot {
  margin-top: auto; padding: 12px; border-radius: var(--r-sm); background: var(--card-2);
  border: 1px solid var(--line-2); font-size: 12px; color: var(--ink-3);
}
.side .foot b { color: var(--ink-2); display: block; font-size: 12.5px; margin-bottom: 2px }
.side .foot .dot {
  display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: var(--ok);
  margin-right: 5px;
}
.side .foot button { display: block; font-size: 12px; color: var(--brand); font-weight: 600; margin-top: 9px }
.side .foot #agent-line { display: block }
/* La ficha del cliente bajo el nombre del hilo (épico #404, PR 8). */
.who .ficha { display: block; font-size: 11.5px; color: var(--ink-3); margin-top: 2px; white-space: normal; line-height: 1.35 }
/* Corregir la ficha a mano (#404). El correo es un BOTÓN porque copiarlo es la
   acción —el dueño viene de hacer el presupuesto y le falta el destinatario—,
   no un texto que haya que seleccionar a dedo en un teléfono. */
.who .ficha .ficha-correo, .who .ficha .ficha-editar {
  font: inherit; color: var(--brand); background: none; border: 0; padding: 0 0 0 6px; cursor: pointer;
}
.who .ficha .ficha-sep { color: var(--ink-3) }
.who .ficha .ficha-editar { text-decoration: underline; text-underline-offset: 2px }
.who .ficha .ficha-correo:hover, .who .ficha .ficha-editar:hover { text-decoration: underline }
/* El formulario vive DENTRO de la cabecera: corregir el dato es parte de mirar
   el chat, no una pantalla aparte a la que haya que ir y volver. */
.ficha-form { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; margin-top: 8px; max-width: 520px }
.ficha-campo { display: flex; flex-direction: column; gap: 2px; min-width: 0 }
.ficha-campo span { font-size: 11px; color: var(--ink-3); font-weight: 600 }
.ficha-campo input {
  font-size: 13px; padding: 6px 8px; border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--card); color: var(--ink); min-width: 0; width: 100%;
}
.ficha-campo input:focus { outline: 2px solid var(--brand); outline-offset: -1px }
.ficha-nota, .ficha-acciones { grid-column: 1 / -1 }
.ficha-nota { font-size: 11px; color: var(--ink-3); margin: 0 }
.ficha-acciones { display: flex; align-items: center; gap: 8px }
.ficha-msg { font-size: 11.5px; color: var(--ink-2) }
/* En el teléfono los cuatro campos van uno debajo de otro: dos columnas de
   170 px dejan el RIF y el correo ilegibles justo donde más se teclean. */
@media (max-width: 620px) { .ficha-form { grid-template-columns: minmax(0, 1fr) } }
.cuenta-acciones { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px }
/* Te pidieron y no tiene precio (épico #404) */
.sin-precio-lista { margin-top: 8px }
.sin-precio-fila { display: flex; align-items: center; gap: 12px; padding: 9px 0; border-top: 1px solid var(--line) }
.sin-precio-fila:first-child { border-top: 0 }
.sin-precio-fila .what { flex: 1; min-width: 0 }
.sin-precio-fila .what b { display: block; font-size: 14px }
.sin-precio-fila .what span { color: var(--ink-3); font-size: 12.5px }
.sin-precio-fila .lnk { color: var(--brand); font-weight: 600; font-size: 12.5px; background: none; border: 0; padding: 0; cursor: pointer }
.sin-precio .pill { font-size: 12px; color: var(--ink-3) }
/* Estado del canal y del sistema (épico #404) */
.setup-status.warning { color: var(--warn) }
.setup-status.expired { color: var(--bad) }
.install-bar.estado-offline { border-color: var(--warn) }
.magazine-hoja { width: min(720px, calc(100vw - 24px)); max-height: calc(100vh - 24px); display: flex; flex-direction: column; padding: 14px }
.magazine-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 10px }
.magazine-head h3 { margin: 0 }
.magazine-marco { flex: 1; width: 100%; min-height: min(70vh, 720px); border: 1px solid var(--line); border-radius: 10px; background: #fff }
.consumo-aviso { color: var(--warn); font-weight: 600 }
/* «Cómo quieres ver a Surfia»: Ola · Cresta · Marea (épico #404). Cada loseta
   enseña un trozo del logo y el nombre vive en su lienzo — ver tema.js. */
.tema-titulo { display: block; color: var(--ink); font-size: 21px; letter-spacing: -.01em }
.tema-losetas { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; margin-top: 12px }
.tema-loseta {
  position: relative; height: 156px; padding: 0; text-align: left;
  background: var(--bg); border: 1px solid var(--line); border-radius: 14px;
  transition: border-color var(--t-fast) var(--ease);
}
.tema-loseta:hover { border-color: var(--aqua-35) }
.tema-lienzo { position: absolute; inset: 0; overflow: hidden; border-radius: 13px; background: var(--bg) }
.tema-art { position: absolute; left: 50%; transform: translateX(-50%); width: 148px }
.tema-loseta[data-tema="oscuro"] .tema-art { top: 34px }
.tema-loseta[data-tema="claro"] .tema-art { top: 6px }
.tema-loseta[data-tema="sistema"] .tema-art { top: 2px }
/* El rótulo trae su propio suelo. Sin él el nombre cae sobre la corriente y
   «como el teléfono», a 11,5 px sobre el marino, da 4,49:1 — por debajo del 4,5
   que pide un texto pequeño. El degradado deja que la ola se hunda detrás. */
.tema-lab {
  position: absolute; left: 0; right: 0; bottom: 0; padding: 26px 12px 11px;
  background: linear-gradient(to top, var(--bg) 62%, transparent);
}
.tema-lab b { display: block; color: var(--ink); font-size: 16px; line-height: 1.2 }
.tema-lab span { display: block; color: var(--ink-3); font-size: 11.5px; margin-top: 2px }
/* La elegida va en --brand y no en --aqua: sobre el blanco el aqua da 1,7:1 y
   el aro se perdería justo en el tema que Cresta enciende. */
.tema-loseta.on { border-color: var(--brand); box-shadow: inset 0 0 0 1px var(--brand) }
.tema-check {
  position: absolute; top: 9px; right: 9px; z-index: 2; width: 20px; height: 20px;
  border-radius: var(--r-pill); background: var(--brand); color: var(--marino); display: grid; place-items: center;
}
.tema-check svg { width: 12px; height: 12px; fill: none; stroke: currentColor; stroke-width: 2.5 }

/* El marco blanco de Cresta cuelga de la OPCIÓN, no de «la elegida»: avisa de
   que al tocarla el panel se pone blanco, y eso es verdad esté elegida o no. */
.tema-loseta[data-tema="claro"] { background: var(--cresta-marco); padding: 12px }
.tema-loseta[data-tema="claro"] .tema-lienzo { inset: 12px; border-radius: 6px }
.tema-loseta[data-tema="claro"] .tema-art { width: 118px }

/* En el teléfono la loseta es ancha y baja: el dibujo se encoge y sube, o el
   suelo del rótulo se traga la corriente de abajo de Ola y parece que solo
   tuviera una. */
@media (max-width: 820px) {
  .tema-losetas { grid-template-columns: 1fr }
  .tema-loseta { height: 140px }
  .tema-art { width: 130px }
  .tema-loseta[data-tema="oscuro"] .tema-art { top: 12px }
  .tema-loseta[data-tema="sistema"] .tema-art { top: 2px }
}
.actualizado { font-size: 11.5px; color: var(--ink-3); background: none; border: 0; padding: 4px 8px; cursor: pointer; white-space: nowrap }
.actualizado:hover { color: var(--ink-2) }

/* ---------- barra de estado de datos ---------- */
.databar {
  display: flex; align-items: center; gap: 10px; padding: 9px 14px; border-radius: var(--r-sm);
  font-size: 12.5px; margin-bottom: 16px; border: 1px solid;
}
.databar.demo { background: var(--aqua-soft); border-color: rgba(34, 211, 238, .3); color: var(--ink-2) }
.databar.live { background: var(--ok-soft); border-color: rgba(14, 159, 110, .3); color: var(--ink-2) }
.databar.err  { background: var(--bad-soft); border-color: rgba(214, 69, 69, .3); color: var(--ink-2) }
.databar b { color: var(--ink) }
.databar button { margin-left: auto; font-size: 12px; font-weight: 700; color: var(--brand); white-space: nowrap }

/* ---------- topbar ---------- */
.top { display: flex; align-items: center; gap: 14px; margin-bottom: 18px; flex-wrap: wrap }
.top .biz { display: flex; align-items: center; gap: 10px }
.top .biz .av {
  width: 38px; height: 38px; border-radius: 12px; background: var(--brand-grad); color: #fff;
  display: grid; place-items: center; font-weight: 700; font-size: 15px;
}
.top .biz .nm { font-weight: 700; font-size: 16px; letter-spacing: -.01em }
.top .biz .sub { font-size: 12.5px; color: var(--ink-3) }
.top .sp { flex: 1 }
.seg { display: flex; background: var(--card); border: 1px solid var(--line); border-radius: var(--r-sm); padding: 3px; box-shadow: var(--shadow) }
.seg button { padding: 6px 13px; border-radius: 8px; font-size: 12.5px; font-weight: 600; color: var(--ink-3); transition: all .15s }
.seg button.on { background: var(--aqua-soft); color: var(--brand) }

.chips { display: flex; gap: 8px; margin-bottom: 20px; overflow-x: auto; padding-bottom: 2px; scrollbar-width: none }
.chips::-webkit-scrollbar { display: none }
/* Las categorías del catálogo (#inv-cats) en ESCRITORIO se ven enteras y bajan
   de línea. Con el scrollbar oculto y sin el degradé del móvil, la fila que se
   deslizaba parecía cortada a secas: «Food Storage Containe» (Chez Toto,
   15-sep-2026). Una categoría que no se ve es una categoría que no se filtra.
   En el móvil sigue deslizándose con su degradé (regla de más abajo). */
@media (min-width: 821px) {
  #inv-cats { flex-wrap: wrap; overflow-x: visible; row-gap: 8px }
}
.chip {
  display: flex; align-items: center; gap: 7px; padding: 7px 14px; border-radius: var(--r-pill); white-space: nowrap;
  background: var(--card); border: 1px solid var(--line); font-size: 13px; font-weight: 600; color: var(--ink-2);
  transition: all .15s; box-shadow: var(--shadow); scroll-snap-align: start;
}
.chip svg { width: 14px; height: 14px }
.chip.on { border-color: var(--brand); color: var(--brand); background: var(--aqua-soft) }
.chip .n { font-size: 12px; font-weight: 600; color: var(--ink-3) }
.chip.on .n { color: var(--brand) }
/* Canal de pruebas: se ve, pero en segundo plano y con borde punteado — que
 * nadie lo confunda con un canal por el que llegan clientes. */
.chip.tech { border-style: dashed; color: var(--ink-3); opacity: .75 }
.chip.tech.on { opacity: 1 }

h1 { font-size: 22px; font-weight: 700; letter-spacing: -.02em; margin-bottom: 4px }
.sub-h { color: var(--ink-3); font-size: 14px; margin-bottom: 20px }
.sub-h b { color: var(--brand); font-weight: 600 }
/* Antes: 12px, gris y en MAYÚSCULAS — el rótulo pesaba MENOS que el contenido
   que estaba separando, así que bajar por Inicio era recorrer una lista plana.
   Ahora se lee primero y en tinta plena: la pantalla tiene capítulos. */
h2 { font-size: 15px; font-weight: 600; letter-spacing: -.01em; color: var(--ink); margin: 30px 0 12px }

.screen { display: none; animation: in .3s ease }
.screen.on { display: block }
@keyframes in { from { opacity: 0; transform: translateY(6px) } to { opacity: 1; transform: none } }

.empty { text-align: center; color: var(--ink-3); font-size: 13.5px; padding: 26px 16px }

/* ---------- el número que preside ----------
   Una sola cifra manda en la pantalla. Antes había seis tarjetas iguales y
   ninguna era la primera que se miraba.

   El orden se cambia con flexbox y no moviendo el HTML: el saludo se encoge a
   una línea de entrada, el número sube inmediatamente detrás —tiene que caber
   en el primer vistazo, sin desplazar— y la frase de contexto baja a
   explicarlo. Todo lo demás conserva su orden de origen. */
/* ⚠️ `.on` es obligatorio: las pantallas se conmutan con `.screen.on { display:
   block }`, y un `#s-inicio { display: flex }` a secas le gana por
   especificidad — Inicio se quedaba pegado encima de Chats, Ventas y las demás. */
#s-inicio.on { display: flex; flex-direction: column }
#s-inicio > * { order: 4 }
#s-inicio > #greet { order: 1; font-size: 15px; font-weight: 600; color: var(--ink-3); margin-bottom: 6px }
#s-inicio > .hero-num { order: 2 }
#s-inicio > #greet-sub { order: 3 }

.hero-num { margin: 0 0 4px }
.hero-num__go { display: block; width: 100%; text-align: left; padding: 0 }
.hero-num__val {
  display: block;
  font-size: clamp(52px, 15vw, 76px);
  font-weight: 700;
  letter-spacing: -.045em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  /* el degradado de marca sobre el número, no detrás: es el único sitio de la
     pantalla donde el color de Surfia aparece a este tamaño */
  background: linear-gradient(120deg, var(--ink) 12%, var(--aqua) 130%);
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
}
.hero-num__meta { display: flex; align-items: center; gap: 10px; margin-top: 10px; flex-wrap: wrap }
.hero-num__lbl { font-size: 14px; color: var(--ink-2) }
.hero-num__meta .trend { font-size: 11.5px; font-weight: 700; font-family: var(--mono); padding: 3px 9px; border-radius: var(--r-pill) }
/* desglose del gestionado: "$X cotizado · $Y vendido" */
.hero-num__desglose { display: block; margin-top: 5px; font-size: 12.5px; color: var(--ink-3); font-variant-numeric: tabular-nums }
.hero-num__meta .trend.up { color: var(--ok); background: var(--ok-soft) }
.hero-num__meta .trend.dn { color: var(--bad); background: var(--bad-soft) }

/* ---------- alertas ---------- */
.alerts { display: flex; flex-direction: column; gap: 8px; margin-bottom: 20px }
/* Barra de color a la izquierda en vez de caja pastel: sobre fondo oscuro los
   rellenos suaves se convierten en manchas y todas las alertas se parecen. */
.alert {
  display: flex; align-items: center; gap: 10px;
  padding: 13px 14px 13px 12px;
  border-radius: var(--r-sm);
  font-size: 13.5px; font-weight: 500;
  border: 1px solid var(--line);
  border-left: 3px solid var(--ink-3);
  background: var(--card);
}
.alert.warning  { border-color: var(--line); border-left-color: var(--warn); background: var(--card); color: var(--ink) }
.alert.critical { border-color: rgba(214, 69, 69, .4); border-left-color: var(--bad); background: var(--card); color: var(--ink) }
.alert.ok { border-left-color: var(--ok) }
.alert .ico { font-size: 15px }
.alert .go { margin-left: auto; font-size: 12.5px; font-weight: 700; color: var(--brand); white-space: nowrap }
/* La barra entera es el botón: en el teléfono, apuntarle al «Ver →» es un
   ejercicio de puntería. El reset global de `button` (arriba) ya quitó fondo y
   borde propios, así que solo hay que devolverle el ancho y la alineación que
   un div traía de fábrica. */
button.alert { width: 100%; text-align: left }
button.alert:hover { border-color: var(--brand); background: var(--card-2) }
button.alert:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px }
/* Un solo foco para toda la hoja: 2px de marca, separado 2px. Las variantes
   con halo extra se quitaron abajo — competían con el color de estado. */

/* ---------- KPIs ----------
   Segundo plano a propósito: la cifra que manda ya está arriba, y estas son el
   detalle para quien quiera bajar a mirarlo. */
.kpis { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px }
.kpi {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--r); padding: 15px 16px 13px;
  box-shadow: var(--shadow); transition: transform .18s, box-shadow .18s; position: relative; overflow: hidden; min-width: 0;
}
.kpi:hover { transform: translateY(-2px); box-shadow: var(--shadow-lift) }
.kpi .lbl { font-size: 12px; font-weight: 600; color: var(--ink-3); padding-right: 56px }
.kpi .val { font-size: 26px; font-weight: 700; letter-spacing: -.03em; margin: 5px 0 8px; font-variant-numeric: tabular-nums }
.kpi .val small { font-size: 14px; color: var(--ink-3); font-weight: 600 }
.kpi .split { display: flex; flex-wrap: wrap; gap: 6px 10px; font-size: 12px; color: var(--ink-3) }
.kpi .split span { display: flex; align-items: center; gap: 5px }
.kpi .split i { width: 8px; height: 8px; border-radius: 3px; flex: none }
.kpi .split svg { width: 12px; height: 12px; flex: none }
.kpi .split .whatsapp i { background: var(--wa) }
.kpi .split .instagram i { background: var(--ig-grad) }
.kpi .trend { position: absolute; top: 14px; right: 14px; font-size: 11px; font-weight: 700; font-family: var(--mono); padding: 3px 9px; border-radius: var(--r-pill) }
.kpi .trend.up { color: var(--ok); background: var(--ok-soft) }
.kpi .trend.dn { color: var(--bad); background: var(--bad-soft) }

/* La tarjeta de ventas ya NO se pinta aquí: pasó a ser el número que preside
   la pantalla (.hero-num). La regla se conserva por si el héroe elegido es
   otro y `sales_total` vuelve a la rejilla — ahí sigue siendo la que el dueño
   busca primero (mockup de Luis). */
.kpi.hero { background: var(--brand-grad); border: none; color: #fff }
.kpi.hero .lbl, .kpi.hero .split { color: rgba(255, 255, 255, .82) }
.kpi.hero .trend { background: rgba(255, 255, 255, .2); color: #fff }

/* ---------- gráfico ---------- */
.card { background: var(--card); border: 1px solid var(--line); border-radius: var(--r); padding: 18px; box-shadow: var(--shadow) }
.chart { display: flex; align-items: flex-end; gap: 10px; height: 130px; margin-top: 14px }
.chart .col { flex: 1; display: flex; flex-direction: column; justify-content: flex-end; gap: 3px; height: 100%; min-width: 0 }
.chart .b { border-radius: 6px 6px 3px 3px; min-height: 3px; transition: height .5s cubic-bezier(.2, .8, .2, 1) }
.chart .b.whatsapp { background: var(--wa); opacity: .9 }
.chart .b.instagram { background: var(--ig-grad); opacity: .85; border-radius: 3px }
.chart .d { font-family: var(--mono); font-size: 10px; color: var(--ink-3); text-align: center; margin-top: 7px }
.legend { display: flex; gap: 16px; font-size: 12px; color: var(--ink-2); margin-top: 4px; flex-wrap: wrap }
.legend span { display: flex; align-items: center; gap: 6px }
.legend i { width: 9px; height: 9px; border-radius: 3px }
.legend .whatsapp i { background: var(--wa) }
.legend .instagram i { background: var(--ig-grad) }

/* ---------- feed ---------- */
.feed { display: flex; flex-direction: column }
.ev { display: flex; gap: 12px; padding: 13px 4px; border-bottom: 1px solid var(--line-2); align-items: flex-start }
.ev:last-child { border: none }
/* Las líneas del feed que tienen conversación detrás son botones: llevan al
   chat donde pasó. Se comportan como fila, no como botón (sin fondo propio),
   pero avisan al pasar por encima y con el teclado. */
button.ev { width: 100%; text-align: left; background: none; border-radius: 10px; transition: background .15s }
button.ev.ev-go:hover { background: var(--aqua-soft) }
button.ev.ev-go:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px }
.ev .ch { width: 32px; height: 32px; border-radius: 10px; display: grid; place-items: center; flex: none }
.ev .ch.whatsapp { background: var(--wa-soft) }
.ev .ch.instagram { background: var(--ig-soft) }
.ev .ch svg { width: 16px; height: 16px }
.ev .tx { font-size: 13.5px; color: var(--ink-2); flex: 1; min-width: 0 }
.ev .tag { font-size: 11.5px; font-weight: 600; padding: 3px 10px; border-radius: var(--r-pill); margin-left: 6px; white-space: nowrap }
.tag.cita { background: var(--aqua-soft); color: var(--brand) }
.tag.venta { background: var(--ok-soft); color: var(--ok) }
.tag.esc { background: var(--warn-soft); color: var(--warn) }
.ev .t { font-family: var(--mono); font-size: 10.5px; color: var(--ink-3); white-space: nowrap; padding-top: 2px }

/* ---------- conversaciones ---------- */
.convs { display: flex; flex-direction: column; gap: 9px }
.conv {
  display: flex; gap: 12px; align-items: center; background: var(--card); border: 1px solid var(--line);
  border-radius: var(--r-sm); padding: 13px 15px; box-shadow: var(--shadow); cursor: pointer;
  transition: all .15s; text-align: left; width: 100%;
}
.conv:hover { transform: translateY(-1px); box-shadow: var(--shadow-lift); border-color: var(--brand) }
.conv .av { width: 38px; height: 38px; border-radius: 50%; display: grid; place-items: center; font-weight: 700; font-size: 14px; color: #fff; flex: none; position: relative }
.conv .av .mini { position: absolute; bottom: -3px; right: -3px; width: 17px; height: 17px; border-radius: 6px; background: var(--card); display: grid; place-items: center; border: 1px solid var(--line) }
.conv .av .mini svg { width: 10px; height: 10px }
.conv .bd { flex: 1; min-width: 0 }
.conv .nm { font-weight: 600; font-size: 14px; display: flex; align-items: center; gap: 6px; min-width: 0 }
/* El titular son dos piezas: quién es y de dónde (#404). En 375 px no caben las
   dos enteras y hay que elegir cuál se rompe: la persona es a quien el dueño
   saluda, así que se corta la EMPRESA.
   La empresa CRECE desde cero (`flex: 1 1 0`) en vez de encogerse desde su
   texto. No es lo mismo: repartiendo el encogimiento —aunque sea 999 a 1— a la
   persona le tocaba una fracción de píxel, y una caja 0,05 px más corta que su
   texto ya dispara `text-overflow`. Medido: «Ramon Silva» ocupaba 84,40 px en
   una caja de 84,35 y salía «Ramon Sil…» teniendo sitio de sobra. Con base 0 no
   hay nada que repartir: la persona conserva su ancho natural y la empresa se
   queda con lo que sobre. Si la persona sola no cabe, entonces sí encoge ella,
   que es el único caso en que debe.
   Sin `min-width: 0` la elipsis no llega a actuar y la fila se parte en cuatro
   renglones — que es lo que hacía el nombre de SUILLA antes de esto. */
.conv .nm .qn { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap }
.conv .nm .qs { flex: none; color: var(--ink-3); font-weight: 400 }
.conv .nm .qd { flex: 1 1 0; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; color: var(--ink-2) }
.conv .sn { font-size: 12.5px; color: var(--ink-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-top: 1px }
/* Cuando un cliente te espera, POR QUÉ te espera importa más que releer lo
   último que escribió: el motivo ocupa el lugar del snippet y se distingue por
   color, no por tamaño (la fila tiene que seguir midiendo lo mismo). */
.conv .sn.motivo { color: var(--warn); font-weight: 600 }
/* El motivo es la razón de ser de esta fila: dejarlo en una línea con puntos
   suspensivos («Lleva 28 min · Pide un d…») lo vuelve inútil justo en el
   teléfono, que es donde el dueño lo va a leer. Dos líneas y hasta ahí. */
.conv .sn.motivo { white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; line-height: 1.35 }
/* La columna derecha manda la altura de la fila: con día + hora + estado son
   TRES renglones. `min-height` iguala TODAS las filas — una lista donde las de
   hoy son más bajas que las de ayer se ve dentada al desplazar. */
.conv .mt { display: flex; flex-direction: column; align-items: flex-end; justify-content: space-between; gap: 3px; flex: none; min-height: 52px }
.conv .tm { font-family: var(--mono); font-size: 10.5px; color: var(--ink-3); line-height: 1.2 }
/* El día va encima de la hora y pesa un punto más: es lo que ORDENA la lista.
   Solo aparece cuando NO es de hoy (ver etiquetaDia en ui.js). */
.conv .dy { font-family: var(--mono); font-size: 10.5px; font-weight: 600; color: var(--ink-2); line-height: 1.2; white-space: nowrap }

/* No leídos (#135): el punto con número, como cualquier app de mensajes. Sin
   contador (demo o servidor viejo) el punto queda solo y sigue diciendo lo
   importante: aquí hay algo que no has visto. */
.conv.unread .nm { font-weight: 800 }
.conv.unread .sn { color: var(--ink-2); font-weight: 600 }
.unread-n { min-width: 18px; height: 18px; padding: 0 5px; border-radius: 999px; background: var(--brand); color: #fff; font-size: 11px; font-weight: 700; font-family: var(--mono); display: grid; place-items: center; line-height: 1 }

.st { font-size: 11.5px; font-weight: 600; padding: 3px 10px; border-radius: var(--r-pill); white-space: nowrap }
.st.resolved { background: var(--ok-soft); color: var(--ok) }
.st.waiting_owner { background: var(--warn-soft); color: var(--warn) }
.st.booked { background: var(--aqua-soft); color: var(--brand) }
/* Sin responder es lo más grave que puede pasarle a un chat: hay un cliente
   esperando y nadie lo sabe. Va en rojo, no en ámbar como "te espera" — esa
   al menos la escaló el agente a propósito. */
.st.unanswered { background: var(--bad-soft); color: var(--bad) }
/* El dueño tomó el volante en este chat: Surfia está callada ahí. Se lee en
   la lista, no solo dentro del hilo — era fácil olvidar dónde había pausado. */
.st.paused { background: var(--aqua-soft); color: var(--brand); border: 1px dashed currentColor }

.btn { padding: 12px 18px; border-radius: var(--r-sm); font-size: 13.5px; font-weight: 700; transition: all var(--t-fast) }
.btn.primary { background: var(--brand-grad); color: #fff; box-shadow: 0 8px 20px -12px rgba(2, 132, 199, .55) }
.btn.primary:hover { transform: translateY(-1px) }
.btn.ghost { background: var(--aqua-soft); color: var(--brand) }
.btn[disabled] { opacity: .5; cursor: not-allowed; transform: none }

/* ---------- ventas ---------- */
.totals { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr) minmax(0, 1fr); gap: 12px; margin-bottom: 16px }
.tot { background: var(--card); border: 1px solid var(--line); border-radius: var(--r); padding: 15px 16px; box-shadow: var(--shadow); min-width: 0 }
.tot .lbl { font-size: 12px; font-weight: 600; color: var(--ink-3); display: flex; align-items: center; gap: 6px }
.tot .lbl svg { width: 13px; height: 13px }
.tot .val { font-size: 24px; font-weight: 700; letter-spacing: -.03em; margin-top: 5px; font-variant-numeric: tabular-nums }
.tot.hero { background: var(--brand-grad); border: none; color: #fff }
.tot.hero .lbl { color: rgba(255, 255, 255, .8) }
.rows { display: flex; flex-direction: column }
.row { display: flex; align-items: center; gap: 12px; padding: 12px 4px; border-bottom: 1px solid var(--line-2); font-size: 13.5px }
.row:last-child { border: none }
.row .ch-i { width: 28px; height: 28px; border-radius: 9px; display: grid; place-items: center; flex: none }
.row .ch-i.whatsapp { background: var(--wa-soft) }
.row .ch-i.instagram { background: var(--ig-soft) }
.row .ch-i svg { width: 14px; height: 14px }
.row .what { flex: 1; min-width: 0 }
.row .what b { font-weight: 600; display: block }
.row .what span { font-size: 12px; color: var(--ink-3) }
.row .by { font-size: 11.5px; font-weight: 600; padding: 3px 10px; border-radius: var(--r-pill); white-space: nowrap }
.row .by.agent { background: var(--aqua-soft); color: var(--brand) }
.row .by.owner { background: var(--card-2); color: var(--ink-3); border: 1px solid var(--line) }
.row .amt { font-family: var(--mono); font-weight: 700; font-size: 14px; white-space: nowrap; font-variant-numeric: tabular-nums }
.row.summary { border-top: 1px solid var(--line); margin-top: 4px }
.row.summary b { font-family: var(--mono); font-size: 12px; color: var(--ink-3); font-weight: 600 }

/* ---------- agenda ---------- */
.day-h { font-size: 12.5px; font-weight: 600; color: var(--ink-3); margin: 18px 0 10px }
.apts { display: flex; flex-direction: column; gap: 9px }
.orders { display: flex; flex-direction: column; gap: 9px }
.orders-summary { display: flex; justify-content: space-between; align-items: baseline; margin: 0 0 10px; color: var(--ink-3); font-size: 13px }
.orders-summary b { color: var(--ink); font-size: 18px }
.orders-note { margin: 0 0 10px; color: var(--ink-3); font-size: 12px }
.order { background: var(--card); border: 1px solid var(--line); border-radius: var(--r-sm); padding: 13px 15px; box-shadow: var(--shadow) }
.order-head, .order-foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap }
.order-head b { display: block; font-size: 14px }
.order-head span, .order-foot span { color: var(--ink-3); font-size: 12px }
.order-head .st { color: var(--ink); font-size: 11px }
.order ul { margin: 11px 0; padding-left: 18px; color: var(--ink-2); font-size: 13px }
.order li { padding: 2px 0 }
.order li span { float: right; color: var(--ink); font-weight: 600 }
.order li em { color: var(--ink-3); font-size: 11px; font-style: normal }
.order-foot strong { color: var(--brand); font-size: 16px }
.order-foot > span { display: flex; align-items: center; gap: 4px }
.order-foot svg { width: 12px; height: 12px }
.order-open { border: 0; background: transparent; color: var(--brand); cursor: pointer; font-size: 12px; padding: 4px 8px }
.order-open:hover { text-decoration: underline }
.apt { display: flex; gap: 14px; background: var(--card); border: 1px solid var(--line); border-radius: var(--r-sm); padding: 13px 15px; box-shadow: var(--shadow); align-items: center }
.apt .hr { font-family: var(--mono); font-weight: 700; font-size: 14px; color: var(--brand); min-width: 76px; flex: none }
.apt .bd { flex: 1; min-width: 0 }
.apt .bd b { font-weight: 600; font-size: 14px; display: block }
.apt .bd span { font-size: 12px; color: var(--ink-3) }
.apt .rt { display: flex; flex-direction: column; align-items: flex-end; gap: 5px }
.apt .src { display: flex; align-items: center; gap: 5px; font-size: 10.5px; color: var(--ink-3); font-family: var(--mono) }
.apt .src svg { width: 12px; height: 12px }
.st.confirmed { background: var(--ok-soft); color: var(--ok) }
.st.reminded { background: var(--aqua-soft); color: var(--brand) }
.st.new { background: var(--warn-soft); color: var(--warn) }

/* ---------- inventario ---------- */
.invs { display: flex; flex-direction: column; gap: 9px }
.inv { background: var(--card); border: 1px solid var(--line); border-radius: var(--r-sm); padding: 13px 15px; box-shadow: var(--shadow) }
.inv .r1 { display: flex; align-items: center; gap: 10px; flex-wrap: wrap }
.inv .r1 b { font-weight: 600; font-size: 14px; flex: 1; min-width: 120px }
/* El nombre es un botón que abre la edición; el lápiz es el aviso de que se
   puede. Hereda el estilo del <b> para que la fila se vea igual que siempre. */
.inv .inv-name { display: flex; align-items: center; gap: 6px; flex: 1; min-width: 120px; text-align: left; color: inherit; padding: 0 }
.inv .inv-name b { flex: initial; min-width: 0 }
.inv .inv-name .pen { width: 13px; height: 13px; color: var(--ink-3); flex: none }
.inv .inv-name:hover b, .inv .inv-name:hover .pen { color: var(--brand) }
.inv .r1 .qty { font-family: var(--mono); font-size: 12.5px; font-weight: 700 }
.inv .bar { height: 6px; border-radius: 3px; background: var(--line-2); margin-top: 10px; overflow: hidden }
.inv .bar i { display: block; height: 100%; border-radius: 3px; transition: width .6s ease }
.inv .r2 { display: flex; gap: 8px; margin-top: 8px; font-size: 11px; color: var(--ink-3); align-items: center }
.pill { font-size: 11.5px; font-weight: 600; padding: 3px 10px; border-radius: var(--r-pill); white-space: nowrap }
.pill.critical { background: var(--bad-soft); color: var(--bad) }
.pill.warning { background: var(--warn-soft); color: var(--warn) }
.pill.hot { background: var(--aqua-soft); color: var(--brand) }

/* ---------- canales ---------- */
.duel { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 12px }
.side-card { background: var(--card); border: 1px solid var(--line); border-radius: var(--r); padding: 17px; box-shadow: var(--shadow); min-width: 0 }
.side-card .hd { display: flex; align-items: center; gap: 9px; font-weight: 700; font-size: 15px; margin-bottom: 14px }
.side-card .hd .ch { width: 30px; height: 30px; border-radius: 9px; display: grid; place-items: center }
.side-card .hd .ch.whatsapp { background: var(--wa-soft) }
.side-card .hd .ch.instagram { background: var(--ig-soft) }
.side-card .hd .ch svg { width: 15px; height: 15px }
.mrow { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; padding: 8px 0; border-bottom: 1px solid var(--line-2); font-size: 13px; color: var(--ink-2) }
.mrow:last-child { border: none }
.mrow b { font-family: var(--mono); font-size: 14px; color: var(--ink); font-weight: 700; font-variant-numeric: tabular-nums }
.vs-bars { margin-top: 12px }
.vs { margin-bottom: 14px }
.vs .lbl { display: flex; justify-content: space-between; gap: 10px; font-size: 12px; color: var(--ink-2); margin-bottom: 6px }
.vs .lbl b { font-family: var(--mono) }
.vs .track { display: flex; height: 10px; border-radius: 5px; overflow: hidden; background: var(--line-2) }
.vs .track .whatsapp { background: var(--wa) }
.vs .track .instagram { background: linear-gradient(90deg, #F58529, #DD2A7B) }
.insight { margin-top: 16px; padding: 14px 16px; border-radius: var(--r-sm); background: var(--aqua-soft); border: 1px solid rgba(34, 211, 238, .3); font-size: 13.5px; color: var(--ink-2) }
.insight .k { font-size: 12px; font-weight: 600; color: var(--brand); display: block; margin-bottom: 4px }

/* ---------- barra de instalación (PWA) ---------- */
/* Arranca DESPUÉS de la barra lateral (232px): a todo lo ancho tapaba el pie de
   la lateral, y con él el botón "Salir" — quien tuviera el aviso de instalar no
   podía cerrar sesión. Lo encontró una prueba automatizada al no poder hacer
   clic en Salir. */
.install-bar {
  position: fixed; left: calc(232px + 12px); right: 12px;
  bottom: calc(12px + env(safe-area-inset-bottom)); z-index: 60;
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 12px 14px; border-radius: var(--r); background: var(--card);
  border: 1px solid var(--line); box-shadow: var(--shadow-lift); font-size: 13.5px;
  animation: in .3s ease;
}
.install-bar[hidden] { display: none }
.install-bar > span { flex: 1 1 200px }
.install-bar .btn { padding: 9px 16px; font-size: 13px }
.install-x { font-size: 15px; color: var(--ink-3); padding: 4px 8px; border-radius: 8px }
.install-x:hover { background: var(--card-2); color: var(--ink) }
/* En móvil no hay barra lateral: vuelve a todo lo ancho, pero por encima de la
   navegación inferior para no tapar los íconos. */
@media (max-width: 820px) {
  .install-bar { left: 12px; bottom: calc(72px + env(safe-area-inset-bottom)) }
}

/* ---------- bienvenida ----------
   La primera pantalla. Cubre TODO —incluida la navegación inferior— porque
   quien todavía no entró no tiene nada que navegar; antes se veía el panel de
   un negocio ficticio por detrás del formulario, y eso confunde a cualquiera.
   Va por encima del diálogo (z 90 contra el 100 del <dialog>) para que la hoja
   de entrada suba SOBRE las ondas y no las tape. */
.welcome {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: grid;
  background: var(--marino);
  overflow: hidden;
}
.welcome__waves,
.welcome__veil { position: absolute; inset: 0; width: 100%; height: 100% }
/* El velo apaga las ondas justo donde hay texto, arriba y abajo, para que el
   titular y los botones se lean sin bajarle la vida al fondo. */
.welcome__veil {
  background:
    linear-gradient(180deg, rgba(5, 13, 24, .92) 0%, rgba(5, 13, 24, .35) 34%, rgba(5, 13, 24, .55) 68%, rgba(5, 13, 24, .95) 100%);
  pointer-events: none;
}
.welcome__inner {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 24px;
  padding: clamp(48px, 9vh, 88px) 24px calc(34px + env(safe-area-inset-bottom));
  width: min(460px, 100%);
  margin: 0 auto;
  text-align: center;
}
.welcome__brand { display: flex; align-items: center; justify-content: center; gap: 12px }
.welcome__mark { width: 46px; height: 40px }
.welcome__word { font-size: 30px; font-weight: 700; letter-spacing: -.04em; color: #fff }

.welcome__claim {
  font-size: clamp(26px, 7.5vw, 34px);
  font-weight: 700;
  line-height: 1.18;
  letter-spacing: -.03em;
  color: #fff;
  margin: auto 0;
}
.welcome__claim span { color: var(--aqua) }
.welcome__aviso { margin: 14px 0 0; font-size: 14.5px; color: var(--aqua); text-wrap: balance }

.welcome__actions { display: grid; gap: 10px }
.wbtn {
  width: 100%;
  padding: 17px 20px;
  border-radius: var(--r-pill);
  font-size: 16px;
  font-weight: 600;
  transition: transform .15s ease, opacity .15s ease;
}
.wbtn:active { transform: scale(.985) }
.wbtn--solid { background: #fff; color: #071322 }
/* Vidrio sobre las ondas: se ve el fondo moverse por debajo del botón. */
.wbtn--ghost {
  background: rgba(255, 255, 255, .10);
  border: 1px solid rgba(255, 255, 255, .22);
  color: #fff;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.welcome__minor { display: flex; align-items: center; justify-content: center; gap: 10px; margin-top: 6px; color: rgba(255, 255, 255, .38) }
.wlink { font-size: 13.5px; font-weight: 600; color: rgba(255, 255, 255, .72); padding: 6px 2px }
.wlink:hover { color: #fff }

/* ---------- diálogo de conexión ---------- */
/* `margin: auto` lo trae el navegador para todo <dialog> abierto con
   showModal() — es lo que lo centra en la pantalla. Nuestro reset
   `* { margin: 0 }` se lo llevaba por delante, y las siete hojas del panel
   salían pegadas a la esquina de arriba a la izquierda con el resto de la
   pantalla vacío. Se devuelve aquí, en el elemento, para que valga en todas;
   la de bienvenida y la de ajustes en el teléfono lo vuelven a pisar más
   abajo con `auto auto 0` porque esas suben desde el borde de abajo. */
dialog { border: none; padding: 0; background: transparent; margin: auto }
dialog::backdrop { background: rgba(10, 22, 40, .55); backdrop-filter: blur(2px) }
/* Sobre la bienvenida el diálogo no lleva fondo propio: taparía las ondas, que
   son justamente lo que tiene que seguir viéndose detrás de la hoja. */
.welcome-on dialog::backdrop { background: rgba(5, 13, 24, .45); backdrop-filter: blur(6px) }
/* Y la hoja sube desde abajo, pegada al borde, como en una app — no aparece
   flotando en el centro de la pantalla. */
.welcome-on #connect { margin: auto auto 0; max-width: 100%; width: 100% }
.welcome-on #auth-sheet {
  width: min(460px, 100%);
  margin: 0 auto;
  border-radius: 24px 24px 0 0;
  border-bottom: none;
  padding-bottom: calc(22px + env(safe-area-inset-bottom));
  animation: sheet-up .28s cubic-bezier(.2, .8, .3, 1);
}
@keyframes sheet-up { from { transform: translateY(16px); opacity: 0 } to { transform: none; opacity: 1 } }
/* En la hoja, la acción principal es una barra a todo lo ancho y las otras dos
   bajan a texto. Tres botones del mismo tamaño apretados en una esquina —como
   estaban— obligan a leerlos para saber cuál es el que uno vino a pulsar. */
.welcome-on .sheet .actions { display: grid; grid-template-columns: 1fr 1fr; gap: 2px; justify-content: stretch }
.welcome-on .sheet .actions .btn.primary { order: 1; grid-column: 1 / -1; width: 100%; padding: 15px; border-radius: var(--r-pill); font-size: 15px }
.welcome-on .sheet .actions .btn.ghost {
  order: 2;
  background: none;
  border: none;
  box-shadow: none;
  color: var(--ink-3);
  font-size: 13px;
  padding: 8px;
}
.welcome-on .sheet .actions .btn.ghost:hover { color: var(--ink) }
.welcome-on .sheet #switch-code { display: block; width: 100%; text-align: center; margin-top: 2px; color: var(--ink-3) }
.welcome-on .auth-head { justify-content: center; margin-bottom: 2px }
.welcome-on .auth-head h3 { font-size: 19px }
/* La barra de arrastre de una hoja de app: dice "esto sube y baja" sin texto. */
.welcome-on #auth-sheet::before {
  content: "";
  display: block;
  width: 38px;
  height: 4px;
  border-radius: var(--r-pill);
  background: var(--line);
  margin: -6px auto 16px;
}
.sheet { background: var(--card); color: var(--ink); border: 1px solid var(--line); border-radius: var(--r); padding: 22px; width: min(440px, calc(100vw - 32px)); box-shadow: var(--shadow-lift) }
.sheet h3 { font-size: 17px; margin-bottom: 6px }
.sheet p { font-size: 13px; color: var(--ink-3); margin-bottom: 16px }
.field { margin-bottom: 12px }
.field label { display: block; font-size: 12px; font-weight: 600; color: var(--ink-3); margin-bottom: 5px }
.field input { width: 100%; padding: 10px 12px; border-radius: var(--r-sm); border: 1px solid var(--line); background: var(--card-2); color: var(--ink); font-size: 13.5px; font-family: var(--mono) }
.field input:focus { outline: 2px solid var(--brand); outline-offset: 1px; border-color: var(--brand) }
/* El desplegable hereda el chrome del navegador (blanco) si nadie lo viste, y
   en el panel oscuro se lee como un error. Mismo traje que los inputs. */
.field select { width: 100%; padding: 10px 12px; border-radius: var(--r-sm); border: 1px solid var(--line); background: var(--card-2); color: var(--ink); font-size: 13.5px; font-family: var(--mono); appearance: none; background-image: linear-gradient(45deg, transparent 50%, var(--ink-3) 50%), linear-gradient(135deg, var(--ink-3) 50%, transparent 50%); background-position: right 16px center, right 11px center; background-size: 5px 5px, 5px 5px; background-repeat: no-repeat }
.field select:focus { outline: 2px solid var(--brand); outline-offset: 1px; border-color: var(--brand) }
.sheet .msg { font-size: 12.5px; margin-bottom: 12px; min-height: 18px }
.sheet .msg.ok { color: var(--ok) }
.sheet .msg.err { color: var(--bad) }
.sheet .actions { display: flex; gap: 10px; justify-content: flex-end; flex-wrap: wrap }

/* ---------- entrar / crear cuenta ---------- */
.auth-head { display: flex; align-items: center; gap: 10px; margin-bottom: 4px }
.auth-head .mark { width: 30px; height: 26px; display: grid; place-items: center; flex: none }
.auth-head .mark svg { width: 28px; height: 24px }
.auth-head h3 { margin: 0 }

.auth-tabs { display: flex; gap: 6px; background: var(--card-2); border: 1px solid var(--line); border-radius: 11px; padding: 3px; margin: 14px 0 16px }
.auth-tabs button { flex: 1; padding: 8px 10px; border-radius: 8px; font-size: 12.5px; font-weight: 600; color: var(--ink-3); transition: all .15s }
.auth-tabs button.on { background: var(--card); color: var(--brand); box-shadow: var(--shadow) }

.auth-view { display: none }
.auth-view.on { display: block }

/* Un formulario SIN botón de envío dentro no se envía al pulsar Enter: el
   navegador simplemente no hace nada. Como el botón visible ("Entrar") vive
   fuera de los formularios —es compartido por las tres vías— cada uno lleva su
   propio submit fuera de pantalla. Sin esto, escribir la contraseña y pulsar
   Enter no entra, que es lo que hace todo el mundo. */
.submit-oculto {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px; border: 0;
  overflow: hidden; clip-path: inset(50%);
  white-space: nowrap;
}
.auth-note { font-size: 12.5px; color: var(--ink-3); margin-bottom: 14px }
.field .hint { text-transform: none; letter-spacing: 0; font-weight: 500; color: var(--ink-3) }

.linkish { font-size: 12.5px; font-weight: 600; color: var(--brand); padding: 2px 0 }
.linkish:hover { text-decoration: underline }
.linkish.alt { display: block; width: 100%; text-align: center; margin-top: 14px; font-size: 12px; color: var(--ink-3) }

#turnstile-slot:empty { display: none }

.pending-banner {
  display: flex; align-items: center; gap: 10px; padding: 12px 14px; margin-bottom: 20px;
  border-radius: var(--r-sm); background: var(--warn-soft); border: 1px solid rgba(201, 138, 43, .3);
  font-size: 13.5px; color: var(--ink);
}
.pending-banner .ico { font-size: 16px }

/* =====================================================
   Ronda de mejoras de Luis (29-jul): encabezado vivo, KPIs que
   entran a su data, gráfico con glow, ventas→conversación,
   inventario editable, demanda perdida y horas pico.
   Lenguaje: "bioluminiscencia" — el brillo aqua de la marca
   emergiendo del marino profundo. IA de vanguardia, sin ruido.
   ============================================================ */

/* ---------- encabezado del negocio ---------- */
/* El anillo giraba sin parar y por debajo llevaba una copia desenfocada
   haciendo de halo. Con el punto de «IA activa» respirando al lado y el punto
   del gráfico latiendo, eran tres cosas en movimiento perpetuo compitiendo con
   la cifra que preside la pantalla. Queda el degradado, quieto: sigue marcando
   el avatar del negocio sin pedir la mirada. El único latido permanente del
   panel es el punto de abajo, que sí significa algo: tu agente está despierto. */
.top .biz .av-ring {
  padding: 2.5px; border-radius: 14px; position: relative;
  background: linear-gradient(135deg, var(--aqua), var(--brand-deep));
}
/* Con logo, el cuadrito cambia de degradado a plato: 3px de aire para que el
   logo no muerda el anillo, y radio 12−3 para que las esquinas cuadren sin
   necesidad de recortar. `contain` y no `cover`: un wordmark recortado son
   letras sueltas sin sentido. */
.top .biz .av[data-logo] { background: var(--logo-plate); padding: 3px }
.top .biz .av > img { width: 100%; height: 100%; object-fit: contain; border-radius: 9px; display: block }
.top .biz .nm { font-size: 17px; font-weight: 800; letter-spacing: -.02em }
.biz-live { display: flex; align-items: center; gap: 6px }
.ia-dot {
  width: 7px; height: 7px; border-radius: 50%; background: var(--aqua); flex: none;
  animation: ia-breathe 2.4s ease-in-out infinite;
}
@keyframes ia-breathe {
  0%, 100% { opacity: 1 }
  50% { opacity: .45 }
}

/* ---------- KPIs clicables ---------- */
button.kpi { display: block; width: 100%; text-align: left; cursor: pointer; font: inherit }
.kpi .peek {
  position: absolute; right: 14px; bottom: 11px; font-size: 11px; font-weight: 700;
  font-family: var(--mono); color: var(--brand); opacity: 0; transform: translateX(-6px);
  transition: opacity .18s, transform .18s; white-space: nowrap;
}
.kpi.hero .peek { color: #fff }
.kpi:hover .peek, .kpi:focus-visible .peek { opacity: 1; transform: none }
.kpi:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px }
.kpi:active { transform: translateY(0) scale(.99) }

/* ---------- gráfico (SVG con glow) ---------- */
.chartwrap { position: relative; margin-top: 14px }
.chart { height: 150px; display: block; margin: 0 }
.chart svg { width: 100%; height: 150px; display: block; overflow: visible }
.chart .grid { stroke: var(--line); stroke-width: 1; stroke-dasharray: 2 7; vector-effect: non-scaling-stroke }
.chart .stroke { vector-effect: non-scaling-stroke; stroke-dasharray: 1; stroke-dashoffset: 1; animation: draw 1.1s cubic-bezier(.4, 0, .2, 1) forwards }
@keyframes draw { to { stroke-dashoffset: 0 } }
.chart .area { opacity: 0; animation: fadein .9s ease .25s forwards }
@keyframes fadein { to { opacity: 1 } }
.chart .dot-last { vector-effect: non-scaling-stroke }

.chart-labels { display: flex; justify-content: space-between; margin-top: 8px }
.chart-labels span { font-family: var(--mono); font-size: 10px; color: var(--ink-3); flex: 1; text-align: center }
.chart-labels span:first-child { text-align: left }
.chart-labels span:last-child { text-align: right }
.chart-tip {
  position: absolute; top: -6px; z-index: 5; pointer-events: none;
  background: var(--marino); color: var(--sobre-marino); border: 1px solid rgba(34, 211, 238, .35);
  border-radius: 10px; padding: 8px 11px; font-size: 11.5px; line-height: 1.6;
  box-shadow: var(--shadow-pop);
  display: flex; flex-direction: column; min-width: 118px;
}
.chart-tip b { font-family: var(--mono) }
.chart-tip span { display: flex; align-items: center; gap: 6px }
.chart-tip span i { width: 8px; height: 8px; border-radius: 3px; flex: none }

/* ---------- ventas → conversación ---------- */
button.row.link { width: 100%; text-align: left; cursor: pointer; font: inherit; border-radius: 10px; transition: background .15s }
button.row.link:hover { background: var(--aqua-soft) }
button.row.link:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px }
.row .chev { font-size: 18px; color: var(--ink-3); font-weight: 700; padding-left: 2px }
button.row.link:hover .chev { color: var(--brand) }

/* ---------- inventario editable ---------- */
.inv-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 14px; flex-wrap: wrap }
.inv-head .btn { flex: none; white-space: nowrap }
.stepper { display: flex; align-items: center; gap: 2px; margin-left: auto }
.stp {
  width: 30px; height: 30px; border-radius: var(--r-sm); display: grid; place-items: center;
  font-family: var(--mono); font-size: 15px; font-weight: 700; color: var(--brand);
  background: var(--aqua-soft); border: 1px solid rgba(34, 211, 238, .3); transition: all .12s;
}
.stp:hover:not([disabled]) { background: var(--brand); color: #fff }
.stp[disabled] { opacity: .35; cursor: not-allowed }
.stepper .qty { min-width: 52px; text-align: center; font-family: var(--mono); font-size: 14px; font-weight: 700 }
.stepper .qty small { font-size: 9.5px; margin-left: 3px; opacity: .7; font-weight: 600 }
.inv .r2 { justify-content: space-between; flex-wrap: wrap }
.avail { display: flex; align-items: center; gap: 7px; font-size: 12.5px; font-weight: 600; color: var(--ink-3); padding: 8px 10px; margin: -8px -10px; min-height: 32px; border-radius: var(--r-sm) }
.avail i { width: 26px; height: 15px; border-radius: var(--r-pill); background: var(--line); position: relative; transition: background .18s; flex: none }
.avail i::after { content: ""; position: absolute; top: 2px; left: 2px; width: 11px; height: 11px; border-radius: 50%; background: #fff; transition: transform .18s; box-shadow: 0 1px 3px rgba(0, 0, 0, .25) }
.avail.on { color: var(--brand) }
.avail.on i { background: var(--brand) }
.avail.on i::after { transform: translateX(11px) }
.inv.off { opacity: .6 }
.pill.mute { background: var(--card-2); color: var(--ink-3); border: 1px solid var(--line) }

/* ---------- lo más pedido + demanda perdida ---------- */
.demand .dr { display: grid; grid-template-columns: minmax(120px, 200px) minmax(0, 1fr) 34px; gap: 12px; align-items: center; padding: 7px 0; animation: in .4s ease both }
.demand .dl { font-size: 13px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis }
.demand .db { height: 10px; border-radius: 5px; background: var(--line-2); overflow: hidden }
.demand .db i { display: block; height: 100%; border-radius: 5px; background: var(--brand-grad); transition: width .7s var(--ease) }
.demand .dc { font-family: var(--mono); font-size: 13px; font-weight: 700; text-align: right; font-variant-numeric: tabular-nums }
.unmet { margin-top: 14px; border: 1px solid rgba(201, 138, 43, .3); background: var(--warn-soft); border-radius: var(--r-sm); padding: 12px 14px }
.unmet .uh { font-size: 13px; font-weight: 600; color: var(--warn-ink); margin-bottom: 8px; display: flex; align-items: center; gap: 7px }
.unmet .ur { display: flex; justify-content: space-between; gap: 10px; font-size: 13px; padding: 5px 0; border-bottom: 1px dashed rgba(201, 138, 43, .25) }
.unmet .ur:last-of-type { border: none }
.unmet .ur b { font-size: 12px; color: var(--warn-ink); font-weight: 700; white-space: nowrap }
.unmet .un { font-size: 11.5px; color: var(--ink-2); margin-top: 8px }

/* ---------- horas pico ---------- */
.hours { overflow-x: auto }
.hm { display: grid; grid-template-columns: 38px repeat(var(--cols, 7), minmax(28px, 1fr)); gap: 4px; align-items: center; min-width: 300px }
.hm .hh { font-family: var(--mono); font-size: 9.5px; color: var(--ink-3); text-align: center }
.hm .hd { font-family: var(--mono); font-size: 10px; color: var(--ink-2); font-weight: 600 }
.hm .hc {
  display: block; height: 26px; border-radius: 7px;
  background: var(--line-2); /* fallback: Safari iOS < 16.2 no trae color-mix */
  background: color-mix(in srgb, var(--aqua) calc(var(--t) * 82%), var(--line-2));
  transition: transform .12s;
}
.hm .hc:hover { transform: scale(1.12) }
.hm .hc.hot { background: var(--brand-grad) }
.hlegend { display: flex; align-items: center; gap: 5px; margin-top: 12px; font-size: 10.5px; font-family: var(--mono); color: var(--ink-3) }
.hlegend .sw { width: 18px; height: 10px; border-radius: 4px; background: var(--line-2); background: color-mix(in srgb, var(--aqua) calc(var(--t) * 82%), var(--line-2)) }
.hlegend .sw.hot { background: var(--brand-grad) }
.hinsight { display: flex; align-items: center; gap: 9px; margin-top: 12px; padding: 11px 14px; border-radius: var(--r-sm); background: var(--aqua-soft); border: 1px solid var(--aqua-25); font-size: 13px; color: var(--ink-2) }
.hinsight b { color: var(--hl-ink) }

/* ---------- toast ---------- */
.toast {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(20px + env(safe-area-inset-bottom)); z-index: 90;
  background: var(--marino); color: var(--sobre-marino); border: 1px solid rgba(34, 211, 238, .35);
  padding: 11px 18px; border-radius: var(--r-pill); font-size: 13px; font-weight: 600;
  box-shadow: 0 12px 32px -8px rgba(10, 22, 40, .55), 0 0 14px rgba(34, 211, 238, .2);
  animation: toast-in .25s cubic-bezier(.2, .9, .3, 1.2); max-width: min(92vw, 480px); text-align: center;
}
/* Dentro del hilo abierto, el toast deja de anclarse al fondo de la pantalla
   (`bottom`) y pasa a anclarse a lo que el teclado de iOS deja VISIBLE
   (`top`). Con el teclado arriba, el layout viewport (al que se ancla
   `bottom`) sigue midiendo la pantalla entera — su "fondo" queda tapado por
   el teclado, y el aviso se pintaba ahí sin que nadie lo viera: la causa real
   de "le doy al botón y no pasa nada". `--vvtop`/`--vvh` los publica
   thread-viewport.js desde `visualViewport` (sobre `document.documentElement`,
   por eso llegan hasta aquí aunque .toast sea hijo directo de <body>).
   Se limita a `body.hilo-abierto` a propósito: fuera del hilo esas variables
   no se publican y el toast de siempre no cambia en nada. */
body.hilo-abierto .toast {
  top: calc(var(--vvtop, 0px) + var(--vvh, 100dvh) - 64px);
  bottom: auto;
}
.toast.err { border-color: rgba(214, 69, 69, .55) }
.toast.ok { border-color: rgba(34, 197, 94, .55) }
.confirmar-btns { display: flex; gap: 8px; justify-content: flex-end; margin-top: 6px }
.confirmar-hoja p { margin-bottom: 12px }
@keyframes toast-in { from { opacity: 0; transform: translate(-50%, 10px) } to { opacity: 1; transform: translate(-50%, 0) } }

/* ---------- modal de producto ---------- */
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px }

/* ---------- movimiento reducido ---------- */
/* Quien pide menos movimiento no recibe ninguno. Antes esta lista era a mano y
   se escapaban cuatro: el punto del sidebar, la entrada de las pantallas, la
   hoja que sube y el aviso flotante. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important; animation-iteration-count: 1 !important;
    transition-duration: .01ms !important; scroll-behavior: auto !important;
  }
  .chart .stroke { stroke-dashoffset: 0 }
  .chart .area { opacity: 1 }
}

/* ---------- móvil ---------- */
.bnav { display: none }
.mob-logo { display: none }
@media (max-width: 820px) {
  .app { grid-template-columns: minmax(0, 1fr) }
  .side { display: none }
  /* safe-area: con viewport-fit=cover el contenido llega hasta los bordes
     físicos; estos términos lo despegan del reloj arriba y de la barra de
     navegación (más el indicador de inicio) abajo. */
  .main { padding: calc(16px + env(safe-area-inset-top)) 14px calc(96px + env(safe-area-inset-bottom)) }
  .kpis { grid-template-columns: repeat(2, minmax(0, 1fr)) }
  .totals { grid-template-columns: repeat(2, minmax(0, 1fr)) }
  .tot.hero { grid-column: 1 / -1 }
  .duel { grid-template-columns: minmax(0, 1fr) }
  .mob-logo { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 10px }
  /* En el teléfono, todo lo que va ANTES del número compite con él por el
     primer vistazo: la cabecera se aprieta para que la cifra entre en pantalla
     sin tener que desplazar. Lo mismo hace un banco con el saldo. */
  .top { gap: 10px; margin-bottom: 12px }
  /* Con "Última hora" son 4 pastillas: si no caben, la fila se desliza en vez
     de partirse en dos líneas o empujar la pantalla. */
  .seg { max-width: 100%; overflow-x: auto; scrollbar-width: none }
  .seg::-webkit-scrollbar { display: none }
  .seg button { white-space: nowrap; flex: none }
  /* Las filas de chips SIN TOPE — estados de conversación (#chips-st) y
     categorías del catálogo (#inv-cats, tantas como tenga el negocio) — se
     deslizan: sangran hasta el borde real de la pantalla (contrarrestando el
     padding de .main) y se desvanecen a la derecha, que es el aviso de "hay
     más". El padding derecho extra deja que el último chip se vea completo al
     llegar al final, fuera de la zona del degradé.
     La fila de CANALES es el caso contrario y va justo debajo. */
  .chips {
    margin-bottom: 14px; margin-inline: -14px; padding-inline: 14px 36px;
    scroll-snap-type: x proximity;
    -webkit-mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 28px), transparent);
    mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 28px), transparent);
  }
  /* Los canales son un conjunto ACOTADO: un negocio tiene dos o seis, no
     veinte. Por eso esta fila se muestra ENTERA y baja a una segunda línea en
     vez de deslizarse. Es el filtro principal del panel, y un canal que no se
     ve es un canal que no se filtra: el degradé de la derecha, que en las otras
     filas dice "desliza", aquí se leía como "se cortó". Hay que anular una por
     una las propiedades de arriba, porque comparten la clase .chips. */
  #chips-ch {
    flex-wrap: wrap; gap: 6px;
    margin-inline: 0; padding-inline: 0;
    overflow-x: visible; scroll-snap-type: none;
    -webkit-mask-image: none; mask-image: none;
  }
  /* Estos ~30px no son cosmética: son los que deciden si los tres chips de hoy
     caben en una línea en un iPhone SE (375pt) o si se parten en dos. */
  #chips-ch .chip { padding: 6px 11px; gap: 6px; font-size: 12.5px }
  /* Donde "Todos los canales" se vuelve "Todos". El texto largo solo cabe —y
     solo hace falta— cuando hay pantalla de sobra. */
  #chips-ch .lbl-long { display: none }
  .hero-num__val { font-size: clamp(46px, 14vw, 62px) }
  /* en móvil el botón baja a su propia línea en vez de estrujar el texto */
  .databar { flex-wrap: wrap; font-size: 12px; padding: 10px 12px; row-gap: 6px }
  .databar > span:nth-child(2) { flex: 1 1 200px }
  .bnav {
    display: flex; position: fixed; bottom: 0; left: 0; right: 0; z-index: 50;
    background: var(--card); border-top: 1px solid var(--line);
    padding: 7px 4px calc(7px + env(safe-area-inset-bottom));
    box-shadow: var(--shadow-up);
  }
  /* min-width:0 — sin él, un flex item no baja de su contenido y las 7
     pestañas se empujan fuera de la pantalla en un iPhone de 375pt. */
  .bnav button { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 3px; font-size: 10px; font-weight: 600; color: var(--ink-3); padding: 5px 1px; border-radius: var(--r-sm); position: relative; transition: background var(--t-fast), color var(--t-fast) }
  .bnav button .lbl { max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis }
  .bnav button svg { width: 20px; height: 20px }
  .bnav button[data-screen="probar"] svg { width: 20px; height: 18px }
  .bnav button.on { color: var(--brand); background: var(--aqua-soft) }
  .bnav .badge { position: absolute; top: 0; right: 22%; background: var(--bad); color: var(--bad-ink); font-size: 9px; font-weight: 700; min-width: 15px; height: 15px; border-radius: 8px; display: grid; place-items: center; padding: 0 4px }
  .field-row { grid-template-columns: minmax(0, 1fr) }
  .toast { bottom: calc(76px + env(safe-area-inset-bottom)) }
  /* En táctil no hay hover: la pista «Ver →» de cada tarjeta se ve siempre. */
  .kpi .peek { opacity: 1; transform: none }

  .demand .dr { grid-template-columns: minmax(90px, 130px) minmax(0, 1fr) 30px; gap: 8px }
  .stp { width: 36px; height: 36px }
}

/* ===== catálogo B2B (nicho inventory, Issue #30 + primer tenant real) ===== */
/* Barra de herramientas del catálogo: solo aparece con >12 productos. */
/* Cabecera del catálogo de Shopify (#491): de dónde viene y hace cuánto. */
#inv-origen { margin-bottom: 12px }
#inv-origen:empty { display: none }
.inv-shopify { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap }
.inv-shopify .ml-txt { margin: 4px 0 0 }
.inv-tools { display: flex; flex-direction: column; gap: 10px; margin-bottom: 12px }
.inv-tools:empty { display: none }
.inv-tools input[type="search"] {
  width: 100%; padding: 10px 14px; border-radius: var(--r-sm); border: 1px solid var(--line);
  background: var(--card); color: var(--ink-2); font: inherit; font-size: 13.5px;
}
.inv-tools input[type="search"]:focus { outline: 2px solid var(--brand); outline-offset: 1px }
.inv .r1 .sku { font-family: var(--mono); font-size: 10.5px; color: var(--ink-3); letter-spacing: .02em }
.inv .r1 .price { font-family: var(--mono); font-size: 12.5px; font-weight: 700; color: var(--brand) }
#inv-more { width: 100%; margin-top: 10px }
/* "Cliente desistió" / "Cancelar cita": acción secundaria, no debe gritar. */
.cancel-apt {
  font-size: 11px; padding: 4px 10px; border-radius: var(--r-sm); cursor: pointer;
  border: 1px solid var(--line); background: transparent; color: var(--ink-3);
}
.cancel-apt:hover { color: var(--bad); border-color: var(--bad) }

/* ---------- Mi Surfia (#52) ----------
   El dueño le escribe a su propio agente antes de exponerlo a un cliente. */

/* El título lleva la marca al lado: es la pantalla donde el dueño moldea a su
   Surfia, y el logo lo dice antes que el texto. 26×23 respeta la proporción
   52:46 del viewBox y le queda a la altura óptica del h1 de 22px. */
.h1-marca { display: flex; align-items: center; gap: 9px }
.h1-marca__mark { width: 26px; height: 23px; flex: none }

.probar-chat { display: flex; flex-direction: column; gap: 14px; margin-top: 14px }
.probar-chat .bubbles { min-height: 180px; max-height: 52vh; overflow-y: auto }
/* El chat de prueba no tiene "otro lado": el dueño escribe a la izquierda como
   lo haría el cliente, y su agente responde a la derecha. Reusa .bub tal cual. */
.probar-chat .reply { max-width: none }

.policy-h {
  font-size: 11px; font-family: var(--mono); letter-spacing: .06em;
  color: var(--ink-3); text-transform: uppercase; margin-bottom: 6px;
}
.policy-d { font-size: 13px; color: var(--ink-2); line-height: 1.5 }

/* ===== «Cómo responde tu agente» (#50): la tarjeta que manda =====
   Es el único sitio del panel donde el dueño cambia el comportamiento de su
   agente, y era la segunda de trece tarjetas idénticas y pegadas entre sí, con
   el botón más pequeño de la pantalla. Ahora va primera y lleva el degradado de
   marca en un riel de 3px: el mismo recurso de .kpi.hero y del número de
   Inicio, y en Mi Surfia no aparece en ningún otro sitio, así que con verlo ya
   se sabe cuál es. NO se rellena de degradado como .kpi.hero: esta tarjeta
   carga hasta seis renglones a 13px, y el texto claro sobre degradado es el
   problema de contraste que ya obligó a subir --brand en el tema oscuro. Basta
   un baño de --aqua-soft que se apaga a los 140px y deja la lista sobre --card
   limpio. El margen es suyo porque .card no declara ninguno: sin él la tarjeta
   va pegada a la siguiente, y despegarla es la mitad de «destaca». */
.responde {
  position: relative;
  overflow: hidden;
  margin: 4px 0 18px;
  border-color: var(--aqua-35);
  background: linear-gradient(180deg, var(--aqua-soft), transparent 140px), var(--card);
  box-shadow: var(--shadow-lift);
}
/* El `overflow: hidden` de arriba es para que el riel siga la curva de --r. */
.responde::before { content: ""; position: absolute; inset: 0 0 auto; height: 3px; background: var(--brand-grad) }
.responde .source-kicker { margin-bottom: 7px }
.responde-t { display: block; font-size: 21px; font-weight: 700; letter-spacing: -.01em; line-height: 1.25; color: var(--ink) }
.responde-d { font-size: 13.5px; color: var(--ink-2); line-height: 1.5; margin-top: 5px }

/* Un renglón por ajuste: el dueño no lee un párrafo, cuenta reglas. El punto va
   en un ::before y no en list-style para que el aqua no se lleve también el
   color del texto. */
.responde-lista { list-style: none; margin: 13px 0 0; padding: 0; display: grid; gap: 7px }
.responde-lista li { position: relative; padding-left: 17px; font-size: 13px; color: var(--ink-2); line-height: 1.45 }
.responde-lista li::before { content: ""; position: absolute; left: 2px; top: 7px; width: 6px; height: 6px; border-radius: 50%; background: var(--aqua) }
.responde-lista b { color: var(--ink); font-weight: 600 }
.responde-pie { font-size: 12.5px; color: var(--ink-3); line-height: 1.45; margin-top: 14px }

/* La llamada a la acción deja de ser el botón más callado de la pantalla: un
   `ghost mini` decía «detalle», y aquí hay que decir «esto se toca». */
.responde-cta { display: inline-flex; align-items: center; gap: 8px; margin-top: 11px }

@media (max-width: 820px) {
  .responde { margin-bottom: 16px }
  .responde-t { font-size: 19px }
  .responde-cta { width: 100%; justify-content: center; padding: 14px 18px; border-radius: var(--r-pill) }
}

/* ===== Ajustes del agente (#50) =====
   El formulario es más alto que el de inventario (cinco grupos), así que la
   hoja crece y hace scroll interno en vez de empujar el modal fuera de la
   pantalla del teléfono, que es donde el dueño lo va a abrir. */
.sheet-wide { width: min(520px, calc(100vw - 32px)); max-height: calc(100dvh - 48px); display: flex; flex-direction: column }
/* El que scrollea es el FORM, que es el hijo flexible — no el div de adentro.
   `min-height: 0` es obligatorio: sin él un ítem flex no baja de su contenido,
   el formulario crece hasta 1055px y "Guardar" queda fuera de una pantalla de
   720. Verificado en navegador: así se rompía. */
.sheet-wide #form-pol { flex: 1; min-height: 0; overflow-y: auto; margin: 0 -4px; padding: 0 4px }

/* La hoja crece por #id y NO ensanchando .sheet-wide, que también viste el
   cuestionario de alta —nueve preguntas de tres palabras, que en 760 flotarían—
   y el Magazine. Es el patrón que ya usa .magazine-hoja: cada hoja declara su
   propia caja y comparte de .sheet-wide solo la columna y el scroll de arriba. */
#pol-modal .sheet { width: min(760px, calc(100vw - 40px)); max-height: min(880px, calc(100dvh - 40px)); padding: 24px 26px }
#pol-modal .sheet h3 { font-size: 21px; margin-bottom: 4px }
#pol-modal .sheet > p { font-size: 13px; margin-bottom: 18px; max-width: 64ch }
#pol-modal .polset { margin-bottom: 22px }
#pol-modal .polset legend { font-size: 13px; color: var(--ink); margin-bottom: 10px }
/* Con la hoja grande hay que ver dónde acaba el formulario y empieza la decisión. */
#pol-modal .actions { padding-top: 14px; border-top: 1px solid var(--line-2) }

/* En el teléfono deja de flotar con márgenes y ocupa la pantalla, subiendo
   desde abajo como una app — el mismo recurso de la hoja de entrar. */
@media (max-width: 820px) {
  /* El <dialog> trae del navegador `max-height: calc(100% - 12px)`: sin
     anularlo queda una franja de fondo bajo la hoja a pantalla completa. */
  #pol-modal { margin: auto auto 0; width: 100%; max-width: 100%; max-height: 100% }
  #pol-modal .sheet {
    width: 100%; max-width: 560px; margin: 0 auto;
    /* Alto FIJO, no máximo: al cambiar la opción de precios aparece o
       desaparece la lista de preguntas, y la hoja saltaba bajo el pulgar.
       Y en unidad de PANTALLA, nunca un %: el <dialog> no declara alto, así que
       un porcentaje no resuelve, la hoja se va a la altura de su contenido
       (1.432px en una pantalla de 812) y «Guardar cambios» queda 600px por
       debajo del borde. Verificado en el navegador: así se rompía. */
    height: 94dvh;
    max-height: none;
    border-radius: 24px 24px 0 0;
    border-bottom: none;
    padding: 18px 16px calc(16px + env(safe-area-inset-bottom));
    animation: sheet-up .28s cubic-bezier(.2, .8, .3, 1);
  }
  /* La barra de arrastre dice «esto sube y baja» sin texto. `flex: none` porque
     .sheet-wide es un flex column y el ::before es un ítem más: sin él se
     estira y le come alto al formulario. */
  #pol-modal .sheet::before {
    content: ""; display: block; flex: none;
    width: 38px; height: 4px; border-radius: var(--r-pill);
    background: var(--line); margin: 0 auto 14px;
  }
  /* Mismo criterio que la hoja de entrar: la acción principal a todo lo ancho y
     la otra baja a texto. Dos botones iguales en una esquina obligan a leerlos. */
  #pol-modal .actions { display: grid; gap: 6px }
  #pol-modal .actions .btn.primary { order: 1; width: 100%; padding: 15px; border-radius: var(--r-pill); font-size: 15px }
  #pol-modal .actions .btn.ghost { order: 2; background: none; border: none; box-shadow: none; color: var(--ink-3); padding: 10px }
}

.polset { border: none; padding: 0; margin: 0 0 18px }
.polset legend { font-size: 12px; font-weight: 600; color: var(--ink-3); margin-bottom: 8px; padding: 0 }
.polhelp { font-size: 12px; color: var(--ink-3); line-height: 1.45; margin: 6px 0 8px }

/* Opción de precios: la tarjeta entera es clicable, no solo el radio de 16px —
   en móvil apuntarle al círculo es la diferencia entre usarlo y no usarlo. */
.opts { display: grid; gap: 8px }
.opt { display: flex; gap: 10px; align-items: flex-start; padding: 11px 12px; border: 1px solid var(--line); border-radius: 10px; background: var(--card-2); cursor: pointer }
.opt.on { border-color: var(--brand); background: var(--aqua-soft) }
.opt input { margin-top: 2px; accent-color: var(--brand); flex-shrink: 0 }
.opt span { display: block }
.opt b { display: block; font-size: 13.5px; font-weight: 600; margin-bottom: 2px }
.opt em { display: block; font-style: normal; font-size: 12px; color: var(--ink-3); line-height: 1.45 }

.chks { display: flex; flex-wrap: wrap; gap: 8px }
.chk { display: flex; gap: 7px; align-items: center; padding: 7px 11px; border: 1px solid var(--line); border-radius: var(--r-pill); background: var(--card-2); font-size: 13px; cursor: pointer }
.chk input { accent-color: var(--brand) }
.chk:has(input:checked) { border-color: var(--brand); background: var(--aqua-soft) }

/* Motivos de aviso (#136): cada uno lleva título y explicación, así que se
   apilan a lo ancho en vez de ir en pills — el dueño decide leyendo el porqué,
   no el nombre. */
.avisos-motivos { display: grid; gap: 8px }
.avisos-motivos .chk { align-items: flex-start; border-radius: 10px; padding: 11px 12px }
.avisos-motivos .chk input { margin-top: 2px; flex-shrink: 0 }
.avisos-motivos .chk b { display: block; font-size: 13.5px; font-weight: 600; margin-bottom: 2px }
.avisos-motivos .chk em { display: block; font-style: normal; font-size: 12px; color: var(--ink-3); line-height: 1.45 }
.avisos-acciones { display: flex; flex-wrap: wrap; gap: 8px; align-items: center }

.preguntas { display: grid; gap: 8px; margin-bottom: 8px }
.preg { display: flex; gap: 8px; align-items: center }
.preg input { flex: 1; min-width: 0; padding: 9px 11px; border-radius: var(--r-sm); border: 1px solid var(--line); background: var(--card-2); color: var(--ink); font-size: 13px }
.preg input:focus { outline: 2px solid var(--aqua-soft); border-color: var(--brand) }
.btn.mini { padding: 6px 11px; font-size: 12px }

/* ---------- activacion guiada de canales ---------- */
.channel-setup { margin: 18px 0 20px; padding: 18px 0 4px; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line) }
.setup-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; margin-bottom: 12px }
.setup-head h2 { margin: 2px 0 0; font-size: 18px }
.setup-kicker { color: var(--brand); font-size: 12px; font-weight: 600 }
.setup-status { border: 1px solid var(--line); border-radius: var(--r-pill); color: var(--ink-2); font-size: 11.5px; font-weight: 600; padding: 5px 11px; white-space: nowrap }
.setup-status.connected { border-color: var(--ok); color: var(--ok) }
.setup-status.waiting { border-color: var(--warn); color: var(--warn) }
/* Conectado, la insignia es el interruptor de «que Surfia conteste aquí». Como
   <button> hereda la tipografía del navegador: se le repite la del <span> para
   que apagar no cambie el aspecto de la insignia. */
button.setup-status { background: none; cursor: pointer; font-family: inherit; line-height: normal }
button.setup-status:hover { border-color: var(--ink-3); color: var(--ink) }
button.setup-status:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px }
/* Apagado por el dueño: ni verde (no está contestando) ni rojo (no está roto). */
.setup-status.muted, button.setup-status.connected.muted { border-color: var(--ink-3); color: var(--ink-2) }
button.setup-status.connected.muted:hover { border-color: var(--ok); color: var(--ok) }
.setup-tabs { display: flex; gap: 4px; margin-bottom: 14px }
.setup-tabs button { border-bottom: 2px solid transparent; color: var(--ink-3); font-size: 13px; padding: 7px 10px }
.setup-tabs button.on { border-color: var(--brand); color: var(--ink); font-weight: 700 }
.setup-grid { display: grid; grid-template-columns: minmax(170px, .7fr) minmax(0, 1.3fr); gap: 18px; align-items: start }
.setup-checklist { display: grid; gap: 8px; padding-top: 5px }
.setup-step { color: var(--ink-2); font-size: 12px; line-height: 1.35 }
.setup-step span { color: var(--ink-3); display: inline-block; font-family: var(--mono); margin-right: 7px; width: 13px }
.setup-step.done { color: var(--ok); text-decoration: line-through; text-decoration-color: color-mix(in srgb, var(--ok) 45%, transparent) }
.setup-step.done span { color: var(--ok) }
.setup-chat { min-width: 0 }
.setup-bubbles { background: var(--card-2); border: 1px solid var(--line); border-radius: var(--r-sm); display: grid; gap: 8px; max-height: 230px; min-height: 106px; overflow-y: auto; padding: 11px }
.setup-bubble { border-radius: 10px; font-size: 12.5px; line-height: 1.45; max-width: 88%; padding: 8px 10px; white-space: pre-wrap }
.setup-bubble.assistant { background: var(--card); border: 1px solid var(--line); justify-self: start }
.setup-bubble.owner { background: var(--brand); color: #fff; justify-self: end }
.setup-reply { display: flex; gap: 8px; margin-top: 9px }
.setup-reply input { background: var(--card); border: 1px solid var(--line); border-radius: var(--r-sm); color: var(--ink); flex: 1; min-width: 0; padding: 9px 11px }
.setup-reply input:focus { border-color: var(--brand); outline: 2px solid var(--aqua-soft) }
.setup-reply .btn { flex: none; padding: 9px 14px }
.setup-note { color: var(--ink-3); font-size: 11px; line-height: 1.4; margin: 8px 0 0 }
@media (max-width: 620px) {
  .setup-grid { grid-template-columns: minmax(0, 1fr) }
  .setup-checklist { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 7px 10px }
}

/* ═══════════ Clientes, buscador y cierre del día (auditoría UX 17-ago) ═══════════ */

/* Chats ↔ Clientes. Va pegado al título porque es un cambio de VISTA, no un
   filtro: los chips de estado de abajo filtran dentro de la vista de chats. */
.seg-view { width: fit-content; margin: 4px 0 12px }
.seg-orden { width: fit-content; margin: 0 0 12px }

.buscador { margin: 0 0 12px }
.buscador input {
  width: 100%; max-width: 420px; padding: 11px 14px; border-radius: 11px;
  border: 1px solid var(--line); background: var(--card); color: var(--ink);
  font-size: 14px; font-family: inherit;
}
.buscador input::placeholder { color: var(--ink-3) }
.buscador input:focus { outline: 2px solid var(--brand); outline-offset: -1px; border-color: transparent }

/* La fila de un cliente reusa .conv: es la misma anatomía (avatar, cuerpo,
   columna derecha) y así las dos vistas se sienten la misma pantalla. */
.conv.cli .nm { display: flex; align-items: center; gap: 6px }
.ch-mini { display: inline-flex; width: 15px; height: 15px }
.ch-mini svg { width: 15px; height: 15px }
.cli-gasto {
  display: flex; flex-direction: column; align-items: flex-end; gap: 1px;
  font-family: var(--mono); font-weight: 700; font-size: 13px; color: var(--ok);
}
.cli-gasto small { font-weight: 500; font-size: 10.5px; color: var(--ink-3) }

/* El cierre del día. Cada línea entra a su pantalla, así que se comporta como
   las alertas de arriba: la fila ENTERA es el botón, no una flechita. */
.cierre { margin: 18px 0 6px }
.cierre-h { margin: 0 0 10px }
.cierre-lista { display: flex; flex-direction: column; gap: 8px }
.cierre-l {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  padding: 13px 15px; border-radius: 12px; border: 1px solid var(--line);
  background: var(--card); font-size: 14px; color: var(--ink); transition: all .15s;
}
.cierre-l:hover { transform: translateX(2px) }
.cierre-tx { flex: 1; min-width: 0 }
.cierre-l .go { color: var(--ink-3); font-weight: 700; flex: none }
/* Lo que te toca hacer se distingue de lo que salió bien SIN gritar: el panel
   entero ya usa el ámbar para "esto te espera" y el verde para "esto se logró". */
.cierre-l.urgente { border-color: rgba(217, 119, 6, .35); background: var(--warn-soft) }
.cierre-l.urgente .cierre-tx { font-weight: 600; color: var(--warn) }
.cierre-l.ok .cierre-tx { color: var(--ok) }

/* MercadoLibre en Canales */
.ml-card { margin-bottom: 14px }
.ml-card .hd { display: flex; align-items: center; gap: 9px; font-weight: 700; font-size: 15px; margin-bottom: 8px }
.ml-card .hd .ch { width: 26px; height: 26px; display: grid; place-items: center }
.ml-card .hd .ch svg { width: 20px; height: 20px }
.ml-txt { font-size: 13.5px; color: var(--ink-2); margin: 0 0 14px; max-width: 60ch }

@media (max-width: 820px) {
  /* En el teléfono, cada fila de controles es contenido que el dueño no ve sin
     bajar. Esta pantalla ya arrastra la banda de datos, la cabecera, el período
     y los canales; añadirle vista + buscador + orden en filas propias dejaba la
     primera conversación fuera de la pantalla. Se juntan y se recorta lo que el
     título ya dice. */
  #s-convs .sub-h { display: none }
  .conv-tools { display: flex; align-items: center; gap: 8px; margin: 4px 0 12px }
  .conv-tools .seg-view { margin: 0; flex: none }
  .conv-tools .buscador { margin: 0; flex: 1; min-width: 0 }
  .conv-tools .buscador input { max-width: none }
  .seg-orden { margin-bottom: 10px }
  .seg-orden button { padding: 6px 10px; font-size: 12px }
}


/* ---------- iconos de interfaz ----------
   El sprite sustituyó a los emojis del panel (alertas, insights, barra de
   datos, botones). Un emoji no hereda el color: el rojo de «te esperan» y el
   ámbar de «casi agotado» tenían que ir en el propio glifo, y cada teléfono
   dibujaba el suyo. Estos toman `currentColor` del sitio donde caen. */
svg.ico { width: 17px; height: 17px; flex: none; display: block }
.alert svg.ico { align-self: flex-start; margin-top: 1px }
.alert.critical svg.ico { color: var(--bad) }
.alert.warning svg.ico { color: var(--warn-ink) }
.alert.ok svg.ico { color: var(--ok) }
.databar svg.ico { width: 15px; height: 15px }
.databar.demo svg.ico { color: var(--aqua) }
.databar.live svg.ico { color: var(--ok) }
.databar.err svg.ico { color: var(--bad) }
.unmet .uh svg.ico { width: 15px; height: 15px; color: var(--warn-ink) }
.hinsight svg.ico { width: 15px; height: 15px; color: var(--aqua); flex: none }
.sn.motivo svg.ico, .th-motivo svg.ico { width: 13px; height: 13px; display: inline-block; vertical-align: -2px; margin-right: 4px }
.install-bar svg.ico, .update-bar svg.ico { width: 15px; height: 15px; display: inline-block; vertical-align: -3px; margin-right: 6px }
.btn-icon svg.ico { width: 15px; height: 15px; display: inline-block; vertical-align: -3px }
.pending-banner svg.ico { color: var(--warn-ink) }

/* La nota que antes se repetía en cada fila del catálogo, dicha una sola vez. */
.inv-nota { font-size: 12.5px; color: var(--ink-3); padding: 12px 4px 0; text-align: center }

/* ---------- siluetas de carga ----------
   El panel arrancaba en blanco entre uno y tres segundos mientras resolvían
   las llamadas al servidor. Estas formas ocupan el sitio de lo que viene, sin
   brillo ni parpadeo: el arranque deja de parecer una pantalla rota. */
.sk { display: block; border-radius: 7px; background: var(--card-2); border: 1px solid var(--line-2) }
.sk + .sk { margin-top: 10px }
.sk-hero { padding: 4px 0 2px }
.sk-fila { padding: 15px 14px; border-radius: var(--r-sm); border: 1px solid var(--line); background: var(--card) }
.sk-kpi { padding: 15px 16px 17px; border-radius: var(--r); border: 1px solid var(--line); background: var(--card) }

/* ---- Cuestionario de alta (#166) ---- */
.onb-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px }
.onb-progress { font-size: 12px; color: var(--ink-3); white-space: nowrap }
.onb-chips { display: flex; flex-wrap: wrap; gap: 8px }
.onb-chip { padding: 7px 12px; border: 1px solid var(--line); border-radius: 999px; background: var(--card-2); cursor: pointer; font-size: 13px; text-align: left; color: inherit }
.onb-chip.on { border-color: var(--brand); font-weight: 600; box-shadow: 0 0 0 1px var(--brand) inset }
.onb-candado { opacity: .72 }
.onb-resumen { margin: 0; padding-left: 18px }
.onb-resumen li { margin: 0 0 7px }
.onb-plans { display: grid; gap: 10px }
.onb-plan { text-align: left; border: 1px solid var(--line); border-radius: 12px; padding: 12px 14px; background: var(--card-2); cursor: pointer; color: inherit; display: grid; gap: 3px }
.onb-plan.on { border-color: var(--brand); box-shadow: 0 0 0 1px var(--brand) inset }
.onb-plan .precio { font-size: 19px; font-weight: 700 }
.onb-plan em { color: var(--ink-3); font-style: normal; font-size: 12px }

/* ---- Surfia aprendió esto de tus clientes (#167) ---- */
.aprendizajes { display: grid; gap: 10px; margin: 4px 0 14px }
.apr-card { border: 1px solid var(--line); border-radius: 12px; background: var(--card-2); padding: 12px 14px }
.apr-card p { margin: 4px 0 10px; color: var(--ink-3); font-size: 13px }
.apr-card textarea { width: 100%; resize: vertical }
.apr-veces { font-size: 11px; color: var(--ink-3); margin-left: 6px }
.apr-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 8px }

/* Agenda de consultorio (#155 6/7): el rango Hoy/Semana, la nota de Google
 * conectado y el sello de sincronización por cita. */
.agenda-seg { display: inline-flex; margin-bottom: 12px }
.agenda-gcal { font-size: 12.5px; color: var(--ink-3); margin: -4px 0 12px }
.gcal-sync { font-size: 11px; font-weight: 600; padding: 2px 8px; border-radius: var(--r-pill); white-space: nowrap }
.gcal-sync.ok { background: var(--ok-soft); color: var(--ok) }
.gcal-sync.wait { background: var(--warn-soft); color: var(--warn) }

/* ── Cobros (épico ERP F1) ─────────────────────────────────────────────── */
.cob-chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0 4px }
.cob-form { display: flex; flex-wrap: wrap; gap: 12px; padding: 14px; align-items: flex-end }
.cob-form label { display: flex; flex-direction: column; gap: 4px; font-size: 13px }
.cob-form input, .cob-form select { padding: 6px 8px; font: inherit }
#cob-f-tasa-wrap { display: flex; gap: 12px }
#cob-f-tasa-wrap[hidden] { display: none }
.cob-draft { display: block; white-space: normal; color: var(--ink-3); font-size: 12.5px; margin-top: 4px }

/* ── Bloques de la Torre de Control ────────────────────────────────────── */
.bloque-row { display: flex; align-items: center; gap: 12px; padding: 10px 0; border-top: 1px solid var(--line) }
.bloque-row:first-of-type { border-top: 0 }
.bloque-row .what { flex: 1; min-width: 0 }
.bloque-row .what b { display: block; font-size: 14px }
.bloque-row .what span { color: var(--ink-3); font-size: 12.5px }

/* La hoja «Más» solo existe en el teléfono: en escritorio la barra lateral ya lo enseña todo. */
.mas { display: none }
/* En el demo no hay papelera (el dataset no tiene chats borrados): el chip no promete nada. */
html.demo [data-convstatus="trash"] { display: none }

/* ── Torre de Control (asistente del dueño) ────────────────────────────── */
.torre-fab {
  position: fixed; right: 18px; bottom: 18px; z-index: 60;
  display: flex; align-items: center; gap: 7px;
  padding: 11px 16px; border: 0; border-radius: 999px; cursor: pointer;
  background: var(--brand-grad); color: #fff; font: inherit; font-weight: 600; font-size: 14px;
  box-shadow: 0 6px 20px rgba(0, 0, 0, .28);
}
.torre-fab svg { width: 18px; height: 18px; fill: currentColor }
.torre-fab:hover { filter: brightness(1.08) }
/* La hoja de «Agente Surfia»: cristal con profundidad.
   Luis la vio «muy simple» y pidió refrescarla. La superficie deja de ser una
   tarjeta plana y pasa a ser un cristal translúcido sobre el panel, con un hilo
   de luz de marca en el canto de arriba. Todo lo de aquí abajo va anclado a
   `.torre` A PROPÓSITO: las burbujas y las notas son clases COMPARTIDAS con el
   hilo de clientes (hilo-screen.js) y con la traza, y un refresh sin ámbito les
   cambiaría la cara de rebote. */
.torre {
  position: fixed; right: 18px; bottom: 18px; z-index: 61;
  width: min(420px, calc(100vw - 36px)); max-height: min(70vh, 640px);
  display: flex; flex-direction: column;
  background: color-mix(in srgb, var(--card) 78%, transparent);
  backdrop-filter: blur(18px) saturate(1.4);
  -webkit-backdrop-filter: blur(18px) saturate(1.4);
  border: 1px solid color-mix(in srgb, var(--brand) 22%, var(--line));
  border-radius: 20px;
  box-shadow: 0 24px 60px -12px rgba(0, 0, 0, .55), 0 0 0 1px rgba(255, 255, 255, .03) inset;
  overflow: hidden;
}
/* El hilo de luz del canto: un solo trazo de marca, sin halo. No es decorativo
   — marca dónde empieza la superficie ahora que el fondo es translúcido. */
.torre::before {
  content: ''; position: absolute; inset: 0 0 auto; height: 1px;
  background: linear-gradient(90deg, transparent, var(--brand), transparent);
  opacity: .85; pointer-events: none;
}
.torre-head { display: flex; align-items: flex-start; gap: 12px; padding: 16px 18px 10px }
.torre-head h2 { margin: 0; font-size: 17px; letter-spacing: -.01em }
/* El nombre del sistema, debajo del nombre del asistente: mismo sitio donde
   antes iba una frase suelta. En versalitas y espaciado para que se lea como
   una firma y no compita con el título. */
.torre-head .sub-h { margin: 3px 0 0; font-size: 10.5px; letter-spacing: .09em; text-transform: uppercase; color: var(--ink-3) }
.torre-head .btn { margin-left: auto }
.torre .bubbles { flex: 1; overflow-y: auto; padding: 6px 16px 10px; min-height: 160px }
/* La Torre contesta con líneas, no con un párrafo: sus saltos de línea son
   parte de la respuesta (una línea por pedido, por cliente, por aviso). Sin
   esto se pegaban todos en un bloque corrido. Anclada a `.torre` a propósito:
   las burbujas del hilo de clientes (thread-mobile.css) se quedan como están,
   que ahí el texto lo escribe una persona y ya viene con su formato. */
.torre .bub { white-space: pre-wrap; overflow-wrap: anywhere }
.torre-caja { display: flex; gap: 8px; padding: 12px 18px 16px; border-top: 1px solid var(--line) }
/* La caja NO declaraba fondo, así que heredaba el blanco del navegador y
   desentonaba sobre el oscuro. Ahora se funde con la superficie y el foco lo
   marca la marca, no el anillo del sistema operativo. */
.torre-caja textarea {
  flex: 1; resize: none; font: inherit; padding: 10px 12px; border-radius: 12px;
  background: color-mix(in srgb, var(--card-2) 88%, transparent);
  border: 1px solid var(--line); color: var(--ink);
  transition: border-color var(--t-fast), box-shadow var(--t-fast);
}
.torre-caja textarea::placeholder { color: var(--ink-3) }
.torre-caja textarea:focus {
  outline: none; border-color: var(--brand);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 18%, transparent);
}
/* Las burbujas, con relieve en vez de línea de puntos. Solo dentro de la hoja. */
.torre .bub.note {
  border: 1px solid color-mix(in srgb, var(--line) 70%, transparent);
  background: color-mix(in srgb, var(--card-2) 82%, transparent);
  box-shadow: 0 2px 8px -4px rgba(0, 0, 0, .35);
}
.torre .bub.agent { box-shadow: 0 8px 22px -10px color-mix(in srgb, var(--brand) 55%, transparent) }
/* La sugerencia deja de ser texto con emoji multicolor y pasa a ser una pieza
   del panel: icono del sprite (que hereda el color) y superficie de marca. */
.torre .sugerencia {
  align-self: stretch; display: flex; gap: 9px; align-items: flex-start;
  margin: 2px 0 4px; padding: 10px 12px; border-radius: 14px; font-size: 12.5px;
  color: var(--ink-2);
  background: color-mix(in srgb, var(--brand) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--brand) 28%, transparent);
}
.torre .sugerencia svg { width: 15px; height: 15px; flex: none; margin-top: 1px; color: var(--brand) }
.propuesta {
  border: 1px solid var(--brand); border-radius: 12px; padding: 11px 13px; margin: 8px 0;
  background: color-mix(in srgb, var(--brand) 8%, transparent);
}
.propuesta .what b { display: block; font-size: 13px }
.propuesta .what span { display: block; color: var(--ink-3); font-size: 12.5px; margin-top: 2px }
.propuesta-btns { display: flex; gap: 8px; margin-top: 9px }
@media (max-width: 820px) {
  /* En el móvil la Torre ocupa la pantalla: el chat necesita el espacio y la
     barra inferior estorbaría. Mismo patrón del hilo. */
  .torre { right: 0; bottom: 0; left: 0; top: 0; width: 100%; max-height: none; border-radius: 0 }
  /* A pantalla completa el encabezado queda bajo la barra de estado del
     teléfono (`viewport-fit=cover` + status bar translúcida): sin el inset de
     arriba, «Torre de Control» se dibuja encima del reloj. Mismo olvido que
     tenía la hoja «Más»; se arreglan los dos juntos. */
  .torre-head { padding-top: calc(14px + env(safe-area-inset-top)) }
  .torre-fab { bottom: calc(64px + env(safe-area-inset-bottom)) }
  /* Con un hilo abierto el botón se va. En el teléfono el hilo es una pantalla
     de foco y su caja de respuesta vive pegada al fondo: el botón flotante caía
     justo encima de "Enviar" y del borde derecho del textarea, y contestarle a
     un cliente — lo único que se hace en esa pantalla — se volvía puntería.
     La Torre no se pierde: al volver a la lista el botón está otra vez ahí. */
  body.hilo-abierto .torre-fab { display: none }
  body.torre-abierta .bnav { display: none }
  /* Con la hoja «Más» abierta el FAB (z 60) flotaba sobre la cuadrícula, y
     encima sobra: la Torre ya está ahí dentro como un icono más. */
  body.mas-abierta .torre-fab { display: none }
  body.torre-abierta { overflow: hidden }
  /* El FAB de la Torre, solo icono: con texto tapaba las tarjetas y la caja del chat. */
  .torre-fab { padding: 12px }
  .torre-fab span { display: none }
  /* La hoja «Más» (épico #404): a pantalla completa bajo la barra (z 49 < 50),
     así la barra sigue a mano para saltar a una fija o cerrar con el mismo botón. */
  .mas:not([hidden]) { display: block }
  .mas {
    position: fixed; inset: 0; z-index: 49; background: var(--bg); overflow-y: auto;
    -webkit-overflow-scrolling: touch; padding: 0 16px calc(84px + env(safe-area-inset-bottom));
  }
  /* El respiro de arriba lo pone el encabezado, no la hoja: es él quien tiene
     que despejar la barra de estado —igual que `.main`— y quien se queda
     pegado arriba al bajar, para que «Cerrar» esté siempre a mano por larga
     que sea la lista. Los márgenes negativos llevan su fondo hasta los bordes:
     sin ellos el contenido se vería pasar por los 16px de los lados. */
  .mas-head {
    position: sticky; top: 0; z-index: 1; background: var(--bg);
    display: flex; align-items: center; gap: 8px;
    margin: 0 -16px 0; padding: calc(16px + env(safe-area-inset-top)) 16px 10px;
    border-bottom: 1px solid var(--line);
  }
  .mas-head h2 { flex: 1; min-width: 0; margin: 0; font-size: 20px }
  .mas-guia { padding-top: 12px }
  .mas-guia .sub-h { margin: 0 0 10px; font-size: 13px }
  .mas-head .btn, .mas-guia .btn { flex: none; padding: 7px 10px; font-size: 12.5px; display: inline-flex; align-items: center; gap: 5px }
  .mas-guia .btn svg { width: 14px; height: 14px; fill: none; stroke: currentColor }
  .mas-seccion h3 { font-size: 12px; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3); margin: 18px 0 10px; font-weight: 600 }
  /* Tres columnas, no cuatro: las secciones traen tres iconos y la cuarta
     columna quedaba vacía, con la fila recostada a la izquierda. Con tres, las
     celdas son anchas, el icono crece y los nombres largos («Personaliza
     Surfia», «Torre de Control») dejan de cortarse. */
  .mas-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 18px 8px }
  /* `width: 100%` como todo botón que hace de bloque en esta hoja de estilos
     (.kpi, .alert, .ev, .row.link): WebKit no estira los controles de
     formulario como ítems de grid, se quedan en su contenido y se pegan a la
     izquierda de su celda, cada uno con un ancho distinto según su etiqueta. */
  .mas-item { width: 100%; display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 0; font-size: 11.5px; font-weight: 500; color: var(--ink-2); text-align: center }
  .mas-item .ico { width: 62px; height: 62px; border-radius: 18px; background: var(--card-2); border: 1px solid var(--line); display: grid; place-items: center; transition: background var(--t-fast), border-color var(--t-fast) }
  .mas-item .ico svg { width: 24px; height: 24px }
  /* El cerebro de «Agente Surfia» lleva las tres corrientes del logo, pero solo
     donde el fondo las deja. Aquí el fondo es --card-2 y los azules lucen — es
     el mismo sitio donde #i-logo ya pinta el logo tricolor, en «Mi Surfia». En
     el botón flotante el fondo ES el degradado de marca: un azul sobre azul
     desaparece, así que allí no se define nada y las tres caen en el
     `currentColor` blanco. */
  .mas-item .ico svg { --cerebro-1: var(--logo-1); --cerebro-2: var(--logo-2); --cerebro-3: var(--logo-3) }
  /* Dos líneas en vez de «…»: el dueño puede renombrar sus pestañas y un
     nombre largo volvería a cortarse por mucho que quepan los de hoy. */
  .mas-item .lbl { max-width: 100%; overflow: hidden; white-space: normal; overflow-wrap: anywhere; line-height: 1.25; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical }
  .mas-item.fav .ico { border-color: var(--brand); background: var(--aqua-soft) }
  .mas-item.fav { color: var(--brand); font-weight: 600 }
  .mas-item:active .ico { background: var(--aqua-soft) }
  body.mas-abierta { overflow: hidden }
}

/* Precio de proveedor con demasiado tiempo encima: en Venezuela eso importa. */
.precio-viejo { color: var(--warn); font-weight: 600 }

/* «Las palabras de tu negocio» (vocabulario, fase Torre te recibe) */
.vocab-h { margin-top: 18px; }
.vocab-row { display: flex; align-items: center; gap: 10px; margin: 8px 0; }
.vocab-row label { flex: 1; color: var(--ink-2); font-size: 14px; }
.vocab-row input { width: 150px; }
#vocab-guardar { margin-top: 10px; }
.onb-trae { border: 1px solid var(--line); border-radius: 10px; padding: 12px 14px; margin: 12px 0; background: var(--card-2); }
.onb-trae p { margin: 6px 0 0; color: var(--ink-2); font-size: 14px; }

/* El alta viva (la Torre te recibe) */
.alta-vista { border: 1px solid var(--line); border-radius: 12px; padding: 10px 12px; margin-bottom: 10px; background: var(--card-2); }
.alta-mini { display: flex; flex-wrap: wrap; gap: 6px; }
.alta-tab { border: 1px solid var(--line); border-radius: 999px; padding: 3px 10px; font-size: 12.5px; background: var(--bg); transition: transform .35s ease, opacity .35s ease; }
.alta-tab.alta-on { animation: alta-pop .45s ease; border-color: var(--brand); }
@keyframes alta-pop { from { transform: scale(.6); opacity: 0; } to { transform: scale(1); opacity: 1; } }
.alta-hint { margin: 8px 0 0; font-size: 12.5px; color: var(--ink-2); }
.alta-chat { max-height: 46vh; min-height: 180px; overflow-y: auto; display: flex; flex-direction: column; gap: 8px; padding: 4px 2px; }
#alta-form { display: flex; gap: 8px; margin-top: 10px; }
#alta-form input { flex: 1; }
.alta-pie { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; justify-content: flex-end; }
@media (max-width: 480px) {
  .alta-chat { max-height: 38vh; }
  .alta-mini { flex-wrap: nowrap; overflow-x: auto; padding-bottom: 2px; }
}
.pill-reco { background: color-mix(in srgb, var(--brand) 14%, transparent); color: var(--brand); border-radius: 999px; padding: 1px 8px; font-size: 11px; font-weight: 600; }

/* La release que está corriendo (#276). Discreta a propósito: se busca cuando
 * algo salió raro después de publicar, no se lee todos los días. */
.version-pie { font-size: 11.5px; color: var(--ink-3); text-align: center; margin: 18px 0 4px }

/* ---------- el editor de la cotización (Issue #399, PR B) ---------- */
.doc-editor { display: flex; flex-direction: column; gap: 12px }
.doc-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 10px; flex-wrap: wrap }
.doc-head b { display: block; font-size: 15px }
.doc-head span { color: var(--ink-3); font-size: 12px }
.doc-acciones { display: flex; gap: 8px; flex-wrap: wrap; align-items: center }
.doc-lineas { width: 100%; border-collapse: collapse; font-size: 13px }
.doc-lineas th { text-align: left; font-size: 11px; color: var(--ink-3); font-weight: 600; padding: 6px 6px; border-bottom: 1px solid var(--line) }
.doc-lineas td { padding: 5px 6px; border-bottom: 1px solid var(--line-2); vertical-align: top }
.doc-lineas td small { display: block; color: var(--ink-3); font-size: 11px }
.doc-lineas input { width: 100%; min-width: 60px; padding: 7px 8px; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--card-2); color: var(--ink); font-size: 13px }
.doc-lineas td:nth-child(2) input, .doc-lineas td:nth-child(3) input { font-family: var(--mono); text-align: right }
/* La unidad va debajo de la cantidad, en la misma celda: es texto del cliente («mts», «cajas»), no un número. */
.doc-lineas td input[data-campo="unit"] { margin-top: 4px; font-family: inherit; text-align: left; font-size: 12px }
.doc-cabecera { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px 14px }
.doc-cabecera label { display: flex; flex-direction: column; gap: 4px; font-size: 11.5px; color: var(--ink-3) }
.doc-cabecera label.ancho { grid-column: 1 / -1 }
.doc-cabecera input, .doc-cabecera textarea { width: 100%; padding: 8px 10px; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--card-2); color: var(--ink); font-size: 13px }
.doc-totales { display: flex; gap: 18px; flex-wrap: wrap; justify-content: flex-end; font-size: 12.5px; color: var(--ink-3) }
.doc-totales b { color: var(--ink); font-family: var(--mono); margin-left: 4px }
.doc-totales .total b { color: var(--brand); font-size: 15px }
.doc-terms { color: var(--ink-2); font-size: 12.5px; white-space: pre-wrap }
@media (max-width: 720px) { .doc-cabecera { grid-template-columns: 1fr 1fr } .doc-lineas th:nth-child(4), .doc-lineas td:nth-child(4) { display: none } }
/* Pestaña «Banco» de Cobros (#404, punto 29): el resumen, los movimientos por
   estado y la subida del estado de cuenta. Las entradas en verde, las salidas
   apagadas: lo que se cuadra es lo que entra. */
#cob-tabs { margin-bottom: 12px }
.banco-mov .amt.in { color: var(--ok) }
.banco-mov .amt.out { color: var(--ink-3) }
.banco-subir input[type="file"] { font-size: 13px; max-width: 100% }
.banco-subir .thread-note { flex-basis: 100% }
.banco-resultado { flex-basis: 100%; margin: 0; padding-left: 18px; font-size: 13px; color: var(--ink-2) }
.banco-resultado li + li { margin-top: 4px }

/* Cuadrar un depósito (#404, punto 29, mitad 2): cada hipótesis con su
   confianza en palabras; la tasa y el método antes de confirmar. */
.banco-hip .what span { white-space: normal }
.banco-hip .conf { font-size: 11.5px; font-weight: 700; padding: 3px 9px; border-radius: 999px; white-space: nowrap }
.conf.alta { background: var(--aqua-soft); color: var(--brand) }
.conf.media { background: var(--card-2); color: var(--ink) }
.conf.baja { background: var(--card-2); color: var(--ink-3) }
.banco-tasa .thread-note { flex-basis: 100% }
.banco-metodo { display: inline-flex; flex-direction: column; gap: 4px; font-size: 13px; margin: 10px 0 }
.banco-metodo select { padding: 6px 8px; font: inherit }
.banco-acciones { display: flex; gap: 8px; margin: 12px 0 }
/* Datos de ejemplo (#404, punto 42): mientras el Inicio es de muestra, cada
   KPI lo dice en su etiqueta y el sello va arriba; el resto se atenúa un poco
   para que no compita con el sello. */
html.muestra .kpi .lbl::after { content: ' · ejemplo'; font-weight: 400; color: var(--ink-3) }
html.muestra #feed, html.muestra #demand-block, html.muestra #hours-block, html.muestra #avisos, html.muestra #alerts { opacity: .9 }
.muestra-sello b { font-weight: 700 }
/* Avisos agrupados (#404, punto 14): una familia con tres o más avisos se
   pliega en un grupo, y pasado el tope el resto queda tras «ver N avisos más».
   El resumen del grupo se ve como una barra de aviso pero no navega: despliega.
   Sin la flecha nativa del navegador: el «Ver ▾» ya dice qué hace. */
.aviso-grupo, .aviso-mas { width: 100% }
.aviso-grupo > summary, .aviso-mas > summary { cursor: pointer; list-style: none }
.aviso-grupo > summary::-webkit-details-marker { display: none }
.aviso-mas > summary::-webkit-details-marker { display: none }
.aviso-grupo > summary .go::before { content: 'Ver ▾' }
.aviso-grupo[open] > summary .go::before { content: 'Cerrar ▴' }
.aviso-grupo[open] > summary.alert { border-color: var(--brand) }
.aviso-grupo-lista { display: flex; flex-direction: column; gap: 8px; margin: 8px 0 0 10px; padding-left: 10px; border-left: 2px solid var(--line) }
.aviso-mas > summary { padding: 6px 12px; font-size: 13px; font-weight: 700; color: var(--brand) }
.aviso-mas > summary:hover { text-decoration: underline }
.aviso-mas > summary:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; border-radius: 6px }

/* Pedidos honestos (#404, PR 14a): el cliente que ya viene (empresa · RIF ·
   teléfono), la promesa de cotización y el buscador. */
.pedidos-q { width: 100%; max-width: 520px; margin: 0 0 12px; padding: 9px 12px; font: inherit; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--card); color: var(--ink) }
.pedidos-q[hidden] { display: none }
.order-head .order-cliente { display: block; font-size: 12.5px; color: var(--ink-2) }
.chip-cotizacion { display: inline-block; margin-top: 4px; padding: 2px 8px; border-radius: 999px; font-size: 11.5px; font-weight: 700 }
.chip-cotizacion.prometida { background: var(--aqua-soft); color: var(--brand) }
.chip-cotizacion.vencida { background: var(--warn-soft); color: var(--warn-ink) }

/* «Cliente de prueba» (#404, punto 5b): un interruptor pequeño bajo la ficha
   del hilo. Marcado, la persona deja de contar en las cifras. */
.ficha-prueba { display: inline-flex; align-items: center; gap: 6px; margin-left: 8px; font-size: 12px; color: var(--ink-3); cursor: pointer; white-space: nowrap }
.ficha-prueba input { margin: 0 }
