/* ============================================================
   S1gnal · modo barra
   ------------------------------------------------------------
   La voz vive en el marco de la aplicación, no encima. Una barra
   en el borde inferior, siempre presente, que crece hacia arriba
   cuando hay conversación.

   Dos reglas que gobiernan esta hoja:

   1. La barra SIEMPRE es oscura, aunque la edición sea de
      superficie clara. En el borde de una app clara necesita
      contraste para leerse como una capa distinta y no como
      otro bloque de contenido.

   2. En reposo sólo se ve lo indispensable: la ranura, la
      invitación y la tecla. Todo lo demás aparece cuando hace
      falta. Amontonar controles fue el error de la primera
      versión.
   ============================================================ */

/* La fila de la barra —invitación, campo de texto, tecla y cierre— vive en el
   mismo marcado que el panel flotante, porque es un solo componente. Mientras
   la barra sólo esté encendida en la landing, esas piezas no tienen sitio en
   las superficies que siguen con el panel alto: ahí se apagan. */
.signal-panel:not(.as-bar) .sg-hint,
.signal-panel:not(.as-bar) .sg-write,
.signal-panel:not(.as-bar) .sg-kbd,
.signal-panel:not(.as-bar) .sg-close { display: none; }

/* El envoltorio de acciones sólo existe para ocupar una celda de la rejilla de
   la barra. Fuera de ella se disuelve y sus hijos vuelven a ser hijos directos
   del panel, que es lo que espera el ritmo vertical del panel alto. */
.signal-panel:not(.as-bar) .sg-actions { display: contents; }

.signal-panel.as-bar {
  position: fixed;
  left: 0; right: 0; bottom: 0; top: auto;
  width: auto; max-width: none;
  height: auto; max-height: 62vh;

  display: flex;
  flex-direction: column;

  /* Superficie propia, no la del tema: la barra es oscura siempre. Pero
     «oscura» ya está definida en el kit —Tinta y sus derivados sobre Tinta—,
     así que se toman de ahí y no se inventan. El valor de respaldo existe sólo
     para cuando el motor se instale fuera de esta app. */
  --bar-ink: var(--dental-ink, #172428);
  --bar-line: var(--dental-line-ink, #526864);
  --bar-text: var(--dental-on-ink, #d7e4e1);
  /* El kit no define un tercer nivel de texto sobre Tinta; se deriva del
     segundo en vez de inventar un color nuevo. */
  --bar-soft: color-mix(in srgb, var(--dental-on-ink, #d7e4e1) 64%, transparent);

  /* Rampa del escáner para superficie oscura.
     La rampa del tema está calibrada sobre Niebla: su segmento apagado es una
     línea clarita que aquí salía casi blanca y convertía la ranura en un código
     de barras. Estos cuatro pasos no se inventan: son los mismos que pinta el
     símbolo de la marca sobre Tinta (RAMP y RAMP_OFF en
     src/components/s1gnal-dental-brand.tsx). El núcleo pálido es el punto
     incandescente; el color de marca nunca lo es. */
  --vw-seg-off: 36 59 52;    /* #243b34 — RAMP_OFF */
  --vw-seg-dim: 14 124 99;   /* #0e7c63 — Verde S1gnal Dental */
  --vw-seg-on: 47 147 118;   /* #2f9376 — RAMP[1] */
  --vw-seg-hot: 217 236 229; /* #d9ece5 — el núcleo */
  --vw-seg-glow: 14 124 99;  /* el halo respira en verde de marca */

  background: var(--bar-ink);
  color: var(--bar-text);
  border: 0;
  border-top: 2px solid var(--sg-amber);
  border-radius: 0;
  box-shadow: 0 -14px 40px rgba(0, 0, 0, .3);
  transform-origin: bottom left;
}

.signal-panel.as-bar::before { display: none; }

/* Fuera del reposo: cabecera, chips y aviso no viven en la barra. */
.signal-panel.as-bar .panel-head,
.signal-panel.as-bar .chips,
.signal-panel.as-bar .notice { display: none; }

/* El CTA a la clínica demo vive al final de la conversación: sólo se ve cuando
   la zona crece — ya hubo un turno, ya hay interés que cerrar. En reposo la
   barra no vende nada: escucha. */
.signal-panel.as-bar .panel-cta {
  margin: 0 28px 16px;
  height: auto;
  padding: 10px 0;
}

/* ---------- Zona que crece ---------- */
/* Nada de 0fr → 1fr: dentro de un flex de altura automática, 1fr resuelve
   contra el espacio disponible — que es cero — y la zona nunca abre. Se anima
   max-height, que sí funciona sin altura definida en el padre. */
.signal-panel.as-bar .sg-grow {
  max-height: 0;
  overflow: hidden;
  transition: max-height .32s cubic-bezier(.2, .9, .3, 1);
}
/* La altura la escribe el JS midiendo el contenido: así crece lo justo
   y no depende de que 46vh resuelva dentro de un flex. */
.signal-panel.as-bar.has-talk .sg-grow { max-height: var(--grow-h, 46vh); }
.signal-panel.as-bar .sg-grow-inner { min-height: 0; }

.signal-panel.as-bar .conversation {
  /* En el panel alto la conversación es una banda Fibonacci de 178 px fijos.
     Aquí la barra crece lo que ocupe el turno: con altura fija, una línea de
     respuesta abría un hueco de tres. */
  height: auto;
  flex: 0 1 auto;
  padding: 26px 28px 10px;
  max-height: 32vh;
  overflow-y: auto;
  background: none;
}
.signal-panel.as-bar .conversation .user-line {
  margin: 0 0 16px;
  font-size: 16px;
  line-height: 1.45;
  color: var(--bar-text);
}
.signal-panel.as-bar .conversation .user-line b {
  display: block;
  font-family: var(--sg-mono);
  font-size: 10px;
  letter-spacing: .18em;
  color: var(--bar-soft);
  font-weight: 500;
  margin-bottom: 4px;
}
.signal-panel.as-bar .conversation .speaker {
  font-family: var(--sg-mono);
  font-size: 10px;
  letter-spacing: .18em;
  color: var(--sg-amber);
  margin-bottom: 4px;
}
.signal-panel.as-bar .conversation .message {
  margin: 0;
  padding-left: 0;
  font-size: 16px;
  line-height: 1.45;
  color: var(--bar-text);
}

.signal-panel.as-bar .s1gnal-card,
.signal-panel.as-bar .s1gnal-dental-proposal { margin: 0 26px 14px; }

/* ---------- La fila ---------- */
/* Rejilla de tres columnas, no una fila de piezas sueltas.
 *
 * Con `flex` la ranura quedaba pegada a la izquierda, el texto junto a ella y
 * los controles al otro extremo: medio ancho de pantalla vacío en medio. Con
 * las columnas laterales al mismo peso (1fr), la ranura cae en el centro real
 * de la barra sin importar cuánto midan sus vecinos, y el hueco se reparte.
 *
 * 112 px de alto = altura del segmento × 4, la misma razón que gobierna el
 * segmento. La ranura necesita ese aire para leerse como instrumento y no como
 * una regla pegada al borde. */
.signal-panel.as-bar .sg-row {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 28px;
  padding: 0 28px;
  height: 112px;
  flex: 0 0 auto;
}
/* La invitación termina junto a la ranura, no pegada al borde izquierdo: así
   el ojo va del texto al instrumento sin cruzar un vacío. */
/* `grid-row: 1` en todos, no sólo la columna. La ranura va antes que el texto
   en el marcado —el orden lo manda el panel alto, donde es la banda de arriba—
   así que al pedir sólo la columna 2 el colocador ya había pasado la 1 y
   mandaba la invitación a una segunda fila, debajo. */
/* `stretch` + `text-align: right`, no `justify-self: end`.
   Con `end` el elemento se dimensiona a su contenido y luego se alinea al
   final de la celda: si el texto es más ancho que la columna, se desborda por
   la izquierda y se corta la primera palabra en vez de poner puntos al final.
   Estirado a la celda, el recorte cae donde debe. */
.signal-panel.as-bar .sg-hint {
  grid-area: 1 / 1;
  justify-self: stretch;
  min-width: 0;
  text-align: right;
}
/* El campo de texto sí toma toda su columna: es donde se está trabajando. */
.signal-panel.as-bar .sg-write { grid-area: 1 / 1; justify-self: stretch; }
.signal-panel.as-bar .reactor-wrap { grid-area: 1 / 2; }
.signal-panel.as-bar .sg-actions {
  grid-area: 1 / 3;
  justify-self: end;
  display: flex; align-items: center;
}

/* ---------- La ranura ----------
 *
 * Es el protagonista de la barra: el símbolo de la marca en movimiento, y lo
 * único que dice sin palabras que esto escucha.
 *
 * Proporción, no medidas sueltas. El segmento del instrumento grande mide
 * 6.5 × 26: alto = ancho × 4. La ranura de la barra conserva esa proporción
 * exacta a otra escala —7 × 28— con 4 px de aire, que es el ancho ÷ φ (4.33).
 * 35 segmentos = 381 px. La fila mide 112 = alto × 4: el segmento es a su
 * altura lo que la ranura es a la barra.
 *
 * Escalar es mover las cuatro variables juntas conservando 1:4 y ancho÷φ;
 * nunca estirar una sola, que es como el LED deja de ser un LED. */
.signal-panel.as-bar {
  --sg-led-w: 7px;
  --sg-led-h: 28px;
  --sg-led-gap: 4px;
  --sg-led-span: 381px; /* 35 × ancho + 34 × aire */
}
/* La ranura es además el botón de hablar: misma cara, cero cromo de botón.
   El padding vertical la lleva a 44 px de área táctil sin mover el dibujo. */
.signal-panel.as-bar .reactor-wrap {
  flex: 0 0 auto;
  box-sizing: content-box;
  padding: calc((44px - var(--sg-led-h)) / 2) 0;
  width: var(--sg-led-span); height: var(--sg-led-h);
  border: 0;
  background: none;
  cursor: pointer;
}
.signal-panel.as-bar .reactor-wrap:focus-visible {
  outline: 2px solid var(--sg-amber);
  outline-offset: 4px;
  border-radius: 6px;
}
.signal-panel.as-bar .reactor {
  height: var(--sg-led-h); border: 0; background: none; padding: 0;
}
.signal-panel.as-bar .reactor .axis,
.signal-panel.as-bar .reactor-state { display: none; }
/* Las escuadras de HUD marcan el instrumento dentro del panel alto. En la
   barra no hay instrumento que enmarcar —la ranura va suelta sobre la
   superficie— y quedaban como dos ganchos sueltos en las puntas. */
.signal-panel.as-bar .reactor::before,
.signal-panel.as-bar .reactor::after { display: none; }

/* En el panel alto la fila de LED está posicionada en absoluto dentro del
   instrumento y reserva sitio para el rótulo de estado. Aquí no hay ni
   instrumento ni rótulo: se devuelve al flujo, porque en absoluto ignoraba el
   alto de 20 px y los segmentos de 26 px se salían de la fila — de ahí que la
   ranura se leyera como un código de barras. */
.signal-panel.as-bar .voice-pixels {
  position: static;
  inset: auto;
  margin: 0;
  height: var(--sg-led-h);
  gap: var(--sg-led-gap);
  align-items: center;
}
/* Sin `flex: 0 0` los segmentos se repartían el ancho y quedaban en 2.3 px. */
.signal-panel.as-bar .voice-pixels i {
  flex: 0 0 var(--sg-led-w);
  width: var(--sg-led-w);
  height: var(--sg-led-h);
  border-radius: 2px;
}

/* El segmento sólo cambia de color. Nunca de forma ni de alto.
   El encendido del motor los estira con `scaleY` de .2 a 1.18: la ranura
   rebotaba al abrir y por un instante dejaba de ser una fila de LED para
   volverse un ecualizador. Aquí se enciende con luz, que es lo que hace un
   LED de verdad. */
.signal-panel.as-bar.is-igniting .voice-pixels i {
  animation-name: sg-ignite-luz;
}
@keyframes sg-ignite-luz {
  from { opacity: 0; }
  to { opacity: 1; }
}

.signal-panel.as-bar .sg-hint {
  margin: 0;
  font-size: var(--text-body, 16px);
  color: var(--bar-soft);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.signal-panel.as-bar .sg-hint b { color: var(--bar-text); font-weight: 600; }
.signal-panel.as-bar .sg-hint-touch { display: none; }
@media (hover: none) {
  /* En un teléfono la frase completa no cabe y terminaba en «Pídeme l…»:
     se queda sólo la instrucción, que es la parte que hace falta. */
  .signal-panel.as-bar .sg-hint-lead,
  .signal-panel.as-bar .sg-hint-key { display: none; }
  .signal-panel.as-bar .sg-hint-touch { display: inline; }
}
.signal-panel.as-bar.has-talk .sg-hint,
.signal-panel.as-bar.is-writing .sg-hint { display: none; }

/* Campo de texto: micrófono bloqueado, lugar ruidoso o preferencia. */
.signal-panel.as-bar .sg-write { min-width: 0; display: none; align-items: center; }
.signal-panel.as-bar.is-writing .sg-write { display: flex; }
.signal-panel.as-bar .sg-write input {
  flex: 1; min-width: 0; height: 38px;
  padding: 0 14px;
  border: 1px solid var(--bar-line);
  border-radius: 8px;
  background: color-mix(in srgb, var(--bar-text) 8%, transparent);
  color: var(--bar-text);
  font-family: var(--sg-text);
  font-size: var(--text-body, 16px);
}
.signal-panel.as-bar .sg-write input::placeholder { color: var(--bar-soft); }
.signal-panel.as-bar .sg-write input:focus-visible {
  outline: 2px solid var(--sg-amber); outline-offset: 1px;
}

/* ---------- Controles: mínimos, y sólo cuando aplican ---------- */
/* Al ocultarse la invitación durante la conversación nada empujaba los
   controles, y se amontonaban a la izquierda dejando la barra coja. */
.signal-panel.as-bar .control-zone {
  flex: 0 0 auto;
  /* `margin-top: auto` es lo que empuja los controles al fondo de la columna en
     el panel alto. En una fila centrada gana sobre `align-items` y dejaba el
     lápiz un renglón más abajo que la tecla y el cierre. */
  margin: 0 0 0 auto;
  display: flex; align-items: center; gap: 10px;
  padding: 0; border: 0; height: auto;
}
.signal-panel.as-bar .voice-control { align-items: center; }

/* La etiqueta y el botón grande de hablar sobran: se habla manteniendo la
   tecla o la barra. En táctil el botón sí aparece, porque no hay teclado. */
.signal-panel.as-bar .voice-label { display: none; }
.signal-panel.as-bar .voice-control { flex-direction: row; gap: 0; }
.signal-panel.as-bar .talk { display: none; }
@media (hover: none) {
  .signal-panel.as-bar .talk { display: grid; width: 42px; height: 42px; }
  /* Y con el botón de hablar en pantalla, la ranura larga sobra: se comía el
     ancho y dejaba la invitación en «Pídeme l…». El botón redondo ya trae su
     propio escáner animado, así que la afordancia no se pierde. */
  .signal-panel.as-bar .reactor-wrap { display: none; }
}

/* Interrumpir sólo existe mientras responde. */
.signal-panel.as-bar #interrupt { display: none; }
.signal-panel.as-bar.is-answering #interrupt { display: grid; }

/* Los controles no son cajas.
 *
 * Tres recuadros del mismo peso —lápiz, tecla y cierre— competían entre sí y
 * con el contenido de la página, y ninguno de los tres era la acción principal:
 * la acción principal es hablar, y esa no tiene botón. Así que se quedan como
 * iconos callados que sólo levantan superficie cuando el puntero llega. */
.signal-panel.as-bar .utility,
.signal-panel.as-bar .sg-close {
  flex: 0 0 auto;
  width: 36px; height: 36px;
  display: grid; place-items: center;
  border: 0;
  border-radius: 8px;
  background: none;
  color: var(--bar-soft);
  cursor: pointer;
  transition: color .14s ease, background-color .14s ease;
}
.signal-panel.as-bar .utility:hover,
.signal-panel.as-bar .sg-close:hover {
  color: var(--bar-text);
  background: color-mix(in srgb, var(--bar-text) 9%, transparent);
}
.signal-panel.as-bar .utility:focus-visible,
.signal-panel.as-bar .sg-close:focus-visible {
  outline: 2px solid var(--sg-amber); outline-offset: 2px;
}
/* Escribir y cerrar no son de la misma familia: una continúa la conversación,
   la otra la termina. Un pelo de línea las separa sin gritar. */
.signal-panel.as-bar .sg-close {
  position: relative;
  margin-left: 20px;
}
/* En el marco de la app el botón es un stop, y un stop en reposo no tiene
   nada que parar: aparece con la conversación y se va con ella. */
.signal-panel.as-frame .sg-close { display: none; }
.signal-panel.as-frame.has-talk .sg-close { display: grid; }

/* Dentro de la app, la barra y el riel del recorrido son la MISMA capa: la de
   S1gnal, que envuelve a la app clara del doctor. Comparten superficie para
   que se lean como una sola cosa y no como dos paneles oscuros distintos.
   En la landing la barra se queda en Tinta: ahí no hay riel al que igualarse. */
.signal-panel.as-bar.as-frame {
  --bar-ink: #0b2b23;
  --bar-line: rgba(215, 228, 225, .16);
}
.signal-panel.as-bar .sg-close::before {
  content: "";
  position: absolute; left: -10px; top: 50%;
  transform: translateY(-50%);
  width: 1px; height: 18px;
  background: var(--bar-line);
}

/* La tecla vive dentro de la frase, no suelta en la fila: ahí es una pista de
   lectura y no un cuarto botón que nadie puede presionar. */
.signal-panel.as-bar .sg-kbd {
  display: inline-block;
  margin: 0 2px;
  padding: 2px 7px;
  font-family: var(--sg-mono);
  font-size: 10px; letter-spacing: .08em;
  line-height: 1.5;
  color: var(--bar-text);
  background: color-mix(in srgb, var(--bar-text) 9%, transparent);
  border: 1px solid var(--bar-line);
  border-radius: 5px;
  white-space: nowrap;
}
/* Mientras se escribe, la barra espaciadora escribe un espacio: anunciarla
   como la tecla de hablar sería mentir. */
.signal-panel.as-bar.is-writing .sg-kbd { display: none; }
@media (hover: none) { .signal-panel.as-bar .sg-kbd { display: none; } }

/* Enviar lo escrito. Sin botón de envío el formulario dependía de que el
   navegador aceptara Enter, y además no había nada que tocar en táctil. */
/* Único control con relleno de la barra: mientras se escribe, enviar sí es la
   acción principal, y es la que debe verse primero. */
.signal-panel.as-bar .sg-send {
  flex: 0 0 auto;
  width: 36px; height: 36px;
  margin-left: 8px;
  display: grid; place-items: center;
  border: 0;
  border-radius: 8px;
  background: var(--sg-amber);
  color: var(--bar-ink);
  cursor: pointer;
  transition: filter .14s ease;
}
.signal-panel.as-bar .sg-send:hover { filter: brightness(1.15); }
.signal-panel.as-bar .sg-send:focus-visible {
  outline: 2px solid var(--sg-amber); outline-offset: 2px;
}

/* Mientras se sostiene, la barra entera se enciende. */
.signal-panel.as-bar.is-holding { border-top-color: var(--sg-hot); }
.signal-panel.as-bar.is-holding .sg-hint { color: var(--bar-text); }

/* La píldora crece a lo ancho hasta ser la barra. */
.signal-panel.as-bar.is-morphing { border-radius: 999px; }
.signal-panel.as-bar.is-open.is-morphing { border-radius: 0; }

/* Un escalón intermedio: por debajo de 1100 la ranura de 381 px le comía el
   ancho a la invitación. Baja de escala con la misma razón 1:4 —5 × 20 con 3
   de aire— en vez de recortarse por un lado. */
@media (max-width: 1100px) {
  .signal-panel.as-bar {
    --sg-led-w: 5px;
    --sg-led-h: 20px;
    --sg-led-gap: 3px;
    --sg-led-span: 277px;
  }
  .signal-panel.as-bar .sg-row { height: 80px; gap: 22px; }
  /* En anchos medios la frase completa se cortaba a media palabra: se queda
     la instrucción, que es la parte que trabaja. */
  .signal-panel.as-bar .sg-hint-lead { display: none; }
}

@media (max-width: 720px) {
  /* Sin ancho que repartir, la rejilla de tres columnas no aporta nada:
     vuelve a ser una fila y el texto ocupa lo que sobre. */
  .signal-panel.as-bar .sg-row {
    display: flex;
    height: 84px; padding: 0 16px; gap: 14px;
  }
  .signal-panel.as-bar .sg-hint { flex: 1; min-width: 0; }
  .signal-panel.as-bar .sg-write { flex: 1; min-width: 0; }
  .signal-panel.as-bar .sg-actions { margin-left: auto; }
  /* Misma razón 1:4, un paso más abajo: 3 × 12 con 2 de aire. */
  .signal-panel.as-bar {
    --sg-led-w: 3px;
    --sg-led-h: 12px;
    --sg-led-gap: 2px;
    --sg-led-span: 173px;
  }
  .signal-panel.as-bar .conversation { padding: 18px 16px 6px; }
  .signal-panel.as-bar .s1gnal-card,
  .signal-panel.as-bar .s1gnal-dental-proposal { margin: 0 16px 12px; }
}
