/* =============================================================================
   Koda — hoja de estilos

   Direccion de diseno: "la hora azul". Casi todo el mundo entrena antes del
   amanecer o de noche, asi que el fondo no es un gris de editor de codigo: es el
   indigo del cielo justo antes de que salga el sol, y el acento es esa primera
   luz calida. Los dos colores significan algo del mundo del runner en vez de ser
   "oscuro + naranja".

   Tipografia: Archivo (variable, con eje de anchura) para todo lo que se lee, y
   DM Mono para lo que se mide — ritmos, tiempos, distancias, fechas. Un dato
   nunca va en la misma letra que una frase: se lee de un vistazo, se alinea en
   columna y no baila cuando cambia el numero.

   Movimiento: solo donde tiene un porque. Ver docs/adr/ADR-015.
   ============================================================================= */

/* --- Tipografias vendorizadas (ver licencias/) ------------------------------ */

@font-face {
  font-family: "Archivo";
  src: url("/fuentes/archivo-variable-latin.woff2") format("woff2-variations");
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "DM Mono";
  src: url("/fuentes/dm-mono-400-latin.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "DM Mono";
  src: url("/fuentes/dm-mono-500-latin.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

/* --- Tokens ----------------------------------------------------------------- */

:root {
  /* Color */
  --noche: #090d18;
  --nocturno: #101625;
  --elevado: #171f33;
  --linea: #232d47;
  --linea-tenue: #1a2237;
  --tiza: #e9edf7;
  --bruma: #838fae;
  --bruma-honda: #5a6584;

  --amanecer: #ffb43f;
  --amanecer-hondo: #e8952a;
  --alba: #ffd79a;
  --brasa: rgba(255, 180, 63, 0.13);

  /* Semantica de entrenamiento: son los colores con los que se pintan las zonas
     en cualquier grafica de running, no una paleta decorativa. */
  --suave: #4fd1a5;
  --suave-claro: #a5edd2;
  --largo: #6ca8ff;
  --alerta: #ff6b84;

  /* Sombras tenidas con el azul del fondo, nunca negro puro */
  --sombra-1: 0 1px 2px rgba(4, 7, 14, 0.5);
  --sombra-2: 0 10px 30px -12px rgba(4, 7, 14, 0.8);
  --sombra-3: 0 30px 70px -24px rgba(4, 7, 14, 0.9);

  /* Radios: mas cerrados por dentro, mas abiertos por fuera */
  --r-xs: 6px;
  --r-sm: 10px;
  --r-md: 14px;
  --r-lg: 22px;
  --r-full: 999px;

  /* Espacio, base 4 */
  --e-1: 0.25rem;
  --e-2: 0.5rem;
  --e-3: 0.75rem;
  --e-4: 1rem;
  --e-5: 1.5rem;
  --e-6: 2rem;
  --e-7: 3rem;

  /* Tipografia */
  --cuerpo: "Archivo", system-ui, -apple-system, "Segoe UI", sans-serif;
  --dato: "DM Mono", ui-monospace, "SF Mono", Menlo, monospace;

  /* Curvas: las de easing.dev que usa Emil Kowalski. Las de serie del navegador
     son demasiado flojas y hacen que todo parezca dudar. */
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
  --ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);

  /* Capas */
  --z-compositor: 10;
  --z-velo: 30;
  --z-panel: 40;
  --z-grano: 60;

  --ancho-hilo: 780px;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

/* Las pantallas y los paneles se ocultan con [hidden], pero llevan display:flex
   o grid — y una regla de autor con display gana al [hidden] del navegador. Sin
   este !important, el panel se abre y ya no hay forma de cerrarlo. */
[hidden] {
  display: none !important;
}

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  min-height: 100dvh;
  background: var(--noche);
  color: var(--tiza);
  font-family: var(--cuerpo);
  font-size: 0.9375rem;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* Grano fijo sobre todo. Sin el, las superficies planas se ven sinteticas; con el
   tienen la textura de una foto con poca luz, que es la hora que representa. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: var(--z-grano);
  pointer-events: none;
  opacity: 0.035;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

::selection {
  background: var(--brasa);
  color: var(--tiza);
}

:focus-visible {
  outline: 2px solid var(--amanecer);
  outline-offset: 2px;
  border-radius: var(--r-xs);
}

/* Curvas de nivel de fondo. Es el lenguaje con el que se dibuja una ruta con
   desnivel en cualquier mapa o GPS, asi que el fondo dice "running" sin una foto
   de banco de un corredor. Se genera con scripts/generar_relieve.py.

   Va como mascara y no como imagen para poder tenirlo: el degradado hace que las
   curvas se apaguen hacia arriba, como un mapa que se pierde en la oscuridad. */
.relieve {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(to top, var(--linea) 0%, rgba(35, 45, 71, 0.35) 45%, transparent 78%);
  -webkit-mask-image: url("/relieve.svg");
  mask-image: url("/relieve.svg");
  -webkit-mask-size: 165% auto;
  mask-size: 165% auto;
  -webkit-mask-position: 30% bottom;
  mask-position: 30% bottom;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}

/* --- Elementos base --------------------------------------------------------- */

h1,
h2,
h3 {
  margin: 0;
  font-stretch: 112%;
  font-weight: 750;
  letter-spacing: -0.022em;
  line-height: 1.12;
  text-wrap: balance;
}

p {
  margin: 0;
  text-wrap: pretty;
}

svg {
  width: 1.25em;
  height: 1.25em;
  flex-shrink: 0;
  display: block;
}

button {
  font: inherit;
  color: inherit;
  border: none;
  background: none;
  cursor: pointer;
  transition: transform 160ms var(--ease-out);
}

button:active:not(:disabled) {
  transform: scale(0.97);
}

button:disabled {
  cursor: default;
  opacity: 0.5;
}

input,
select {
  font: inherit;
  color: var(--tiza);
  width: 100%;
  min-height: 46px;
  padding: 0 var(--e-3);
  border: 1px solid var(--linea);
  border-radius: var(--r-sm);
  background: var(--noche);
  transition:
    border-color 160ms ease,
    box-shadow 160ms ease;
}

input::placeholder {
  color: var(--bruma-honda);
}

input:focus,
select:focus {
  outline: none;
  border-color: var(--amanecer);
  box-shadow: 0 0 0 3px var(--brasa);
}

input[type="number"] {
  font-family: var(--dato);
  font-variant-numeric: tabular-nums;
}

label {
  display: block;
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--bruma);
  margin-bottom: var(--e-1);
}

.letra-chica {
  font-size: 0.75rem;
  line-height: 1.5;
  color: var(--bruma-honda);
}

.nota {
  font-size: 0.8125rem;
  color: var(--bruma);
}

.nota-destacada {
  display: flex;
  gap: var(--e-2);
  align-items: flex-start;
  padding: var(--e-3);
  border-radius: var(--r-sm);
  border-left: 2px solid var(--amanecer);
  background: var(--elevado);
  color: var(--tiza);
}

.nota-destacada svg {
  color: var(--amanecer);
  margin-top: 1px;
}

/* Cualquier medida — ritmo, distancia, tiempo, fecha. */
.dato {
  font-family: var(--dato);
  font-size: 0.94em;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
  word-spacing: -0.14em;
}

.eyebrow {
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--bruma-honda);
}

/* --- Botones ---------------------------------------------------------------- */

.boton {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--e-2);
  min-height: 46px;
  padding: 0 var(--e-5);
  border-radius: var(--r-sm);
  font-weight: 600;
  font-size: 0.9375rem;
  position: relative;
  transition:
    transform 160ms var(--ease-out),
    filter 160ms ease;
}

.boton-primario {
  background: linear-gradient(165deg, #ffbe55, var(--amanecer-hondo));
  color: #1f1400;
  box-shadow: var(--sombra-1);
}

.boton-secundario {
  border: 1px solid var(--linea);
  color: var(--bruma);
}

@media (hover: hover) and (pointer: fine) {
  .boton-primario:hover {
    filter: brightness(1.08);
  }

  .boton-secundario:hover {
    color: var(--tiza);
    border-color: var(--bruma-honda);
  }
}

/* Estado de carga: el texto se difumina en vez de desaparecer. Sin el blur se ven
   dos objetos distintos cruzandose; con el, el ojo lee una sola transformacion. */
.boton .cargador {
  position: absolute;
  width: 18px;
  height: 18px;
  border-radius: var(--r-full);
  border: 2px solid currentColor;
  border-top-color: transparent;
  opacity: 0;
  animation: girar 700ms linear infinite;
}

.boton .texto-boton {
  transition:
    filter 200ms ease,
    opacity 200ms ease;
}

.boton[data-cargando="si"] .texto-boton {
  filter: blur(3px);
  opacity: 0;
}

.boton[data-cargando="si"] .cargador {
  opacity: 1;
}

@keyframes girar {
  to {
    transform: rotate(360deg);
  }
}

.boton-icono {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: var(--r-sm);
  color: var(--bruma);
  transition:
    transform 160ms var(--ease-out),
    background-color 160ms ease,
    color 160ms ease;
}

.boton-icono svg {
  width: 21px;
  height: 21px;
}

@media (hover: hover) and (pointer: fine) {
  .boton-icono:hover {
    color: var(--tiza);
    background: var(--elevado);
  }
}

/* --- La marca --------------------------------------------------------------- */

/* El logotipo. Antes era un icono de linea sobre un degradado ambar hecho en CSS;
   ahora es el icono de aplicacion de verdad, el mismo que se ve en la pantalla de
   inicio del movil. Que el logotipo de la web y el icono instalado sean el mismo
   fichero no es ahorro: es que la pestana, el marcador y el icono del movil tienen
   que ser reconociblemente la misma cosa. */
.marca {
  display: grid;
  place-items: center;
  box-shadow: var(--sombra-1);
  border-radius: var(--r-md);
  flex-shrink: 0;
}

.marca img {
  width: 100%;
  height: 100%;
  display: block;
}


.marca-sm {
  width: 34px;
  height: 34px;
  border-radius: var(--r-sm);
}
.marca-md {
  width: 42px;
  height: 42px;
}
.marca-lg {
  width: 58px;
  height: 58px;
  border-radius: var(--r-lg);
}
.marca-xl {
  width: 72px;
  height: 72px;
  border-radius: var(--r-lg);
}

/* -----------------------------------------------------------------------------
   El retrato de Koda

   La marca (el icono de linea sobre ambar) es el logotipo: identifica al producto
   y se tiñe con currentColor. El retrato es el personaje: identifica a QUIEN te
   contesta. Son dos cosas distintas y por eso no comparten clase — el rail lleva
   logotipo, la conversacion lleva cara.

   No va recortado en circulo: el dibujo tiene orejas puntiagudas y cualquier
   mascara redonda se las come. Flota sobre un resplandor ambar, que ademas lo
   despega del fondo sin necesidad de un borde.
   ----------------------------------------------------------------------------- */

.retrato {
  position: relative;
  display: inline-grid;
  place-items: center;
  flex-shrink: 0;
  line-height: 0;
}

.retrato::before {
  content: "";
  position: absolute;
  inset: -22%;
  border-radius: 50%;
  background: radial-gradient(circle, var(--brasa), transparent 68%);
}

.retrato img {
  position: relative;
  width: 100%;
  height: auto;
  filter: drop-shadow(0 3px 8px rgba(0, 0, 0, 0.55));
}

/* -----------------------------------------------------------------------------
   Koda hablando

   El ecualizador del avatar solo se ve si ese mensaje esta en pantalla. Subes un
   poco en el hilo — o estas en el movil, donde caben dos mensajes — y desaparece
   la unica senal de que sigue hablando; con audio de veinte segundos, eso parece
   que se colgo. El retrato de la cabecera esta siempre a la vista.

   El resplandor crece con --voz, que app.js pone desde el PCM que suena en ese
   instante. No es un ritmo inventado: es su voz. La contraparte de las barras del
   microfono, que ya se mueven con la tuya.
   ----------------------------------------------------------------------------- */

.retrato.habla::before {
  background: radial-gradient(circle, var(--amanecer), transparent 66%);
  opacity: calc(0.18 + var(--voz, 0) * 0.5);
  transform: scale(calc(1 + var(--voz, 0) * 0.28));
  /* Solo hacia abajo: subir lo maneja --voz, que ya llega suavizado. Frenar la
     bajada evita el parpadeo en los silencios entre palabras. */
  transition: opacity 90ms linear;
}

.retrato.habla img {
  transform: scale(calc(1 + var(--voz, 0) * 0.05));
}

/* Por la cascada llega un MP3 ya montado: no hay nivel que seguir, asi que el
   resplandor late solo. Dice lo mismo con menos detalle. */
.retrato.habla-sin-nivel::before {
  animation: aliento-de-koda 1400ms var(--ease-in-out) infinite alternate;
}

@keyframes aliento-de-koda {
  from {
    opacity: 0.16;
    transform: scale(1);
  }
  to {
    opacity: 0.55;
    transform: scale(1.22);
  }
}

@media (prefers-reduced-motion: reduce) {
  .retrato.habla::before,
  .retrato.habla img {
    transition: none;
    animation: none;
    transform: none;
  }
  .retrato.habla::before {
    opacity: 0.4;
  }
}

.retrato-sm {
  width: 40px;
}
.retrato-lg {
  width: 82px;
}
.retrato-xl {
  width: 104px;
}

/* Un gesto dura lo justo para verse y volver. Escala desde el 88% en vez de
   aparecer: sustituir la imagen sin mas se lee como un parpadeo de carga. */
@keyframes gesto-de-koda {
  from {
    transform: scale(0.88) rotate(-4deg);
  }
  60% {
    transform: scale(1.06) rotate(1.5deg);
  }
  to {
    transform: scale(1) rotate(0);
  }
}

.retrato img.gesticula {
  animation: gesto-de-koda 420ms var(--ease-out);
}

@media (prefers-reduced-motion: reduce) {
  .retrato img.gesticula {
    animation: none;
  }
}

/* =============================================================================
   Entrar
   ============================================================================= */

.pantalla-login {
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: var(--e-5) var(--e-4);
  position: relative;
  overflow: hidden;
}

/* El sol que todavia no ha salido: una sola fuente de luz calida abajo a la
   derecha, que es de donde vienen todas las sombras de la interfaz. */
.fondo-decorativo {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(60rem 40rem at 85% 110%, rgba(255, 180, 63, 0.15), transparent 62%),
    radial-gradient(40rem 30rem at 10% -10%, rgba(108, 168, 255, 0.07), transparent 60%);
}

.tarjeta-login {
  position: relative;
  width: 100%;
  max-width: 400px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--e-3);
}

.tarjeta-login h1 {
  font-size: clamp(2.75rem, 12vw, 3.5rem);
  font-stretch: 118%;
  font-weight: 800;
  letter-spacing: -0.04em;
  margin-top: var(--e-3);
}

.tarjeta-login .subtitulo {
  color: var(--bruma);
  font-size: 1.0625rem;
  max-width: 22ch;
}

#form-solicitar {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: var(--e-3);
  margin-top: var(--e-4);
}

.campo {
  position: relative;
}

/* El botón armado para borrar. No es rojo desde el principio a propósito: un botón
   permanentemente en rojo se vuelve paisaje y deja de avisar de nada. */
.boton-peligro {
  border-color: var(--alerta);
  color: var(--alerta);
}

/* El eco de cómo se ha leído el tiempo. En ámbar y no en gris: es una confirmación
   activa, no una nota al pie que se ignora. */
.lectura-tiempo {
  margin: var(--e-1) 0 0;
  font-size: 0.8125rem;
  color: var(--amanecer);
}

/* Entrar pegando el enlace, solo visible en la aplicación instalada. */
.pegar-enlace {
  margin-top: var(--e-3);
  text-align: left;
}

.pegar-enlace summary {
  cursor: pointer;
  font-size: 0.8125rem;
  color: var(--bruma);
  padding: var(--e-1) 0;
}

.pegar-enlace summary:hover {
  color: var(--tiza);
}

.pegar-enlace .campo {
  margin: var(--e-2) 0;
}

/* --- Un dato que no cuadra, dicho donde está el dato ------------------------- */

.campo-mal,
.campo-mal:focus {
  border-color: var(--alerta);
  /* El borde solo no basta: hay quien no distingue rojo de gris, y el aviso de texto
     de debajo es lo que de verdad comunica. Esto es refuerzo, no el mensaje. */
  box-shadow: 0 0 0 1px var(--alerta);
}

.aviso-campo {
  margin: var(--e-1) 0 0;
  font-size: 0.8125rem;
  line-height: 1.45;
  color: var(--alerta);
}

.campo .icono-campo {
  position: absolute;
  left: var(--e-3);
  top: 50%;
  transform: translateY(-50%);
  width: 19px;
  height: 19px;
  color: var(--bruma-honda);
  pointer-events: none;
  transition: color 160ms ease;
}

.campo:focus-within .icono-campo {
  color: var(--amanecer);
}

.campo input {
  padding-left: calc(var(--e-3) * 2 + 19px);
}

/* =============================================================================
   Armazon de la app
   ============================================================================= */

.app {
  display: grid;
  grid-template-columns: 1fr;
  height: 100dvh;
  overflow: hidden;
}

.rail {
  display: none;
}

.chat {
  display: flex;
  flex-direction: column;
  min-height: 0;
  min-width: 0;
  position: relative;
}

.cabecera-chat {
  display: flex;
  align-items: center;
  gap: var(--e-3);
  padding: var(--e-3) var(--e-4);
  padding-top: max(var(--e-3), env(safe-area-inset-top));
  border-bottom: 1px solid var(--linea-tenue);
  background: rgba(9, 13, 24, 0.82);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  z-index: 2;
}

.identidad {
  display: flex;
  flex-direction: column;
  line-height: 1.25;
  margin-right: auto;
  min-width: 0;
}

.identidad strong {
  font-stretch: 110%;
  font-weight: 700;
  letter-spacing: -0.015em;
}

.estado {
  font-size: 0.75rem;
  color: var(--bruma-honda);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.acciones-cabecera {
  display: flex;
  gap: var(--e-1);
}

/* --- El hilo ---------------------------------------------------------------- */

.burbujas {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  display: flex;
  flex-direction: column;
  gap: var(--e-3);
  padding: var(--e-5) max(var(--e-4), calc((100% - var(--ancho-hilo)) / 2));
  scrollbar-width: thin;
  scrollbar-color: var(--linea) transparent;
}

.burbujas::-webkit-scrollbar {
  width: 10px;
}

.burbujas::-webkit-scrollbar-thumb {
  background: var(--linea);
  border: 3px solid var(--noche);
  border-radius: var(--r-full);
}

.mensaje {
  display: flex;
  gap: var(--e-2);
  align-items: flex-start;
  max-width: 100%;
  /* Entrada: sube un poco y aparece. Proposito — evitar que un mensaje nuevo
     teletransporte el hilo. 220ms, ease-out, solo transform y opacity. */
  animation: entrar-mensaje 220ms var(--ease-out) both;
}

@keyframes entrar-mensaje {
  from {
    opacity: 0;
    transform: translateY(10px) scale(0.985);
  }
}

/* El historial no entra: ya estaba. Cuarenta mensajes animandose a la vez al abrir
   la aplicacion serian una cascada de medio segundo antes de poder leer nada. */
.burbujas.sin-entrada .mensaje {
  animation: none;
}

/* Separador entre dias del historial. Una linea con la fecha encima: sin el, una
   conversacion de hace tres semanas se lee como si acabara de pasar. */
.separador-dia {
  display: flex;
  align-items: center;
  gap: var(--e-3);
  margin: var(--e-2) 0;
  color: var(--bruma-honda);
  font-size: 0.75rem;
  text-transform: lowercase;
}

.separador-dia::before,
.separador-dia::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--linea-tenue);
}

.separador-dia span {
  font-variant-caps: all-small-caps;
  letter-spacing: 0.08em;
}

.mensaje-usuario {
  flex-direction: row-reverse;
  align-self: flex-end;
}

.avatar {
  width: 28px;
  height: 28px;
  border-radius: var(--r-sm);
  display: grid;
  place-items: center;
  flex-shrink: 0;
  margin-top: 3px;
  overflow: hidden;
}

.avatar img {
  width: 100%;
  height: 100%;
  display: block;
}

.burbuja {
  max-width: min(100%, 58ch);
  padding: var(--e-3) var(--e-4);
  border-radius: var(--r-lg);
  font-size: 0.9375rem;
  line-height: 1.6;
}

.mensaje-coach .burbuja {
  background: var(--nocturno);
  border: 1px solid var(--linea-tenue);
  border-bottom-left-radius: var(--r-xs);
}

.mensaje-usuario .burbuja {
  background: linear-gradient(165deg, #ffbe55, var(--amanecer-hondo));
  color: #1f1400;
  border-bottom-right-radius: var(--r-xs);
  box-shadow: var(--sombra-1);
}

.mensaje-usuario .burbuja .dato {
  color: #2e1f00;
}

/* Contenido ya formateado: parrafos, listas y negritas. Se construye nodo a nodo
   en JS, nunca con innerHTML — lo que escribe el modelo no se interpreta como
   HTML jamas. */
.burbuja > * + * {
  margin-top: var(--e-2);
}

.burbuja ul,
.burbuja ol {
  margin: 0;
  padding-left: var(--e-4);
  display: flex;
  flex-direction: column;
  gap: var(--e-1);
}

.burbuja ul {
  list-style: none;
  padding-left: var(--e-3);
}

.burbuja ul li {
  position: relative;
  padding-left: var(--e-4);
}

.burbuja ul li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.66em;
  width: 7px;
  height: 2px;
  border-radius: 1px;
  background: var(--amanecer);
}

.mensaje-usuario .burbuja ul li::before {
  background: #1f1400;
}

.burbuja ol {
  list-style: none;
  counter-reset: paso;
}

.burbuja ol li {
  counter-increment: paso;
  position: relative;
  padding-left: var(--e-5);
}

.burbuja ol li::before {
  content: counter(paso);
  position: absolute;
  left: 0;
  top: 0;
  font-family: var(--dato);
  font-size: 0.78em;
  color: var(--amanecer);
}

.burbuja strong {
  font-weight: 650;
}

.mensaje-coach .dato {
  color: var(--alba);
}

/* --- Transcripcion de voz --------------------------------------------------- */

.etiqueta-voz {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--bruma-honda);
  margin-bottom: var(--e-1);
}

.etiqueta-voz svg {
  width: 12px;
  height: 12px;
}

.mensaje-usuario .etiqueta-voz {
  color: rgba(31, 20, 0, 0.55);
  justify-content: flex-end;
  width: 100%;
}

/* Lo que el modelo cree haber oido, antes de confirmarlo. Se ve distinto a
   proposito: el runner tiene que poder distinguir el borrador del texto final. */
.provisional {
  color: var(--bruma);
  font-style: italic;
}

.mensaje-usuario .provisional {
  color: rgba(31, 20, 0, 0.62);
}

.provisional::after {
  content: "";
  display: inline-block;
  width: 2px;
  height: 0.95em;
  margin-left: 3px;
  vertical-align: -0.12em;
  background: currentColor;
  animation: cursor 1s steps(2, start) infinite;
}

@keyframes cursor {
  50% {
    opacity: 0;
  }
}

/* Al confirmarse, el borrador y el texto definitivo se cruzan. Un fundido normal
   deja ver dos textos superpuestos; un desenfoque de 2px los mezcla y el ojo lee
   una sola cosa que se afina. */
.asentando {
  filter: blur(2.5px);
  opacity: 0.55;
  transition:
    filter 180ms ease,
    opacity 180ms ease;
}

/* --- Koda pensando y hablando ----------------------------------------------- */

.pensando {
  display: flex;
  align-items: center;
  gap: var(--e-2);
  color: var(--bruma);
  font-size: 0.875rem;
}

.puntos {
  display: flex;
  gap: 4px;
}

/* Animacion CSS y no JS a proposito: mientras esto se ve, el hilo principal esta
   ocupado esperando y decodificando la respuesta. Las de CSS corren fuera de el y
   no pierden fotogramas justo cuando mas se miran. */
.puntos span {
  width: 5px;
  height: 5px;
  border-radius: var(--r-full);
  background: currentColor;
  animation: latir 1.1s var(--ease-in-out) infinite;
}

.puntos span:nth-child(2) {
  animation-delay: 140ms;
}
.puntos span:nth-child(3) {
  animation-delay: 280ms;
}

@keyframes latir {
  0%,
  60%,
  100% {
    opacity: 0.28;
    transform: translateY(0);
  }
  30% {
    opacity: 1;
    transform: translateY(-3px);
  }
}

.avatar.hablando {
  border-color: var(--amanecer);
  box-shadow: 0 0 0 3px var(--brasa);
}

/* --- Estado vacio ----------------------------------------------------------- */

.bienvenida {
  position: relative;
  margin: auto 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--e-3);
  padding: var(--e-4) 0 var(--e-6);
}

/* En el hilo el relieve va aun mas bajo: compite con el texto de la conversacion,
   que es lo unico que importa ahi. */
.relieve-suave {
  opacity: 0.55;
  -webkit-mask-position: 60% 120%;
  mask-position: 60% 120%;
}

.bienvenida > *:not(.relieve) {
  position: relative;
}

.bienvenida h2 {
  font-size: clamp(1.75rem, 7vw, 2.25rem);
  font-stretch: 116%;
  font-weight: 800;
  letter-spacing: -0.035em;
  margin-top: var(--e-2);
}

.bienvenida p {
  color: var(--bruma);
  max-width: 42ch;
}

.sugerencias {
  display: flex;
  flex-wrap: wrap;
  gap: var(--e-2);
  margin-top: var(--e-3);
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--e-2);
  padding: var(--e-2) var(--e-3);
  border: 1px solid var(--linea);
  border-radius: var(--r-full);
  background: var(--nocturno);
  color: var(--bruma);
  font-size: 0.8125rem;
  font-weight: 500;
  transition:
    transform 160ms var(--ease-out),
    border-color 160ms ease,
    color 160ms ease;
}

.chip svg {
  width: 16px;
  height: 16px;
  color: var(--amanecer);
}

@media (hover: hover) and (pointer: fine) {
  .chip:hover {
    color: var(--tiza);
    border-color: var(--bruma-honda);
  }
}

/* --- El compositor ---------------------------------------------------------- */

.compositor {
  padding: var(--e-3) max(var(--e-4), calc((100% - var(--ancho-hilo)) / 2));
  padding-bottom: max(var(--e-3), env(safe-area-inset-bottom));
  border-top: 1px solid var(--linea-tenue);
  background: rgba(9, 13, 24, 0.82);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  z-index: var(--z-compositor);
}

.caja-compositor {
  display: flex;
  align-items: center;
  gap: var(--e-2);
  padding: var(--e-1);
  border: 1px solid var(--linea);
  border-radius: var(--r-lg);
  background: var(--nocturno);
  transition:
    border-color 160ms ease,
    box-shadow 160ms ease;
}

.caja-compositor:focus-within {
  border-color: var(--bruma-honda);
  box-shadow: var(--sombra-1);
}

.caja-compositor input {
  flex: 1;
  min-width: 0;
  border: none;
  background: none;
  min-height: 42px;
  padding-left: var(--e-3);
}

.caja-compositor input:focus {
  outline: none;
  box-shadow: none;
}

.boton-mic,
.boton-enviar {
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  border-radius: var(--r-md);
  flex-shrink: 0;
  transition:
    transform 160ms var(--ease-out),
    background-color 180ms ease,
    color 180ms ease;
}

.boton-mic {
  color: var(--bruma);
}

.boton-mic svg {
  width: 21px;
  height: 21px;
}

.boton-mic .icono-parar {
  display: none;
}

@media (hover: hover) and (pointer: fine) {
  .boton-mic:hover {
    color: var(--tiza);
    background: var(--elevado);
  }
}

.boton-enviar {
  background: var(--elevado);
  color: var(--bruma-honda);
}

.boton-enviar svg {
  width: 19px;
  height: 19px;
}

/* Solo se enciende cuando hay algo que mandar. */
.caja-compositor:has(input[type="text"]:not(:placeholder-shown)) .boton-enviar,
.compositor:has(#previa-foto:not([hidden])) .boton-enviar {
  background: linear-gradient(165deg, #ffbe55, var(--amanecer-hondo));
  color: #1f1400;
}

/* --- Foto lista para enviar --- */

.previa-foto {
  display: flex;
  align-items: center;
  gap: var(--e-3);
  margin-bottom: var(--e-2);
  padding: var(--e-2);
  border: 1px solid var(--linea);
  border-radius: var(--r-md);
  background: var(--nocturno);
  animation: entrar-previa 220ms var(--ease-out) both;
}

@keyframes entrar-previa {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
}

.previa-foto img {
  width: 44px;
  height: 44px;
  border-radius: var(--r-sm);
  object-fit: cover;
  flex-shrink: 0;
}

.previa-texto {
  flex: 1;
  min-width: 0;
  line-height: 1.3;
}

.foto-enviada {
  display: block;
  width: 100%;
  max-width: 240px;
  border-radius: var(--r-md);
  margin-bottom: var(--e-2);
}

.previa-texto strong {
  display: block;
  font-size: 0.875rem;
}

/* --- Grabando --------------------------------------------------------------- */

.compositor.grabando .caja-compositor {
  display: none;
}

.barra-grabacion {
  display: flex;
  align-items: center;
  gap: var(--e-3);
  height: 52px;
  padding: 0 var(--e-3) 0 var(--e-4);
  border: 1px solid rgba(255, 180, 63, 0.34);
  border-radius: var(--r-lg);
  background: var(--nocturno);
}

.punto-rec {
  width: 8px;
  height: 8px;
  border-radius: var(--r-full);
  background: var(--amanecer);
  flex-shrink: 0;
  animation: respirar 1.6s var(--ease-in-out) infinite;
}

@keyframes respirar {
  50% {
    opacity: 0.25;
  }
}

.etiqueta-rec {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--tiza);
  white-space: nowrap;
}

/* Las barras se mueven con el volumen real del microfono. Si no se mueven, no te
   esta oyendo — y eso se ve antes de mandar el audio, no despues. */
.ondas {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 3px;
  height: 26px;
  min-width: 0;
  overflow: hidden;
}

.ondas span {
  width: 3px;
  height: 100%;
  border-radius: var(--r-full);
  background: var(--amanecer);
  transform: scaleY(0.16);
  transform-origin: center;
  transition: transform 80ms linear;
}

.cronometro {
  font-family: var(--dato);
  font-size: 0.8125rem;
  font-variant-numeric: tabular-nums;
  color: var(--bruma);
  flex-shrink: 0;
}

.barra-grabacion .boton-mic {
  background: var(--amanecer);
  color: #1f1400;
}

.barra-grabacion .boton-mic .icono-micro {
  display: none;
}

.barra-grabacion .boton-mic .icono-parar {
  display: block;
}

/* =============================================================================
   Paneles
   ============================================================================= */

.velo {
  position: fixed;
  inset: 0;
  z-index: var(--z-velo);
  background: rgba(4, 7, 14, 0.65);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
  opacity: 0;
  transition: opacity 300ms var(--ease-out);
}

.velo.abierto {
  opacity: 1;
}

.panel {
  position: fixed;
  z-index: var(--z-panel);
  display: flex;
  flex-direction: column;
  background: var(--nocturno);
  box-shadow: var(--sombra-3);
  /* Sale por donde entro: en movil sube desde abajo, en escritorio entra desde la
     derecha. La curva es la de Vaul/Ionic, la que usan las hojas de iOS. */
  transition: transform 420ms var(--ease-drawer);
}

/* Movil: hoja inferior */
@media (max-width: 759px) {
  .panel {
    inset: auto 0 0 0;
    max-height: 92dvh;
    border-radius: var(--r-lg) var(--r-lg) 0 0;
    border-top: 1px solid var(--linea);
    transform: translateY(100%);
    padding-bottom: env(safe-area-inset-bottom);
  }

  .panel.abierto {
    transform: translateY(0);
  }

  /* El asa: en una hoja que sube desde abajo, dice que se puede cerrar. */
  .cabecera-panel::before {
    content: "";
    position: absolute;
    top: 8px;
    left: 50%;
    transform: translateX(-50%);
    width: 36px;
    height: 4px;
    border-radius: var(--r-full);
    background: var(--linea);
  }
}

/* Escritorio: cajon lateral */
@media (min-width: 760px) {
  .panel {
    inset: 0 0 0 auto;
    width: min(440px, 100%);
    border-left: 1px solid var(--linea);
    transform: translateX(100%);
  }

  .panel.abierto {
    transform: translateX(0);
  }
}

.cabecera-panel {
  position: relative;
  /* El arrastre de la hoja se lleva el gesto: sin esto el navegador intenta
     desplazar la pagina al mismo tiempo y el panel da tirones. */
  touch-action: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e-3);
  padding: var(--e-4);
  padding-top: max(var(--e-4), env(safe-area-inset-top));
  border-bottom: 1px solid var(--linea-tenue);
  flex-shrink: 0;
}

.cabecera-panel h2 {
  display: flex;
  align-items: center;
  gap: var(--e-2);
  font-size: 1.0625rem;
  font-stretch: 110%;
}

.cabecera-panel h2 svg {
  width: 19px;
  height: 19px;
  color: var(--amanecer);
}

.contenido-panel {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--e-4) var(--e-4) var(--e-7);
  display: flex;
  flex-direction: column;
  gap: var(--e-4);
  scrollbar-width: thin;
  scrollbar-color: var(--linea) transparent;
}

/* En la bienvenida no hay a donde volver: el chat todavia no se ha visto. Se sale
   guardando o diciendo "lo hago despues", no con una cruz que no lleva a nada. */
.panel.modo-bienvenida .cerrar-panel {
  display: none;
}

/* =============================================================================
   Panel del plan — "la pista"
   ============================================================================= */

.pista {
  padding: var(--e-4);
  border-radius: var(--r-lg);
  background:
    radial-gradient(28rem 14rem at 90% -20%, rgba(255, 180, 63, 0.12), transparent 70%),
    var(--elevado);
  border: 1px solid var(--linea-tenue);
}

.pista-titular {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--e-3);
  margin-bottom: var(--e-4);
}

.pista-titular h3 {
  font-size: 1.25rem;
  font-stretch: 114%;
}

.cuenta-atras {
  text-align: right;
  flex-shrink: 0;
  line-height: 1;
}

.cuenta-atras .numero {
  display: block;
  font-family: var(--cuerpo);
  font-size: 2.5rem;
  font-stretch: 120%;
  font-weight: 800;
  letter-spacing: -0.045em;
  font-variant-numeric: tabular-nums;
  color: var(--amanecer);
}

.cuenta-atras .unidad {
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--bruma-honda);
}

/* Los carriles: una barra por semana, la altura es el volumen. El plan se cuenta
   hacia atras desde la carrera, asi que la bajada del final no es un bug — es el
   taper, y aqui se ve de un vistazo. */
.carriles {
  display: flex;
  align-items: flex-end;
  gap: 3px;
  height: 68px;
  margin-bottom: var(--e-2);
}

.carril {
  flex: 1;
  min-width: 0;
  border-radius: 3px 3px 1px 1px;
  background: var(--linea);
  transform-origin: bottom;
  position: relative;
}

.carril-hecha {
  background: var(--bruma-honda);
}
.carril-descarga {
  background: var(--suave);
  opacity: 0.75;
}
.carril-taper {
  background: var(--suave-claro);
}
.carril-actual {
  background: var(--amanecer);
  box-shadow: 0 0 12px rgba(255, 180, 63, 0.45);
}

/* Momento unico: los carriles crecen en cascada al abrir el plan. Es lo que se ve
   una vez, cuando ya hay un plan que enseñar — el sitio donde el presupuesto de
   deleite esta permitido. */
.carriles.animar .carril {
  animation: crecer 320ms var(--ease-out) both;
  animation-delay: calc(var(--i) * 26ms);
}

@keyframes crecer {
  from {
    transform: scaleY(0.06);
    opacity: 0;
  }
}

.pista-pie {
  display: flex;
  justify-content: space-between;
  gap: var(--e-2);
  font-size: 0.75rem;
  color: var(--bruma-honda);
  border-top: 1px solid var(--linea-tenue);
  padding-top: var(--e-2);
}

.pista-pie .meta {
  display: flex;
  align-items: center;
  gap: 5px;
  color: var(--bruma);
}

.pista-pie svg {
  width: 14px;
  height: 14px;
}

/* --- Lo siguiente ----------------------------------------------------------- */

.proxima {
  display: flex;
  gap: var(--e-3);
  align-items: flex-start;
  padding: var(--e-4);
  border-radius: var(--r-md);
  border: 1px solid rgba(255, 180, 63, 0.26);
  background: var(--brasa);
}

.proxima .icono-sesion {
  color: var(--amanecer);
}

.proxima .cuando {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--amanecer);
  margin-bottom: 2px;
}

/* --- Zonas de ritmo --------------------------------------------------------- */

.bloque {
  display: flex;
  flex-direction: column;
  gap: var(--e-2);
}

.bloque > h4 {
  margin: 0;
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--bruma-honda);
}

.zonas {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(128px, 1fr));
  gap: var(--e-2);
  list-style: none;
  padding: 0;
  margin: 0;
}

.zonas li {
  padding: var(--e-2) var(--e-3);
  border-radius: var(--r-sm);
  background: var(--elevado);
  border-left: 2px solid var(--linea);
}

.zonas li:nth-child(4n + 1) {
  border-left-color: var(--suave);
}
.zonas li:nth-child(4n + 2) {
  border-left-color: var(--largo);
}
.zonas li:nth-child(4n + 3) {
  border-left-color: var(--alba);
}
.zonas li:nth-child(4n + 4) {
  border-left-color: var(--amanecer);
}

.zonas .nombre-zona {
  display: block;
  font-size: 0.6875rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--bruma-honda);
  margin-bottom: 1px;
}

.zonas .dato {
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--tiza);
}

/* --- Semanas ---------------------------------------------------------------- */

.semana {
  border: 1px solid var(--linea-tenue);
  border-radius: var(--r-md);
  background: var(--nocturno);
  overflow: hidden;
}

.semanas {
  display: flex;
  flex-direction: column;
  gap: var(--e-2);
}

.semana > summary {
  display: flex;
  align-items: center;
  gap: var(--e-2);
  padding: var(--e-3);
  cursor: pointer;
  list-style: none;
  -webkit-user-select: none;
  user-select: none;
  transition: background-color 160ms ease;
}

.semana > summary::-webkit-details-marker {
  display: none;
}

@media (hover: hover) and (pointer: fine) {
  .semana > summary:hover {
    background: var(--elevado);
  }
}

.semana .caret {
  width: 15px;
  height: 15px;
  color: var(--bruma-honda);
  transition: transform 200ms var(--ease-out);
}

.semana[open] .caret {
  transform: rotate(90deg);
}

.semana .num-semana {
  font-weight: 600;
  font-size: 0.875rem;
}

.semana .volumen {
  margin-left: auto;
  font-family: var(--dato);
  font-size: 0.8125rem;
  color: var(--bruma);
}

.etiqueta {
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 2px 7px;
  border-radius: var(--r-xs);
}

.etiqueta-descarga {
  background: rgba(79, 209, 165, 0.14);
  color: var(--suave);
}

.etiqueta-taper {
  background: rgba(165, 237, 210, 0.13);
  color: var(--suave-claro);
}

.sesiones {
  border-top: 1px solid var(--linea-tenue);
}

.sesion {
  display: flex;
  align-items: baseline;
  gap: var(--e-3);
  padding: var(--e-2) var(--e-3);
  font-size: 0.875rem;
}

.sesion + .sesion {
  border-top: 1px solid var(--linea-tenue);
}

.sesion-dia {
  width: 2.4rem;
  flex-shrink: 0;
  font-family: var(--dato);
  font-size: 0.75rem;
  color: var(--bruma-honda);
  text-transform: lowercase;
}

.icono-sesion {
  align-self: center;
  color: var(--bruma);
}

.icono-sesion svg {
  width: 16px;
  height: 16px;
}

.sesion-facil .icono-sesion {
  color: var(--suave);
}
.sesion-largo .icono-sesion {
  color: var(--largo);
}
.sesion-series .icono-sesion,
.sesion-tempo .icono-sesion {
  color: var(--amanecer);
}
.sesion-descanso {
  color: var(--bruma-honda);
}

.sesion-texto {
  min-width: 0;
}

.sesion-ritmo {
  margin-left: auto;
  flex-shrink: 0;
  font-family: var(--dato);
  font-size: 0.75rem;
  color: var(--bruma-honda);
}

/* --- Vacio y carga ---------------------------------------------------------- */

.vacio {
  margin: auto;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--e-3);
  padding: var(--e-6) var(--e-4);
  color: var(--bruma);
  max-width: 34ch;
}

.vacio svg {
  width: 34px;
  height: 34px;
  color: var(--linea);
}

/* Cuando el hueco es "todavia no tienes plan", quien lo ocupa es Koda corriendo.
   Un icono de linea gris en una pantalla vacia se lee como algo que fallo al
   cargar; el personaje se lee como lo que es. */
.vacio-con-koda img {
  width: clamp(140px, 42%, 190px);
  height: auto;
  margin-bottom: calc(var(--e-2) * -1);
  filter: drop-shadow(0 6px 16px rgba(0, 0, 0, 0.5));
}

.vacio strong {
  font-size: 1.0625rem;
  font-stretch: 110%;
  font-weight: 700;
  color: var(--tiza);
}

/* Esqueleto en vez de una ruleta: tiene la forma de lo que va a llegar, asi que
   la espera no cambia el layout cuando el contenido aparece. */
.esqueleto {
  border-radius: var(--r-md);
  background: linear-gradient(100deg, var(--nocturno) 30%, var(--elevado) 50%, var(--nocturno) 70%);
  background-size: 220% 100%;
  animation: barrer 1.4s linear infinite;
}

@keyframes barrer {
  to {
    background-position: -220% 0;
  }
}

/* =============================================================================
   Calendario
   Un mes entero y no una lista: una lista dice "el martes 8 km"; la rejilla deja
   ver cuantos dias seguidos hay descanso, si el largo siempre cae en domingo y
   cuanto falta para la carrera. Eso es lo que se mira al planear la semana.
   ============================================================================= */

.selector-vista {
  display: flex;
  gap: 2px;
  padding: 3px;
  border-radius: var(--r-sm);
  background: var(--elevado);
  border: 1px solid var(--linea-tenue);
}

.opcion-vista {
  flex: 1;
  min-height: 34px;
  border-radius: var(--r-xs);
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--bruma);
  transition:
    background-color 180ms var(--ease-out),
    color 180ms var(--ease-out);
}

.opcion-vista[aria-pressed="true"] {
  background: var(--nocturno);
  color: var(--tiza);
  box-shadow: var(--sombra-1);
}

.calendario-cabecera {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--e-2);
  margin-bottom: var(--e-2);
}

.mes-actual {
  margin: 0;
  font-size: 0.9375rem;
  font-stretch: 110%;
  text-transform: capitalize;
}

.hacia-atras {
  transform: rotate(180deg);
}

.calendario-dias,
.calendario-rejilla {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 3px;
}

.calendario-dias {
  margin-bottom: 3px;
}

.calendario-dias span {
  text-align: center;
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--bruma-honda);
}

.dia {
  position: relative;
  aspect-ratio: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  border-radius: var(--r-xs);
  font-family: var(--dato);
  font-size: 0.8125rem;
  color: var(--bruma);
  background: var(--elevado);
  transition:
    transform 160ms var(--ease-out),
    background-color 160ms ease;
}

/* Los dias de relleno del mes anterior y el siguiente siguen ahi porque quitarlos
   rompe la rejilla, pero no compiten: casi no se ven. */
.dia-fuera {
  background: none;
  color: var(--bruma-honda);
  opacity: 0.35;
}

.dia .punto {
  width: 5px;
  height: 5px;
  border-radius: var(--r-full);
  background: currentColor;
}

.dia-facil {
  color: var(--suave);
}
.dia-largo {
  color: var(--largo);
}
.dia-series,
.dia-tempo {
  color: var(--amanecer);
}
.dia-cruzado {
  color: var(--bruma);
}

.dia .punto-hecho {
  width: 7px;
  height: 7px;
  box-shadow: 0 0 0 2px var(--nocturno);
}

.numero-dia {
  color: var(--tiza);
  line-height: 1;
}

.dia-fuera .numero-dia {
  color: inherit;
}

/* Hoy va con un anillo y no con relleno: el relleno lo tiene el dia elegido, y si
   los dos se pintaran igual no se sabria cual es cual. */
.dia-hoy {
  box-shadow: inset 0 0 0 1.5px var(--bruma-honda);
}

.dia-elegido {
  background: var(--amanecer);
}

.dia-elegido .numero-dia,
.dia-elegido .punto {
  color: #1f1400;
}

.dia-carrera {
  background: linear-gradient(160deg, #ffbe55, var(--amanecer-hondo));
  color: #1f1400;
}

.dia-carrera .numero-dia {
  color: #1f1400;
}

.marca-carrera {
  width: 12px;
  height: 12px;
}

.calendario-detalle {
  min-height: 4.5rem;
  margin-top: var(--e-3);
  padding-top: var(--e-3);
  border-top: 1px solid var(--linea-tenue);
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 0.875rem;
}

@media (hover: hover) and (pointer: fine) {
  .dia:not(.dia-fuera):hover {
    background: var(--linea);
  }

  .dia-elegido:hover,
  .dia-carrera:hover {
    filter: brightness(1.08);
  }
}

/* =============================================================================
   Perfil y recordatorios
   ============================================================================= */

#form-perfil {
  display: flex;
  flex-direction: column;
  gap: var(--e-4);
}

.fila-campos {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--e-3);
}

.marca-reciente {
  margin: 0;
  padding: var(--e-4);
  border: 1px solid var(--linea-tenue);
  border-radius: var(--r-md);
  background: var(--elevado);
  display: flex;
  flex-direction: column;
  gap: var(--e-3);
}

.marca-reciente legend {
  padding: 0 var(--e-2);
  margin-left: calc(var(--e-2) * -1);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--amanecer);
}

.campo-select {
  position: relative;
}

.campo-select select {
  appearance: none;
  padding-right: var(--e-6);
}

.icono-select {
  position: absolute;
  right: var(--e-3);
  top: 50%;
  transform: translateY(-50%);
  width: 15px;
  height: 15px;
  color: var(--bruma-honda);
  pointer-events: none;
}

.acciones-form {
  display: flex;
  flex-direction: column;
  gap: var(--e-2);
}

.bloque-avisos {
  padding-top: var(--e-4);
  border-top: 1px solid var(--linea-tenue);
  display: flex;
  flex-direction: column;
  gap: var(--e-2);
}

.bloque-avisos h3 {
  display: flex;
  align-items: center;
  gap: var(--e-2);
  font-size: 0.9375rem;
}

.bloque-avisos h3 svg {
  width: 17px;
  height: 17px;
  color: var(--amanecer);
}

.aviso {
  display: flex;
  align-items: center;
  gap: var(--e-3);
  padding: var(--e-3);
  border-radius: var(--r-md);
  background: var(--elevado);
  border: 1px solid var(--linea-tenue);
}

.aviso .icono-aviso {
  color: var(--bruma-honda);
  transition: color 200ms ease;
}

.aviso:has(input[type="checkbox"]:checked) .icono-aviso {
  color: var(--amanecer);
}

.aviso-texto {
  flex: 1;
  min-width: 0;
}

.aviso-texto label {
  margin: 0;
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--tiza);
  cursor: pointer;
}

.aviso input[type="time"] {
  width: 6.5rem;
  min-height: 38px;
  padding: 0 var(--e-2);
  font-family: var(--dato);
  font-size: 0.8125rem;
  flex-shrink: 0;
  background: var(--noche);
}

.aviso input[type="time"]:disabled {
  opacity: 0.4;
}

/* Interruptor de verdad, no una casilla del sistema: se ve el estado desde lejos
   y el area de toque es la que necesita un pulgar. */
.interruptor {
  position: relative;
  width: 42px;
  height: 25px;
  flex-shrink: 0;
}

.interruptor input {
  position: absolute;
  inset: 0;
  width: 100%;
  min-height: 0;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
  z-index: 1;
}

.interruptor .pista-interruptor {
  position: absolute;
  inset: 0;
  border-radius: var(--r-full);
  background: var(--linea);
  transition: background-color 200ms var(--ease-out);
}

.interruptor .pista-interruptor::after {
  content: "";
  position: absolute;
  top: 3px;
  left: 3px;
  width: 19px;
  height: 19px;
  border-radius: var(--r-full);
  background: var(--bruma);
  transition:
    transform 200ms var(--ease-out),
    background-color 200ms var(--ease-out);
}

.interruptor input:checked + .pista-interruptor {
  background: var(--amanecer-hondo);
}

.interruptor input:checked + .pista-interruptor::after {
  transform: translateX(17px);
  background: #fffaf0;
}

.interruptor input:focus-visible + .pista-interruptor {
  outline: 2px solid var(--amanecer);
  outline-offset: 2px;
}

/* =============================================================================
   Escritorio
   ============================================================================= */

@media (min-width: 760px) {
  .app {
    grid-template-columns: 86px minmax(0, 1fr);
  }

  .rail {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--e-2);
    padding: var(--e-4) var(--e-2);
    border-right: 1px solid var(--linea-tenue);
    background: var(--nocturno);
  }

  .rail .marca {
    margin-bottom: var(--e-4);
  }

  .boton-rail {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 5px;
    width: 100%;
    padding: var(--e-2) var(--e-1);
    border-radius: var(--r-md);
    color: var(--bruma-honda);
    font-size: 0.625rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    transition:
      transform 160ms var(--ease-out),
      background-color 160ms ease,
      color 160ms ease;
  }

  .boton-rail svg {
    width: 22px;
    height: 22px;
  }

  .boton-rail[aria-current="true"] {
    color: var(--amanecer);
    background: var(--brasa);
  }

  .solo-movil {
    display: none;
  }

  .cabecera-chat .marca-sm {
    display: none;
  }

  .cabecera-chat {
    padding-block: var(--e-4);
  }
}

/* A partir de aqui cabe el plan al lado sin apretar la conversacion: deja de ser
   un cajon que tapa y pasa a ser una columna fija. Un plan que se consulta a cada
   rato no deberia costar un clic cada vez. */
@media (min-width: 1200px) {
  .app.plan-anclado {
    grid-template-columns: 86px minmax(0, 1fr) 400px;
  }

  .app.plan-anclado #panel-plan {
    position: static;
    transform: none;
    width: auto;
    box-shadow: none;
    background: var(--noche);
    border-left: 1px solid var(--linea-tenue);
    /* Sin esto la columna crece con su contenido en vez de repartir el alto, y
       las semanas quedan fuera de la pantalla sin forma de llegar a ellas: un
       elemento de rejilla trae min-height:auto y no deja desbordar por dentro. */
    min-height: 0;
  }

  .app.plan-anclado #panel-plan .cerrar-panel {
    display: none;
  }
}

/* =============================================================================
   Movimiento anadido — cada bloque dice para que sirve.
   El criterio esta en ADR-015: si no se puede nombrar el problema que resuelve,
   no se anima.
   ============================================================================= */

/* Cambio de pantalla (entrar -> app). Se ve una vez por sesion, despues de una
   redireccion: sin esto el contenido aparece de golpe y parece un salto de pagina.
   Solo opacidad, 220ms. */
/* Se anima .chat y no .app: una animacion de opacidad con fill:both deja un
   contexto de apilamiento permanente en el elemento, y el panel dejaria de poder
   salir por encima del velo — se ve como si el plan estuviera desenfocado. */
.pantalla-login:not([hidden]),
.app:not([hidden]) > .chat {
  animation: aparecer 220ms var(--ease-out) both;
}

@keyframes aparecer {
  from {
    opacity: 0;
  }
}

/* Las sugerencias del estado vacio. Primera vez que se abre la app y nunca mas:
   es el unico sitio donde el presupuesto de deleite esta permitido sin discusion.
   60ms entre una y otra — mas seria lento. */
.bienvenida .chip {
  animation: entrar-chip 300ms var(--ease-out) both;
}

.bienvenida .chip:nth-child(1) {
  animation-delay: 80ms;
}
.bienvenida .chip:nth-child(2) {
  animation-delay: 140ms;
}
.bienvenida .chip:nth-child(3) {
  animation-delay: 200ms;
}

@keyframes entrar-chip {
  from {
    opacity: 0;
    transform: translateY(7px);
  }
}

/* Contenido del plan al abrirlo. El panel es una superficie ocasional, no algo
   que se vea cien veces al dia. El escalonado nunca bloquea: se puede tocar
   cualquier cosa mientras entra. */
.contenido-panel.escalonar > * {
  animation: entrar-tarjeta 280ms var(--ease-out) both;
  animation-delay: calc(var(--i) * 40ms);
}

@keyframes entrar-tarjeta {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
}

/* Koda hablando. El anillo solo decia "algo pasa"; tres barras que se mueven
   dicen "esta sonando su voz", que es lo unico que el runner necesita saber
   cuando el movil esta en el bolsillo y solo lo mira de reojo. */
.ecualizador {
  display: none;
  align-items: center;
  justify-content: center;
  gap: 2px;
  width: 100%;
  height: 100%;
}

.avatar.hablando .ecualizador {
  display: flex;
}

.avatar.hablando > img,
.avatar.hablando > svg {
  display: none;
}

.ecualizador i {
  width: 2.5px;
  height: 40%;
  border-radius: var(--r-full);
  background: var(--amanecer);
  transform-origin: center;
  animation: ecualizar 800ms var(--ease-in-out) infinite alternate;
}

.ecualizador i:nth-child(2) {
  animation-delay: 160ms;
  height: 62%;
}
.ecualizador i:nth-child(3) {
  animation-delay: 320ms;
}

@keyframes ecualizar {
  from {
    transform: scaleY(0.45);
  }
  to {
    transform: scaleY(1.25);
  }
}

/* Acordeon de las semanas. Es la unica animacion que cuesta layout en cada
   fotograma, asi que va corta a proposito: 200ms. El alto lo mide el JS — animar
   hacia "auto" no se puede. */
.sesiones {
  overflow: hidden;
}

/* La espera de Koda se sustituye por su respuesta. Un cambio seco deja ver los
   dos textos cruzandose; 3px de desenfoque los funde y el ojo lee una sola cosa
   que se convierte en otra. */
.cambiando {
  filter: blur(3px);
  opacity: 0;
  transition:
    filter 160ms ease,
    opacity 160ms ease;
}

/* Mientras el dedo arrastra la hoja, manda el dedo: la transicion se apaga para
   que el panel siga al pulgar sin retraso, y vuelve al soltar. */
.panel.arrastrando {
  transition: none;
}

/* =============================================================================
   Menos movimiento
   Menos y mas suave, no cero: lo que ayuda a entender se queda (opacidad, color),
   lo que se mueve por el espacio se va.
   ============================================================================= */

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  .mensaje,
  .carriles.animar .carril,
  .bienvenida .chip,
  .contenido-panel.escalonar > * {
    animation: aparecer 180ms ease both;
    animation-delay: 0ms;
  }

  .ecualizador i {
    animation-duration: 2s;
  }

  .panel {
    transition: opacity 200ms ease;
  }

  .puntos span,
  .punto-rec,
  .esqueleto {
    animation-duration: 2.4s;
  }

  .ondas span {
    transition: none;
  }

  button:active:not(:disabled) {
    transform: none;
  }

}
