/* ═══════════════════════════════════════════════════════════════
   MIEL · Estructura — barra superior, riel de módulos, chat y
   panel lateral. Tres columnas en escritorio; en móvil el riel y
   el panel se vuelven cajones deslizables sobre el chat.
   ───────────────────────────────────────────────────────────────
   Una sola pantalla. Antes había dos: el chat en `/` y el rostro
   con las vitales en `/hud`. Eso obligaba a elegir entre hablarle
   y verla, y dejaba la mitad del sistema —qué motor respondió, qué
   agentes hay, qué queda pendiente— en una pestaña que casi nadie
   abría.

   DOS GRAMÁTICAS, A PROPÓSITO:

     · El MARCO —barra, riel, compositor, píldoras— lleva vidrio,
       aurora, degradado de marca y esquinas redondas. Es lo que
       hace que la pantalla se sienta viva.

     · El PANEL DE DATOS es lo contrario: superficies opacas,
       monoespaciada, versalitas, medidores. Es lo que hace que una
       cifra sea una cifra.

   No es una mezcla indecisa: es la regla de que el brillo vive en
   el marco y nunca debajo de un dato, llevada hasta su conclusión.
   Un número sobre vidrio cambia de contraste según lo que pase por
   detrás, y un número que a veces se lee y a veces no es peor que
   un número ausente.
   ═══════════════════════════════════════════════════════════════ */

/* --alto-ventana lo fija app.js desde visualViewport, que es lo unico que
   reporta el alto real cuando el teclado de iOS esta abierto.

   Va dentro de min() y no suelta: si la variable queda desactualizada (el
   navegador no siempre dispara el evento al cambiar el tamano de la ventana),
   una variable mas grande que la ventana empujaba el compositor FUERA de la
   pantalla. Pasaba en 1366x768, que es la resolucion de portatil mas comun.
   Con min() la app nunca puede ser mas alta que el viewport, y el caso del
   teclado abierto (donde la variable es MENOR) sigue funcionando.

   La primera declaracion es el respaldo para navegadores sin dvh. */
.app { display:flex; flex-direction:column; height:100vh; }
.app { height:min(100dvh, var(--alto-ventana, 100dvh)); }

/* Aurora de marca: tres manchas muy difusas y muy lentas. Es lo que impide
   que la pantalla se lea como un rectángulo negro —o como una hoja de papel,
   en tema claro—. Va en el fondo del documento, debajo de todo, y no recibe
   eventos.

   `z-index:-1` y NO un `z-index` positivo en `.app`. Levantar `.app` parecía
   lo natural, pero le abre un contexto de apilado propio, y entonces el riel
   y el panel —que viven adentro— quedan encerrados por debajo de cualquier
   capa que se cuelgue del `body`. El velo de los cajones es una de esas: se
   pintaba ENCIMA del cajón que acababa de abrirse, así que en el teléfono el
   menú se abría y no se veía nada. Con la aurora en -1, `.app` no abre
   contexto y el orden vuelve a ser el que espera `ui.js`. */
body::before {
  content:''; position:fixed; inset:-30%; z-index:-1; pointer-events:none;
  background:
    radial-gradient(38% 32% at 18% 12%, var(--aurora-1), transparent 70%),
    radial-gradient(34% 30% at 82% 78%, var(--aurora-2), transparent 70%),
    radial-gradient(30% 26% at 60% 30%, var(--aurora-3), transparent 70%);
  filter:blur(28px);
  animation:derivar 34s ease-in-out infinite alternate;
}

/* ── Barra superior ────────────────────────────────────── */
.topbar {
  height:var(--topbar-h);
  flex:0 0 auto;
  display:flex; align-items:center; gap:var(--sp-4);
  padding:0 var(--sp-4);
  background:var(--glass-2);
  -webkit-backdrop-filter:var(--blur-lg); backdrop-filter:var(--blur-lg);
  border-bottom:1px solid var(--glass-line);
  position:relative; z-index:30;
}

/* La identidad no se encoge. Si se encoge, lo primero que desaparece es la
   marca y queda una barra de iconos sueltos de los que no se sabe de qué
   aplicación son. Lo que cede es la fila de señales. */
.brand { display:flex; align-items:center; gap:var(--sp-3); flex:none; }
.brand-logo { width:30px; height:30px; object-fit:contain; flex:0 0 auto; }
.brand-text { min-width:0; }
.brand-name {
  font-family:var(--font-display);
  font-size:var(--fs-lg); font-weight:var(--peso-fuerte);
  letter-spacing:.2em; padding-left:.2em; line-height:1.1;
  background:var(--grad-nombre);
  -webkit-background-clip:text; background-clip:text; color:transparent;
}
.brand-sub {
  font-size:var(--fs-xs); color:var(--text-3); letter-spacing:.04em;
  line-height:1.2; margin-top:1px;
}

.topbar-status { display:flex; align-items:center; gap:var(--sp-2); margin-left:auto; min-width:0; }
.topbar-actions { display:flex; align-items:center; gap:var(--sp-1); flex:none; }

/* ── Cuerpo de tres columnas ───────────────────────────── */
/* `grid-template-rows:minmax(0,1fr)` y no la fila automática: con la fila
   `auto`, la columna del medio crece hasta lo que mida la conversación y
   empuja el compositor fuera de la pantalla. */
.shell {
  flex:1; min-height:0;
  display:grid;
  grid-template-columns:var(--rail-w) minmax(0,1fr) var(--side-w);
  grid-template-rows:minmax(0,1fr);
}
.shell[data-side="closed"] { grid-template-columns:var(--rail-w) minmax(0,1fr) 0; }

/* ── Riel de módulos ───────────────────────────────────── */
.rail {
  grid-column:1;
  display:flex; flex-direction:column; min-height:0;
  border-right:1px solid var(--glass-line);
  overflow-y:auto; overscroll-behavior:contain;
  padding-bottom:var(--sp-4);
}
.rail-group { display:flex; flex-direction:column; gap:2px; padding:0 var(--sp-2); }
.rail-footer { margin-top:auto; padding:var(--sp-4) var(--sp-3) 0; }
.atajos {
  display:flex; flex-direction:column; gap:6px; margin-top:var(--sp-2);
  font-size:var(--fs-xs); color:var(--text-3);
}

/* ── Columna de chat ───────────────────────────────────── */
/* min-height:0 es lo que permite que .feed se encoja. Sin esto, un item de
   grid usa min-height:auto y NO baja de su contenido: .chat crecia para caber
   feed + compositor, desbordaba .shell y el compositor quedaba fuera de la
   pantalla. Se veia en 1366x768 (la resolucion de portatil mas comun), en
   1024x768 y en Android 412x915; en pantallas mas altas no aparecia porque
   sobraba espacio. */
.chat { grid-column:2; display:flex; flex-direction:column; min-width:0; min-height:0; }

/* La cabecera es el rostro. No es un adorno con forma de cara: su ritmo
   cambia con el estado real del sistema, y está puesta donde uno mira
   mientras espera la respuesta. */
.chat-head {
  flex:0 0 auto; position:relative;
  display:flex; align-items:center; gap:var(--sp-4);
  padding:var(--sp-3) var(--sp-5);
}
#rostro {
  width:96px; height:96px; flex:none;
  filter:drop-shadow(0 0 22px rgba(232,184,92,.22));
}
.chat-head-texto { min-width:0; }
.rostro-linea { display:flex; align-items:center; gap:var(--sp-3); flex-wrap:wrap; }
.rostro-linea strong {
  font-family:var(--font-display); font-size:var(--fs-xl);
  font-weight:var(--peso-fuerte); letter-spacing:var(--track-tight);
  line-height:var(--lh-tight);
  background:var(--grad-texto);
  -webkit-background-clip:text; background-clip:text; color:transparent;
}
.chat-head .meta {
  font-size:var(--fs-xs); color:var(--text-3);
  display:flex; align-items:center; gap:6px; flex-wrap:wrap; margin-top:2px;
}

/* La onda del micrófono: cuarenta barras que solo se ven mientras Miel
   escucha o habla. Ocupa lugar siempre —altura fija— para que encenderla no
   empuje la conversación hacia abajo justo cuando uno empieza a hablar. */
.onda {
  position:absolute; left:var(--sp-5); right:var(--sp-5); bottom:2px;
  height:22px; display:flex; align-items:flex-end; gap:2px;
  opacity:0; transition:opacity var(--dur-2) var(--curva-estandar);
  pointer-events:none;
}
.onda[data-activa="si"] { opacity:1; }
.onda i {
  flex:1; min-width:1px; height:4px; border-radius:1px;
  background:var(--grad-linea);
  transition:height 90ms linear;
}
@media (max-width:820px) { .onda { left:var(--sp-3); right:var(--sp-3); } }

.feed {
  flex:1; min-height:0; overflow-y:auto; overscroll-behavior:contain;
  padding:var(--sp-4) var(--sp-5) var(--sp-5);
  display:flex; flex-direction:column; gap:var(--sp-4);
  scroll-behavior:smooth;
  /* El contenido se desvanece contra los bordes en vez de cortarse en seco.
     Va con `mask-image` y no con un degradado de fondo: el fondo queda DEBAJO
     de las tarjetas, así que un degradado ahí no las toca — se probó y el
     corte seguía siendo duro. La máscara actúa sobre lo pintado.

     El primer tramo es opaco hasta 24px para que el borde superior no coma
     texto cuando no hay scroll. */
  -webkit-mask-image:linear-gradient(to bottom, transparent 0, #000 24px,
                                     #000 calc(100% - 28px), transparent 100%);
  mask-image:linear-gradient(to bottom, transparent 0, #000 24px,
                             #000 calc(100% - 28px), transparent 100%);
  overflow-anchor:auto;
}
/* 1180px y no 860: una tabla de tres columnas no entraba y se comprimia
   hasta partir palabras. El limite de linea comoda para LEER se mantiene en la
   burbuja (76ch); esto solo da aire al contenido que de verdad lo necesita. */
.feed-inner { width:100%; max-width:1180px; margin:0 auto; display:flex; flex-direction:column; gap:var(--sp-4); }

/* ── Compositor ────────────────────────────────────────── */
.composer { flex:0 0 auto; padding:var(--sp-2) var(--sp-5) var(--sp-4); }
.composer-inner { max-width:1180px; margin:0 auto; }

/* ── Panel lateral ─────────────────────────────────────── */
.side {
  grid-column:3;
  display:flex; flex-direction:column; min-width:0; min-height:0;
  background:var(--bg-sunken);
  border-left:1px solid var(--border);
  overflow:hidden;
}
.shell[data-side="closed"] .side { display:none; }

.side-tabs {
  flex:0 0 auto; display:flex; gap:2px;
  padding:var(--sp-2) var(--sp-2) 0;
  border-bottom:1px solid var(--border);
}
.side-body { flex:1; min-height:0; overflow-y:auto; padding:var(--sp-3); }
.side-panel { display:flex; flex-direction:column; gap:var(--sp-3); animation:fade-in var(--t); }

/* ── Cajones (móvil / tablet) ──────────────────────────── */
.scrim {
  position:fixed; inset:0; background:var(--overlay); z-index:40;
  animation:fade-in var(--t); -webkit-backdrop-filter:blur(2px); backdrop-filter:blur(2px);
}

@media (max-width:1180px) {
  .shell, .shell[data-side="closed"] { grid-template-columns:var(--rail-w) minmax(0,1fr); }
  .side {
    position:fixed; top:var(--topbar-h); right:0; bottom:0; width:min(360px,88vw);
    z-index:50; box-shadow:var(--shadow-3);
    transform:translateX(100%); transition:transform var(--dur-3) var(--curva-expresiva);
  }
  .shell[data-side="open"] .side { display:flex; transform:none; }
  .shell[data-side="closed"] .side { display:flex; }
}

@media (max-width:820px) {
  .shell, .shell[data-side="closed"] { grid-template-columns:minmax(0,1fr); }
  .rail {
    position:fixed; top:var(--topbar-h); left:0; bottom:0; width:min(280px,84vw);
    z-index:50; box-shadow:var(--shadow-3); background:var(--bg);
    transform:translateX(-100%); transition:transform var(--dur-3) var(--curva-expresiva);
  }
  .shell[data-rail="open"] .rail { transform:none; }
  .feed { padding:var(--sp-3) var(--sp-3) var(--sp-4); }
  .composer { padding:var(--sp-2) var(--sp-3) var(--sp-3); }
  .chat-head { padding:var(--sp-3); gap:var(--sp-3); }
  #rostro { width:64px; height:64px; }
  .brand-sub { display:none; }
  .topbar { padding:0 var(--sp-3); gap:var(--sp-3); }
}

/* En pantalla de teléfono el rostro es un sello al lado del estado. Sigue
   estando —es la identidad de Miel— pero deja de comerse la altura útil. */
@media (max-width:560px) {
  #rostro { width:52px; height:52px; }
  .chat-head .meta .meta-sep, .chat-head .meta #chat-meta { display:none; }
  .rostro-linea strong { font-size:var(--fs-lg); }
}

/* La barra a 390px no da para todo. El orden de sacrificio no es estético:
   primero se va el subtítulo, después el rótulo de la señal de conexión, y
   nunca los botones —el micrófono, el audio y el acceso a los datos son la
   única forma de manejar Miel desde el teléfono. */
@media (max-width:560px) {
  /* La paleta de comandos es un atajo de teclado: en un teléfono no hay
     Ctrl+K, y todas sus acciones están listadas en el riel. Es el botón que
     menos cuesta perder cuando cinco objetivos de 44px no caben. */
  #btn-palette { display:none; }
}
/* 479 y no 420. El corte estaba puesto a ojo y dejaba rota justo la franja de
   421 a 479 —que es la del iPhone Pro Max y la del 14 Plus, 428 y 430 px—:
   ahí el rótulo «En línea» y el logo todavía se mostraban, la fila no daba, y
   como la píldora no parte el texto, se montaba quince píxeles encima del
   botón del micrófono. Medido: a 480 entra todo con holgura, a 479 no. */
@media (max-width:479px) {
  .topbar { gap:var(--sp-2); }
  .topbar-actions { gap:2px; }
  #chip-conn .chip-label { display:none; }
  #chip-conn { padding:0 9px; }
  /* El nombre en degradado ya es la marca; el logo al lado es redundante y
     cuesta 42px que hacen falta para los botones. */
  .brand-logo { display:none; }
}
/* Solo en los teléfonos más chicos —320px— se va también el interruptor de
   tema: sigue el del sistema por defecto, así que es el único control de la
   barra que casi nadie toca dos veces. */
@media (max-width:350px) {
  #btn-theme { display:none; }
  #chip-conn { display:none; }
}

/* Pantalla baja: el teléfono acostado, y también la ventana a medio achicar
   en el portátil. Con 390px de alto, el rostro se come dos tercios de lo útil
   y la conversación queda en una rendija. Se juzga por ALTO y no por ancho:
   un teléfono horizontal es ancho y bajo, y una regla de ancho no lo ve. */
@media (max-height:520px) {
  /* La barra baja de 60 a 48. Es un token y no un número suelto justamente
     para esto: el riel y el panel se cuelgan de `--topbar-h` y siguen
     alineados solos. */
  :root { --topbar-h:48px; }
  .chat-head { padding:var(--sp-1) var(--sp-4); }
  .feed { padding-top:var(--sp-2); padding-bottom:var(--sp-2); }
  #rostro { width:40px; height:40px; }
  .chat-head .meta { display:none; }
  .rostro-linea strong { font-size:var(--fs-md); }
  .suggestions { display:none !important; }
  /* El recordatorio de «Enter envía» y el contador de caracteres son ayuda,
     no contenido: con 343px de alto cuestan un renglón de conversación. */
  .composer-meta { display:none; }
  .composer { padding-top:0; padding-bottom:max(var(--sp-2), env(safe-area-inset-bottom)); }
  .onda { display:none; }
}

/* En monitores grandes la conversación se centra y se le pone tope. El texto
   ya venía limitado en la burbuja, pero el compositor no: en 2560px quedaba
   un campo de escritura de dos metros con el cursor perdido a la izquierda.
   El tope de `.feed-inner` y `.composer-inner` ya lo resuelve; acá solo se
   centra también la cabecera para que el rostro no quede solo en un extremo. */
@media (min-width:1700px) {
  .chat-head { width:100%; max-width:1180px; margin-inline:auto; }
}

@media (min-width:821px) { .only-mobile { display:none !important; } }
@media (max-width:1180px) { .only-wide { display:none !important; } }

/* ── Paleta de comandos ────────────────────────────────── */
.palette-wrap {
  position:fixed; inset:0; z-index:80;
  display:flex; align-items:flex-start; justify-content:center;
  padding:12vh var(--sp-4) var(--sp-4);
  background:var(--overlay); -webkit-backdrop-filter:blur(3px); backdrop-filter:blur(3px);
  animation:fade-in var(--t-fast);
}

/* ── Zona de avisos flotantes ──────────────────────────── */
.toasts {
  position:fixed; right:var(--sp-4); bottom:var(--sp-4); z-index:90;
  display:flex; flex-direction:column; gap:var(--sp-2);
  width:min(360px, calc(100vw - var(--sp-6)));
  pointer-events:none;
}

/* ── Areas seguras de iOS (notch y barra de inicio) ─────────
   index.html declara viewport-fit=cover, que le pide a iOS dibujar por debajo
   del notch y de la barra de inicio. Eso OBLIGA a compensar con los insets: sin
   esto el compositor quedaba tapado por la barra de inicio del iPhone y no se
   podia escribir, y la barra superior se metia bajo el notch.

   Se usa max() y no una suma para no agregar espacio en equipos sin notch,
   donde los insets valen 0. */
.composer {
  padding-bottom:max(var(--sp-4), env(safe-area-inset-bottom));
  padding-left:max(var(--sp-5), env(safe-area-inset-left));
  padding-right:max(var(--sp-5), env(safe-area-inset-right));
}
.topbar {
  padding-left:max(var(--sp-4), env(safe-area-inset-left));
  padding-right:max(var(--sp-4), env(safe-area-inset-right));
}
.feed {
  padding-left:max(var(--sp-5), env(safe-area-inset-left));
  padding-right:max(var(--sp-5), env(safe-area-inset-right));
}

@media (max-width:820px) {
  .composer {
    padding-bottom:max(var(--sp-3), env(safe-area-inset-bottom));
    padding-left:max(var(--sp-3), env(safe-area-inset-left));
    padding-right:max(var(--sp-3), env(safe-area-inset-right));
  }
  .feed {
    padding-left:max(var(--sp-3), env(safe-area-inset-left));
    padding-right:max(var(--sp-3), env(safe-area-inset-right));
  }
  .topbar { padding-left:max(var(--sp-3), env(safe-area-inset-left)); padding-right:max(var(--sp-3), env(safe-area-inset-right)); }
  /* Los cajones deslizables tambien nacen contra el borde fisico. */
  .rail { padding-left:env(safe-area-inset-left); padding-bottom:env(safe-area-inset-bottom); }
  .side { padding-right:env(safe-area-inset-right); padding-bottom:env(safe-area-inset-bottom); }
}
