html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
html, body { height: 100%; }
:root {
  --composer-dock-height: 0px;
  --keyboard-offset: 0px;
  --header-dock-height: 0px;
  /* Efecto de escritura de la respuesta (.ai-word, ver más abajo): color de
     "tinta fresca" mientras aparece cada palabra y color final ya asentado.
     Dorado en los dos modos; el final queda negro en claro, blanco en
     oscuro (ver override en html:not(.dark) más abajo). */
  --ai-word-flash: #f59e0b;
  --ai-word-final: #fff;
  --ai-response-grad-1: #ffffff;
  --ai-response-grad-2: #fef3c7;
  --ai-response-grad-3: #f59e0b;
  --ai-response-grad-4: #ffffff;
  --ai-response-shadow: rgba(245,158,11,.18);
}
html:not(.dark) {
  --ai-word-final: #0a0a0b;
  --ai-response-grad-1: #111827;
  --ai-response-grad-2: #b45309;
  --ai-response-grad-3: #f59e0b;
  --ai-response-grad-4: #111827;
  --ai-response-shadow: rgba(245,158,11,.12);
}
body {
  -webkit-font-smoothing: antialiased;
  padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
  overscroll-behavior-y: none;
}

/* El chat necesita una caja de altura conocida para que el área con scroll
   reparta bien el espacio con el composer fijo. En móvil se usa dvh para
   seguir el viewport visible real. */
#app {
  height: 100svh;
  height: 100dvh;
  min-height: 100svh;
  min-height: 100dvh;
}

@supports (-webkit-touch-callout: none) {
  #app {
    height: -webkit-fill-available;
    height: 100dvh;
    min-height: -webkit-fill-available;
    min-height: 100dvh;
  }
}

/* Con el teclado abierto (clase que pone syncAppViewportHeight en ai.js), y
   SOLO ahí — para no tocar el comportamiento normal en el resto de casos —
   #app sí mide exacto el espacio visible real (var(--app-vh), medido con
   visualViewport.height), para que la casilla quede pegada arriba del
   teclado en vez de flotar con un hueco vacío abajo. */
html.keyboard-open #app { height: var(--app-vh); }

/* Con el teclado abierto no queda espacio para el saludo/título fijo de la
   pantalla vacía Y las píldoras de sugerencias a la vez — las píldoras
   flotan encima de la casilla y terminaban tapando ese texto. El saludo se
   esconde mientras tanto; vuelve solo al cerrarse el teclado. */
html.keyboard-open #chatEmpty { opacity: 0; pointer-events: none; transition: opacity .2s ease; }

/* Un poco más de aire entre la casilla y el teclado (además del padding
   normal de #composerWrap, ver más abajo) — nada más que eso, no toca el
   alto de #app ni el scroll. */
html.keyboard-open #composerWrap {
  bottom: calc(var(--keyboard-offset) + .9rem);
  padding-bottom: calc(env(safe-area-inset-bottom) + .9rem);
}

/* Escopado a #chatMain (no un <main> genérico): styles.css es compartido
   por todas las páginas (publicidad.html, ads.html, avisos.html...), y
   --composer-dock-height solo lo actualiza ai.js, que corre nada más que
   acá — con un selector "main" a secas, esto le pisaba (con !important) el
   padding-bottom propio a los <main> de todas esas otras páginas. */
#chatMain {
  min-height: 0;
  padding-top: calc(var(--header-dock-height) + .5rem) !important;
  padding-bottom: calc(var(--composer-dock-height) + 1rem) !important;
}

/* El header flota (position:fixed) transparente encima del chat, en vez de
   reservar su propia franja de espacio como antes — el chat ocupa toda la
   altura de la pantalla y se ve pasar por detrás al scrollear (el padding
   de arriba de #chatMain, justo arriba, es lo que evita que el primer
   mensaje arranque tapado bajo el header en reposo). */
#appHeader {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 30;
  background: transparent;
  /* position:fixed saca al header del <body> (que reserva el notch/status
     bar con env(safe-area-inset-top) en su propio padding) — sin esto el
     header quedaría pegado contra el notch en celulares con muesca. Pisa
     el pt-6/sm:pt-8 de Tailwind (selector por ID le gana a la clase). */
  padding-top: calc(env(safe-area-inset-top) + 1.5rem);
}
@media (min-width: 640px) {
  #appHeader { padding-top: calc(env(safe-area-inset-top) + 2rem); }
}

#chatList {
  min-height: 0;
}

.no-scrollbar { scrollbar-width: none; -ms-overflow-style: none; }
.no-scrollbar::-webkit-scrollbar { display: none; }

/* Margen de abajo del contenedor de escribir. Va como padding-bottom en
   #composerWrap (el envoltorio) y no como margin-bottom en #composer (la
   caja en sí): un margin-bottom ahí puede colapsar con el de sus
   contenedores padre y terminar sin verse — padding nunca colapsa, así que
   es la forma segura de que el margen se note siempre. El área segura del
   celular (gesture bar/home indicator) ya la reserva el propio body más
   arriba, así que no se repite acá para no duplicarla. */
#composerWrap {
  position: fixed;
  left: 0;
  right: 0;
  bottom: var(--keyboard-offset);
  z-index: 40;
  padding-bottom: calc(env(safe-area-inset-bottom) + 1rem);
}
@media (min-width: 640px) {
  #composerWrap { padding-bottom: calc(env(safe-area-inset-bottom) + 1.25rem); }
}

/* Botón incógnito: activo cuando el chat no está guardando historial. */
.incognito-active {
  background: rgba(129,140,248,.18) !important;
  color: #a5b4fc;
  box-shadow: inset 0 0 0 1.5px rgba(129,140,248,.6);
}

/* Sugerencias en píldora encima de la casilla del chat. Suben desde abajo
   al aparecer y bajan de nuevo al esconderse (controlado desde JS con una
   clase, no con display:none de un salto). Entrada más lenta y con
   desaceleración, salida más rápida y con aceleración — el mismo patrón
   asimétrico usado en el resto de las animaciones de la app. */
#suggestPills {
  transition: opacity .62s cubic-bezier(.33,1,.68,1), transform .62s cubic-bezier(.33,1,.68,1), filter .62s cubic-bezier(.33,1,.68,1);
  opacity: 0;
  filter: blur(6px);
  transform: translateY(26px) scale(.955);
}

#suggestPills.ai-pills-in {
  opacity: 1;
  filter: blur(0);
  transform: none;
  transition: opacity 1.05s cubic-bezier(.22,1,.36,1), transform 1.05s cubic-bezier(.22,1,.36,1), filter 1.05s cubic-bezier(.22,1,.36,1);
}

.ai-pill {
  font-size: 13px;
  font-weight: 700;
  color: #fff;
  background: rgba(255,255,255,.07);
  border: 1px solid rgba(255,255,255,.16);
  border-radius: 999px;
  padding: .7rem 1.1rem;
  white-space: nowrap;
  opacity: 0;
  transform: translateY(10px) scale(.97);
  transition: background .35s ease, transform .35s ease, opacity .55s ease;
}

.ai-pill:hover { background: rgba(255,255,255,.13); transform: translateY(-1px); }

#suggestPills.ai-pills-in .ai-pill {
  opacity: 1;
  transform: none;
}

#suggestPills.ai-pills-in .ai-pill:nth-child(1) { transition-delay: .04s; }
#suggestPills.ai-pills-in .ai-pill:nth-child(2) { transition-delay: .12s; }
#suggestPills.ai-pills-in .ai-pill:nth-child(3) { transition-delay: .2s; }

html:not(.dark) .ai-pill {
  color: #0a0a0b;
  background: #fff;
  border-color: rgba(0,0,0,.08);
  box-shadow: 0 2px 10px rgba(0,0,0,.07);
}
html:not(.dark) .ai-pill:hover { background: #f5f5f7; }

/* Píldoras con ícono de la pantalla vacía (debajo de #heroSubtitle) — los
   accesos directos a las mismas 4 funciones del menú del foco. Van en dos
   columnas compactas para que ocupen menos ancho visual sin perder claridad.
   Los íconos no traen su propio tamaño en el HTML — .hero-quick-pill svg de
   acá abajo es lo único que lo define. */
.hero-quick-pill {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: .5rem;
  font-size: 13px;
  font-weight: 700;
  color: #fff;
  background: rgba(255,255,255,.07);
  border: 1px solid rgba(255,255,255,.16);
  border-radius: 999px;
  padding: .78rem .9rem;
  width: 100%;
  text-align: left;
  line-height: 1.15;
  transition: background .2s ease, transform .15s ease;
  opacity: 0;
  transform: translateY(24px) scale(.96);
  animation: aiHeroIn 1.18s cubic-bezier(.22,1,.36,1) both;
}
.hero-quick-pill svg { flex-shrink: 0; width: 20px; height: 20px; }
.hero-quick-pill:nth-child(1) { animation-delay: .34s; }
.hero-quick-pill:nth-child(2) { animation-delay: .46s; }
.hero-quick-pill:nth-child(3) { animation-delay: .58s; }
.hero-quick-pill:nth-child(4) { animation-delay: .7s; }
.hero-quick-pill:hover { background: rgba(255,255,255,.13); transform: translateY(-1px); }
html:not(.dark) .hero-quick-pill {
  color: #0a0a0b;
  background: #fff;
  border-color: rgba(0,0,0,.08);
  box-shadow: 0 2px 10px rgba(0,0,0,.07);
}
html:not(.dark) .hero-quick-pill:hover { background: #f5f5f7; }

/* Logo + saludo + título de la pantalla vacía: fijos arriba (justify-start
   en el HTML), debajo del botón de la flecha del header. Ya no se atenúan
   ni se mueven al enfocar la casilla — las sugerencias flotan encima de la
   casilla (position:absolute) sin tocar este bloque para nada. La
   transición de acá es un respaldo elegante: si por lo que sea llega a
   cambiar de posición (p. ej. el teclado del celular achicando la pantalla
   al enfocar la casilla), que sea con un desplazamiento suave y lento en
   vez de un salto brusco. */
#chatEmpty {
  transition: transform .6s cubic-bezier(.16,1,.3,1), opacity .6s cubic-bezier(.16,1,.3,1);
}

/* Botón del foco (abre el menú de opciones): se prende de amarillo mientras
   el menú está abierto, como una bombilla encendida. */
.ai-bulb-btn { transition: background .2s ease, box-shadow .2s ease, color .2s ease; }
.ai-bulb-btn[aria-expanded="true"] {
  color: #facc15;
  background: rgba(250,204,21,.16);
  box-shadow: inset 0 0 0 1.5px rgba(250,204,21,.55);
}
.ai-bulb-btn[aria-expanded="true"] svg path:last-child { fill: rgba(250,204,21,.35); }

/* Menú del foco: ahora es una ventana grande que sube de abajo (mismo
   patrón translate-y-full/opacity-0 que #brandFormPanel, #quotePanel,
   etc.), no el pequeño dropdown anclado al botón de antes — ver
   openChipMenu/closeChipMenu en ai.js. #chipMenuDragHandle se puede
   arrastrar hacia abajo para cerrarla (ver initChipMenuDrag). */
#chipMenuPanel { transition: transform .5s cubic-bezier(.16,1,.3,1), opacity .5s cubic-bezier(.16,1,.3,1); }
#chipMenuDragHandle { cursor: grab; touch-action: none; }
#chipMenuDragHandle:active { cursor: grabbing; }

/* Botón de la flecha (header): relleno sólido siempre visible (no
   transparente), no solo al pasar el mouse/tocar — más un círculo real
   que un simple contorno. Se hunde un poco al presionarlo, como
   confirmación de que el toque se registró. */
.ai-arrow-btn {
  background: rgba(255,255,255,.1);
  transition: transform .15s ease, background .2s ease;
}
.ai-arrow-btn:hover { background: rgba(255,255,255,.16); }
.ai-arrow-btn:active { transform: scale(.82); }

/* Nombre "Aison AI" (+ subtítulo): se guarda/oculta apenas hay scroll hacia
   abajo en el chat, y vuelve al llegar arriba del todo — ver
   initHeaderScroll en ai.js. Colapsa su alto (max-height + overflow:
   hidden) además de esfumarse, para no dejar un hueco reservado ahí
   arriba; va en su propio bloque (no en #headerTopRow, que además
   contiene el botón de cuenta con position:absolute) para no arrastrar ni
   recortar ese botón, que se queda fijo. */
.ai-header-name-block {
  overflow: hidden;
  max-height: 60px;
  transition: opacity .25s ease, transform .25s ease, max-height .3s ease;
}
.ai-header-name-block.ai-header-hidden {
  opacity: 0;
  transform: translateY(-8px);
  pointer-events: none;
  max-height: 0;
}

/* Pulso breve en la casilla al enviar un mensaje, como confirmación visual
   de que el mensaje salió. */
@keyframes aiComposerSent {
  0% {
    transform: translateY(0) scale(1);
    box-shadow: 0 0 0 0 rgba(255,255,255,.08), 0 0 0 0 rgba(255,255,255,.04);
  }
  35% {
    transform: translateY(-2px) scale(1.005);
    box-shadow: 0 14px 34px -18px rgba(255,255,255,.18), 0 0 0 10px rgba(255,255,255,.04);
  }
  100% {
    transform: translateY(0) scale(1);
    box-shadow: 0 0 0 0 rgba(255,255,255,0), 0 0 0 22px rgba(255,255,255,0);
  }
}

.ai-composer-sent { animation: aiComposerSent 1.28s cubic-bezier(.22,1,.36,1); }

.rail {
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;
  touch-action: pan-x pan-y;
  cursor: grab;
  scroll-snap-type: x mandatory;
}

.rail.dragging, #instaGrid.dragging, #avisosGrid.dragging { cursor: grabbing; scroll-snap-type: none; }
.rail.dragging *, #instaGrid.dragging *, #avisosGrid.dragging * { pointer-events: none; }
.rail.dragging, #instaGrid.dragging, #avisosGrid.dragging { user-select: none; -webkit-user-select: none; }

.stage-dark {
  background:
    radial-gradient(120% 90% at 50% -10%, rgba(255,255,255,0.10), transparent 55%),
    radial-gradient(80% 60% at 15% 0%, rgba(120,120,140,0.10), transparent 60%),
    #070708;
}

.stage-light {
  background:
    radial-gradient(120% 90% at 50% -10%, rgba(0,0,0,0.06), transparent 55%),
    #eceef2;
}

/* Fondo plano (sin el degradado gris/blanco de arriba): solo para Aison AI,
   la página principal conserva el degradado de .stage-dark/.stage-light. */
.stage-flat { background: #070708; }
html:not(.dark) .stage-flat { background: #eceef2; }

.card { scroll-snap-align: start; }

@media (prefers-reduced-motion: no-preference) {
  .fade-up { animation: fadeUp .6s cubic-bezier(.2,.7,.2,1) both; }

  @keyframes fadeUp {
    from { opacity: 0; transform: translateY(14px); }
    to { opacity: 1; transform: none; }
  }
}

@keyframes likePop {
  0% { transform: scale(1) rotate(0deg); }
  25% { transform: scale(1.8) rotate(-8deg); }
  45% { transform: scale(1.35) rotate(6deg); }
  65% { transform: scale(1.55) rotate(-3deg); }
  100% { transform: scale(1) rotate(0deg); }
}

.like-pop { animation: likePop .6s cubic-bezier(.2,.9,.25,1); }

@keyframes floatUp {
  from { opacity: 1; transform: translate(0, 0) scale(1); }
  to { opacity: 0; transform: translate(var(--dx, 0), -70px) scale(.3); }
}

.like-particle {
  position: absolute;
  left: 50%;
  top: 0;
  pointer-events: none;
  animation: floatUp .85s ease-out forwards;
}

@keyframes pulseCredit {
  0% { transform: scale(1); }
  40% { transform: scale(1.3); }
  100% { transform: scale(1); }
}

.pulse-credit {
  animation: pulseCredit .4s ease;
  display: inline-block;
}

/* Personaliza tu conversación (chatpersonalizado.html): catálogo con
   pestañas de categoría — sigue el modo claro/oscuro del resto de Aison AI
   (oscuro por defecto acá abajo, con los overrides de modo claro más
   adelante en el archivo). El fondo/header de la página los da .stage-flat
   (misma clase que avisos.html/publicidad.html), así que acá solo quedan los
   componentes propios del catálogo (pestañas, tarjetas, filas). */
.ai-store-tab {
  flex-shrink: 0;
  white-space: nowrap;
  font-size: .82rem;
  font-weight: 700;
  padding: .55rem 1.05rem;
  border-radius: 999px;
  background: rgba(255,255,255,.08);
  color: #fff;
  border: 1px solid rgba(255,255,255,.14);
  transition: background .2s ease, color .2s ease;
}

.ai-store-tab.is-active { background: #fff; color: #0a0a0b; border-color: #fff; }

/* Entrada animada de las pestañas y las tarjetas al abrir Personaliza tu conversación:
   cada una aparece con un pequeño desfase (--d) para que se sientan una
   detrás de otra en vez de aparecer todas de golpe. */
@keyframes aiStoreIn {
  from { opacity: 0; transform: translateY(14px); }
  to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: no-preference) {
  .ai-store-in {
    animation: aiStoreIn .5s cubic-bezier(.16,1,.3,1) both;
    animation-delay: var(--d, 0s);
  }
}

/* Tarjeta de colección: eyebrow + titular grande + miniatura arriba a la
   derecha (espacio pensado para reemplazarse por una foto/ilustración real
   más adelante sin tocar el resto de la tarjeta), y debajo la lista de
   personalidades de esa categoría. */
.ai-store-card {
  background: #1c1c1f;
  border-radius: 1.5rem;
  padding: 1.1rem 1.15rem .3rem;
  box-shadow: 0 1px 2px rgba(0,0,0,.2);
}

.ai-store-card__top { display: flex; align-items: flex-start; justify-content: space-between; gap: .75rem; }
.ai-store-card__eyebrow { font-size: .72rem; font-weight: 600; color: rgba(255,255,255,.45); }
.ai-store-card__headline { font-size: 1.3rem; font-weight: 800; line-height: 1.18; margin-top: .15rem; max-width: 14rem; color: #fff; }

.ai-store-card__thumb {
  flex-shrink: 0;
  width: 3.75rem;
  height: 3.75rem;
  border-radius: 1.1rem;
  display: grid;
  place-items: center;
  font-size: 1.7rem;
  line-height: 1;
}

.ai-store-row {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .85rem 0;
  border-top: 1px solid rgba(255,255,255,.08);
}

.ai-store-row--first { border-top: none; padding-top: .65rem; }

.ai-store-row__icon {
  flex-shrink: 0;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 999px;
  display: grid;
  place-items: center;
  font-size: 1.15rem;
  background: rgba(255,255,255,.06);
  border: 1px solid rgba(255,255,255,.12);
}

.ai-store-row__body { flex: 1; min-width: 0; }
.ai-store-row__name { font-weight: 700; font-size: .92rem; color: #fff; }
.ai-store-row__desc {
  font-size: .78rem;
  line-height: 1.3;
  color: rgba(255,255,255,.5);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.ai-store-row__cta {
  flex-shrink: 0;
  font-size: .8rem;
  font-weight: 700;
  color: #fff;
  padding: .5rem 1rem;
  border-radius: 999px;
  background: linear-gradient(135deg,#818cf8,#4f46e5);
  transition: transform .15s ease, filter .15s ease;
}

.ai-store-row__cta:hover { filter: brightness(1.08); transform: translateY(-1px); }
.ai-store-row__cta.is-open { filter: brightness(.92); }

.ai-store-lang-row {
  display: none;
  flex-wrap: wrap;
  gap: .4rem;
  padding: 0 0 .85rem 3.5rem;
  margin-top: -.5rem;
}

.ai-store-lang-row.is-open { display: flex; }

.ai-store-lang-chip {
  font-size: .7rem;
  font-weight: 600;
  padding: .35rem .6rem;
  border-radius: 999px;
  background: rgba(255,255,255,.08);
  border: 1px solid rgba(255,255,255,.14);
  color: #fff;
  transition: background .15s ease;
}

.ai-store-lang-chip:hover { background: rgba(255,255,255,.16); }

/* Modo claro: mismo diseño, colores invertidos. */
html:not(.dark) .ai-store-tab {
  background: #fff;
  color: #0a0a0b;
  border-color: rgba(0,0,0,.08);
  box-shadow: 0 1px 3px rgba(0,0,0,.05);
}
html:not(.dark) .ai-store-tab.is-active { background: #0a0a0b; color: #fff; border-color: #0a0a0b; }
html:not(.dark) .ai-store-card { background: #fff; box-shadow: 0 1px 2px rgba(0,0,0,.04); }
html:not(.dark) .ai-store-card__eyebrow { color: rgba(0,0,0,.42); }
html:not(.dark) .ai-store-card__headline { color: #0a0a0b; }
html:not(.dark) .ai-store-row { border-top-color: rgba(0,0,0,.06); }
html:not(.dark) .ai-store-row__icon { background: #fff; border-color: rgba(0,0,0,.08); }
html:not(.dark) .ai-store-row__name { color: #0a0a0b; }
html:not(.dark) .ai-store-row__desc { color: rgba(0,0,0,.5); }
html:not(.dark) .ai-store-lang-chip { background: #f2f2f5; border-color: rgba(0,0,0,.08); color: #0a0a0b; }
html:not(.dark) .ai-store-lang-chip:hover { background: #e7e7ea; }

.chip-menu-item {
  display: flex;
  align-items: center;
  gap: .9rem;
  width: 100%;
  text-align: left;
  font-weight: 600;
  font-size: 1.05rem;
  padding: 1rem 1.1rem;
  border-radius: 1rem;
  color: inherit;
  transition: background .15s ease;
}

/* Los íconos vienen con su propio h-4 w-4 (Tailwind) desde el HTML/JS que
   los arma — este selector les gana en especificidad (clase + tipo vs.
   clase sola) sin tener que tocar cada ícono uno por uno. */
.chip-menu-item svg { width: 22px; height: 22px; }

.chip-menu-item:hover { background: rgba(255,255,255,.08); }

.chip-menu-item[aria-pressed="true"] {
  background: #fff;
  color: #000;
}

/* Selector de imágenes de referencia (ver insertReferencePicker en ai.js):
   flota justo encima de la casilla (#refPicker en index.html), nunca
   dentro del chat — así siempre es el único que se ve, y desaparece apenas
   se elige una imagen o se cierra a mano. */
.ai-ref-picker {
  position: relative;
  background: #1c1c1f;
  border: 1px solid rgba(255,255,255,.1);
  border-radius: 22px;
  padding: .9rem 1rem .85rem;
  box-shadow: 0 18px 44px -14px rgba(0,0,0,.4);
  opacity: 0;
  transform: translateY(8px);
  transition: opacity .25s ease, transform .25s ease;
}
.ai-ref-picker.ai-ref-picker--in { opacity: 1; transform: translateY(0); }

.ai-ref-picker__close {
  position: absolute;
  top: .55rem;
  right: .55rem;
  height: 26px;
  width: 26px;
  display: grid;
  place-items: center;
  border-radius: 999px;
  color: rgba(255,255,255,.5);
  transition: background .15s ease, color .15s ease;
}
.ai-ref-picker__close:hover { background: rgba(255,255,255,.1); color: #fff; }

.ai-ref-picker__hint {
  font-size: 12.5px;
  font-weight: 700;
  line-height: 1.4;
  color: rgba(255,255,255,.7);
  margin: 0 1.6rem .65rem 0;
}
.ai-ref-picker__scroll {
  display: flex;
  gap: .65rem;
  overflow-x: auto;
  padding-bottom: .2rem;
}
/* Alto fijo, ancho libre: las imágenes vienen en varios tamaños (1080x1536,
   1080x1080...) — forzar también el ancho las recortaba (sobre todo las
   cuadradas, mucho más angostas que la caja vertical de antes). Con solo
   el alto fijo y el <img> con width:auto (ver abajo), cada miniatura
   conserva su propia proporción sin recortarse. */
.ai-ref-picker__item {
  flex: 0 0 auto;
  height: 224px;
  border-radius: 18px;
  overflow: hidden;
  padding: 0;
  border: 1.5px solid rgba(255,255,255,.14);
  cursor: pointer;
  transition: transform .15s ease, border-color .15s ease;
}
.ai-ref-picker__item img { height: 100%; width: auto; display: block; }
.ai-ref-picker__item:hover { transform: translateY(-2px); }

html:not(.dark) .ai-ref-picker { background: #fff; border-color: rgba(0,0,0,.08); box-shadow: 0 18px 44px -16px rgba(0,0,0,.2); }
html:not(.dark) .ai-ref-picker__hint { color: rgba(0,0,0,.6); }
html:not(.dark) .ai-ref-picker__item { border-color: rgba(0,0,0,.12); }
html:not(.dark) .ai-ref-picker__close { color: rgba(0,0,0,.4); }
html:not(.dark) .ai-ref-picker__close:hover { background: rgba(0,0,0,.06); color: #0a0a0b; }

html:not(.dark) .stage-dark {
  background:
    radial-gradient(120% 90% at 50% -10%, rgba(0,0,0,0.06), transparent 55%),
    #eceef2;
}

html:not(.dark) body { color: #0a0a0b; }
html:not(.dark) .chip-menu-item:hover { background: rgba(0,0,0,.05); }
html:not(.dark) header .ring-white\/15 { --tw-ring-color: rgba(0,0,0,.15); }
html:not(.dark) header .ai-arrow-btn { background: rgba(0,0,0,.06); }
html:not(.dark) header .ai-arrow-btn:hover { background: rgba(0,0,0,.1); }

#composer { background: #2b2b2e; color: #fff; transition: background .3s ease, color .3s ease, box-shadow .3s ease; }
#composer #prompt::placeholder { color: rgba(255,255,255,.45); }
#composer .chip-menu-item { color: #fff; }
#composer .chip-menu-item:hover { background: rgba(255,255,255,.08); }
#composer .chip-menu-item[aria-pressed="true"] { background: #fff; color: #000; }

/* Modo claro: la casilla de escribir queda blanca con una sombra tenue detrás;
   el modo oscuro no cambia. */
html:not(.dark) #composer {
  background: #fff;
  color: #0a0a0b;
  box-shadow: 0 12px 34px -14px rgba(0,0,0,.18);
}
html:not(.dark) #composer #prompt::placeholder { color: rgba(0,0,0,.4); }
html:not(.dark) #composer .chip-menu-item { color: #0a0a0b; }
html:not(.dark) #composer .chip-menu-item:hover { background: rgba(0,0,0,.05); }
html:not(.dark) #composer .chip-menu-item[aria-pressed="true"] { background: #0a0a0b; color: #fff; }
html:not(.dark) #chipMenuPanel {
  background: #fff !important;
  box-shadow: 0 16px 44px -12px rgba(0,0,0,.22);
}
html:not(.dark) #chipMenuDragHandle span { background: rgba(0,0,0,.15); }

/* Manual de Marca y otros paneles siguen el modo claro/oscuro del sitio
   (blanco en claro, negro en oscuro). */
html:not(.dark) #brandFormPanel,
html:not(.dark) #mockupFormPanel,
html:not(.dark) #chatSizePanel,
html:not(.dark) #accountPanel,
html:not(.dark) #voicePanel,
html:not(.dark) #articlePanel {
  background: #fff;
  color: #0a0a0b;
  --tw-ring-color: rgba(0,0,0,.1);
}

html:not(.dark) #articleContent { color: rgba(0,0,0,.6); }
html:not(.dark) #articleContent li::marker { color: rgba(0,0,0,.35); }
html:not(.dark) #articleDate { color: rgba(0,0,0,.4); }
html:not(.dark) #articleTitleBar { background: rgba(255,255,255,.9); }
html:not(.dark) #articleCtaText { color: #0a0a0b; }
html:not(.dark) #avisosSubtitle { color: rgba(0,0,0,.4); }
html:not(.dark) #articleAskForm,
html:not(.dark) #articleAskImageBtn { --tw-ring-color: rgba(0,0,0,.15); }
html:not(.dark) #articleAskInput { color: #0a0a0b; }
html:not(.dark) #articleAskInput::placeholder { color: rgba(0,0,0,.4); }
html:not(.dark) #brandFormPanel .text-white,
html:not(.dark) #mockupFormPanel .text-white,
html:not(.dark) #chatSizePanel .text-white,
html:not(.dark) #accountHeader .text-white { color: #0a0a0b; }
html:not(.dark) #brandFormPanel .text-white\/50,
html:not(.dark) #brandFormPanel .text-white\/60,
html:not(.dark) #brandFormPanel .text-white\/70,
html:not(.dark) #brandFormPanel .text-white\/85,
html:not(.dark) #mockupFormPanel .text-white\/50,
html:not(.dark) #mockupFormPanel .text-white\/60,
html:not(.dark) #mockupFormPanel .text-white\/70,
html:not(.dark) #mockupFormPanel .text-white\/85,
html:not(.dark) #voiceStatus { color: rgba(0,0,0,.5); }
html:not(.dark) #voiceTitle { color: rgba(0,0,0,.75); }
html:not(.dark) #voiceTimeLeft { color: rgba(0,0,0,.6); }
html:not(.dark) #accountHeader,
html:not(.dark) #brandFormPanel .border-white\/10,
html:not(.dark) #mockupFormPanel .border-white\/10 { border-color: rgba(0,0,0,.1); }
html:not(.dark) #brandFormPanel .ring-white\/15,
html:not(.dark) #mockupFormPanel .ring-white\/15,
html:not(.dark) #accountHeader .ring-white\/15,
html:not(.dark) #voiceModalClose,
html:not(.dark) #voicePlayBtn,
html:not(.dark) #voicePauseBtn,
html:not(.dark) #voiceTimeLeft { --tw-ring-color: rgba(0,0,0,.15); }
/* Por defecto (modo oscuro, sin html:not(.dark)) — antes esto vivía como
   style="" inline en cada input/textarea de index.html, y por especificidad
   le ganaba siempre a la regla html:not(.dark) de acá abajo (que ya estaba
   bien escrita): en modo claro quedaba texto blanco sobre fondo casi
   blanco, ilegible. Sacando el inline y poniendo la base acá, el modo
   claro por fin puede pisarla. */
#brandFormPanel input,
#brandFormPanel textarea,
#mockupFormPanel input,
#mockupFormPanel textarea {
  background: rgba(255,255,255,.05);
  color: #fff;
}
#brandFormPanel input::placeholder,
#brandFormPanel textarea::placeholder,
#mockupFormPanel input::placeholder,
#mockupFormPanel textarea::placeholder { color: rgba(255,255,255,.4); }

html:not(.dark) #brandFormPanel input,
html:not(.dark) #brandFormPanel textarea,
html:not(.dark) #mockupFormPanel input,
html:not(.dark) #mockupFormPanel textarea {
  background: rgba(0,0,0,.04);
  color: #0a0a0b;
  --tw-ring-color: rgba(0,0,0,.15);
}
html:not(.dark) #brandFormPanel input:focus,
html:not(.dark) #brandFormPanel textarea:focus,
html:not(.dark) #mockupFormPanel input:focus,
html:not(.dark) #mockupFormPanel textarea:focus { --tw-ring-color: rgba(0,0,0,.35); }
html:not(.dark) #brandFormPanel input::placeholder,
html:not(.dark) #brandFormPanel textarea::placeholder,
html:not(.dark) #mockupFormPanel input::placeholder,
html:not(.dark) #mockupFormPanel textarea::placeholder { color: rgba(0,0,0,.35); }
html:not(.dark) #brandFormPanel .border-white\/20,
html:not(.dark) #mockupFormPanel .border-white\/20 { border-color: rgba(0,0,0,.2); }
html:not(.dark) #brandFormPanel .border-t-white,
html:not(.dark) #mockupFormPanel .border-t-white { border-top-color: #0a0a0b; }

/* Visor "estilo iBook" del manual de marca terminado (ver initBrandBookViewer
   en ai.js) — una página a pantalla completa por vez, deslizable, con
   esquinas redondeadas y sombra (look de libro/tarjeta) y transición
   animada al pasar de página, para que se sienta como "pasar página". */
#brandBookTrack,
#mockupBookTrack {
  position: relative;
  height: 100%;
  transition: transform .45s cubic-bezier(.16,1,.3,1);
}
.brand-book-page {
  flex: 0 0 100%;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
}
.brand-book-page img {
  max-height: 100%;
  max-width: 100%;
  border-radius: 18px;
  box-shadow: 0 24px 60px -20px rgba(0,0,0,.5);
  object-fit: contain;
}
.brand-book-dot {
  height: 6px;
  width: 6px;
  border-radius: 999px;
  background: rgba(255,255,255,.25);
  transition: width .25s ease, background .25s ease;
}
.brand-book-dot.is-active { width: 18px; background: #fff; }
html:not(.dark) .brand-book-dot { background: rgba(0,0,0,.2); }
html:not(.dark) .brand-book-dot.is-active { background: #0a0a0b; }

/* Ventana de cuenta: el resto de #accountPanel ya cambia a blanco con la
   regla de arriba; acá solo se ajustan los textos y anillos concretos de
   su contenido (el avatar se deja siempre blanco sobre su degradado). */
html:not(.dark) #accountNameText,
html:not(.dark) #accountChatCredits { color: #0a0a0b; }
html:not(.dark) #accountEmailText,
html:not(.dark) #accountCreditsCard span:first-child { color: rgba(0,0,0,.5); }
html:not(.dark) #accountCreditsCard { --tw-ring-color: rgba(0,0,0,.1); }
html:not(.dark) #themeToggle,
html:not(.dark) #openThemeModal,
html:not(.dark) #manageSubscriptionBtn,
html:not(.dark) #dynamicOrbBtn,
html:not(.dark) #historyBtn,
html:not(.dark) #logoutBtn,
html:not(.dark) #studioLinkBtn {
  color: #0a0a0b;
  --tw-ring-color: rgba(0,0,0,.12);
}
html:not(.dark) #themeToggle:hover,
html:not(.dark) #openThemeModal:hover,
html:not(.dark) #manageSubscriptionBtn:hover,
html:not(.dark) #dynamicOrbBtn:hover,
html:not(.dark) #historyBtn:hover,
html:not(.dark) #logoutBtn:hover,
html:not(.dark) #studioLinkBtn:hover { background: rgba(0,0,0,.05); }
.quote-field {
  background: #2b2b2e;
  color: #fff;
  -webkit-text-fill-color: #fff;
  -webkit-appearance: none;
  appearance: none;
  border: 1px solid rgba(255,255,255,.12);
}

.quote-field::placeholder { color: rgba(255,255,255,.4); }

.quote-field:focus {
  border-color: rgba(245,158,11,.6);
  box-shadow: 0 0 0 3px rgba(245,158,11,.18);
}

select.quote-field { color-scheme: dark; }

.quoteCheckGlow {
  background: radial-gradient(circle, rgba(245,158,11,.45), transparent 70%);
  animation: quoteGlowPulse 1.8s ease-in-out infinite;
}

@keyframes quoteGlowPulse {
  0%, 100% { opacity: .55; transform: scale(.9); }
  50% { opacity: 1; transform: scale(1.08); }
}

.quoteCheckCircle {
  stroke-dasharray: 252;
  stroke-dashoffset: 252;
  transform-origin: center;
  animation: quoteCircleDraw .7s cubic-bezier(.65,0,.45,1) forwards, quoteCirclePop .5s .7s cubic-bezier(.34,1.56,.64,1) both;
}

.quoteCheckMark {
  stroke-dasharray: 60;
  stroke-dashoffset: 60;
  animation: quoteMarkDraw .4s .6s cubic-bezier(.65,0,.45,1) forwards;
}

@keyframes quoteCircleDraw { to { stroke-dashoffset: 0; } }
@keyframes quoteMarkDraw { to { stroke-dashoffset: 0; } }
@keyframes quoteCirclePop {
  0% { transform: scale(1); }
  50% { transform: scale(1.12); }
  100% { transform: scale(1); }
}

.quoteSuccessText {
  opacity: 0;
  animation: quoteTextIn .5s ease forwards;
  animation-delay: var(--quote-text-delay, .85s);
}

@keyframes quoteTextIn {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: none; }
}

.chat-message {
  display: flex;
  width: 100%;
}

.chat-message--assistant {
  justify-content: flex-start;
}

.chat-message--user {
  justify-content: flex-end;
}

.chat-bubble {
  max-width: min(85%, 620px);
  padding: .9rem 1rem;
  border-radius: 1.25rem;
  line-height: 1.4;
  font-size: .95rem;
  box-shadow: 0 10px 30px rgba(0,0,0,.14);
}

@media (prefers-reduced-motion: no-preference) {
  .chat-message {
    animation: chatMessageIn .28s cubic-bezier(.16,1,.3,1) both;
  }

  .chat-message--assistant .chat-bubble {
    transform-origin: left bottom;
  }

  .chat-message--user .chat-bubble {
    transform-origin: right bottom;
  }
}

@keyframes chatMessageIn {
  from {
    opacity: 0;
    transform: translateY(10px) scale(.98);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.chat-bubble--assistant {
  background: none;
  color: #fff;
  border: none;
  box-shadow: none;
  padding-left: 0;
  padding-right: 0;
  max-width: 100%;
}

.chat-bubble--user {
  background: #26262b;
  color: #fff;
  border-bottom-right-radius: .55rem;
}

html:not(.dark) .chat-bubble--assistant { color: #0a0a0b; }

html:not(.dark) .chat-bubble--user {
  background: #ffffff;
  color: #0a0a0b;
}

/* ===== Aison AI: tarjeta de código (```html …```) con ejecutar/descargar ===== */
.ai-code-card {
  margin: .5rem 0;
  border-radius: 14px;
  overflow: hidden;
  background: #0b0b0d;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.1);
}

.ai-code-card__header {
  display: flex;
  align-items: center;
  gap: .6rem;
  padding: .55rem .75rem;
  background: rgba(255,255,255,.04);
  border-bottom: 1px solid rgba(255,255,255,.08);
}

/* Tres puntos tipo ventana de editor (macOS), solo decorativos. */
.ai-code-card__dots { display: flex; gap: 5px; flex-shrink: 0; }
.ai-code-card__dots i {
  display: block;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: rgba(255,255,255,.18);
}
.ai-code-card__dots i:nth-child(1) { background: #ff5f57; }
.ai-code-card__dots i:nth-child(2) { background: #febc2e; }
.ai-code-card__dots i:nth-child(3) { background: #28c840; }

.ai-code-card__lang {
  font-size: 11.5px;
  font-weight: 600;
  color: rgba(255,255,255,.55);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

.ai-code-card__actions { display: flex; gap: .4rem; margin-left: auto; }

.ai-code-card__btn {
  font-size: 11px;
  font-weight: 600;
  color: #fff;
  background: rgba(255,255,255,.08);
  border: 1px solid rgba(255,255,255,.14);
  border-radius: 999px;
  padding: .3rem .65rem;
  transition: background .2s ease;
}

.ai-code-card__btn:hover { background: rgba(255,255,255,.16); }

.ai-code-card__pre {
  margin: 0;
  padding: .5rem 0;
  max-height: 320px;
  overflow: auto;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12.5px;
  line-height: 1.6;
}

.ai-code-card__row { display: flex; }

.ai-code-card__lineno {
  flex-shrink: 0;
  width: 2.4rem;
  text-align: right;
  padding-right: .75rem;
  color: rgba(255,255,255,.25);
  user-select: none;
}

.ai-code-card__linecode {
  flex: 1;
  padding-right: .9rem;
  color: #e5e7eb;
  white-space: pre-wrap;
  word-break: break-word;
}

.ai-code-tok-tag { color: #7dd3fc; }
.ai-code-tok-string { color: #fbbf24; }
.ai-code-tok-comment { color: #6b7280; font-style: italic; }

.ai-code-card__preview {
  display: block;
  width: 100%;
  height: 340px;
  border: 0;
  background: #fff;
}

html:not(.dark) .ai-code-card { background: #f4f4f6; box-shadow: inset 0 0 0 1px rgba(0,0,0,.08); }
html:not(.dark) .ai-code-card__header { background: rgba(0,0,0,.03); border-bottom-color: rgba(0,0,0,.08); }
html:not(.dark) .ai-code-card__lang { color: rgba(0,0,0,.55); }
html:not(.dark) .ai-code-card__lineno { color: rgba(0,0,0,.28); }
html:not(.dark) .ai-code-card__linecode { color: #1a1a1c; }
html:not(.dark) .ai-code-tok-tag { color: #0369a1; }
html:not(.dark) .ai-code-tok-string { color: #b45309; }
html:not(.dark) .ai-code-tok-comment { color: #9ca3af; }
html:not(.dark) .ai-code-card__btn { color: #0a0a0b; background: rgba(0,0,0,.06); border-color: rgba(0,0,0,.12); }
html:not(.dark) .ai-code-card__btn:hover { background: rgba(0,0,0,.1); }

.ai-justify { text-align: justify; text-justify: inter-word; }

/* ===== Aison AI: chat de texto ===== */

/* Prioridad para lo nuevo: al llegar una pregunta+respuesta nueva, la anterior
   pierde relevancia (se difumina, se encoge un poco y se atenúa) a los 3s; un
   clic encima la trae de vuelta con un "rebote" elegante. El bezier con
   overshoot (1.56) es lo que da el efecto de resorte al restaurarla. */
.exchange {
  padding: .75rem 0;
  transform-origin: top center;
  transition: opacity .7s cubic-bezier(.4,0,.2,1), transform .55s cubic-bezier(.34,1.56,.64,1), filter .7s ease;
}

.exchange--dimmed {
  opacity: .45;
  transform: scale(.96) translateY(-3px);
  filter: blur(.6px) saturate(.7);
  cursor: pointer;
}

.exchange--dimmed:hover {
  opacity: .8;
  transform: scale(.98) translateY(-1px);
  filter: blur(0) saturate(1);
}

@keyframes aiMsgIn {
  from { opacity: 0; transform: translateY(14px) scale(.97); }
  to { opacity: 1; transform: none; }
}

.ai-msg-in { animation: aiMsgIn 1.12s cubic-bezier(.22,1,.36,1) both; }

@keyframes aiAssistantMsgIn {
  0% {
    opacity: 0;
    transform: translateY(18px) translateX(-8px) scale(.982);
  }
  58% {
    opacity: 1;
    transform: translateY(-1px) translateX(0) scale(1.006);
  }
  100% {
    opacity: 1;
    transform: none;
  }
}

.chat-message--assistant.ai-msg-in {
  transform-origin: left bottom;
  animation: aiAssistantMsgIn 1.38s cubic-bezier(.22,1,.36,1) both;
}

@keyframes aiUserMsgIn {
  0% {
    opacity: 0;
    transform: translateY(18px) translateX(10px) scale(.985);
  }
  55% {
    opacity: 1;
    transform: translateY(-1px) translateX(0) scale(1.01);
  }
  100% {
    opacity: 1;
    transform: none;
  }
}

.chat-message--user.ai-msg-in {
  transform-origin: right bottom;
  animation: aiUserMsgIn 1.72s cubic-bezier(.22,1,.36,1) both;
}

/* Palabra apareciendo "recién escrita": arranca en el color de acento del
   tema (--ai-word-flash) y termina en el color normal del texto
   (--ai-word-final). El efecto vive solo durante la entrada; al final la
   respuesta queda en un color sólido para que no se mezcle azul/blanco,
   amarillo/blanco, etc. */
@keyframes aiWordIn {
  0% {
    opacity: 0;
    filter: blur(3px) saturate(1.15) brightness(1.12);
    transform: translateY(7px) scale(.985);
    color: var(--ai-word-flash);
    text-shadow: 0 0 14px var(--ai-response-shadow);
  }
  48% {
    opacity: 1;
    filter: blur(0) saturate(1.04) brightness(1.04);
    transform: translateY(0) scale(1.01);
    color: var(--ai-word-flash);
    text-shadow: 0 0 10px var(--ai-response-shadow);
  }
  100% {
    opacity: 1;
    filter: blur(0) saturate(1) brightness(1);
    transform: none;
    color: var(--ai-word-final);
    text-shadow: 0 0 0 transparent;
  }
}

.ai-response-text {
  color: var(--ai-word-final);
  -webkit-text-fill-color: currentColor;
  text-shadow: none;
}

.ai-word {
  display: inline-block;
  opacity: 0;
  color: var(--ai-word-final);
  -webkit-text-fill-color: currentColor;
  will-change: transform, filter, opacity, color, text-shadow;
  animation: aiWordIn .96s cubic-bezier(.22,1,.36,1) forwards;
}

@keyframes aiDotBounce {
  0%, 60%, 100% { transform: translateY(0); opacity: .4; }
  30% { transform: translateY(-5px); opacity: 1; }
}

.ai-typing-dot {
  display: inline-block;
  width: 7px;
  height: 7px;
  border-radius: 999px;
  background: currentColor;
  animation: aiDotBounce 1.1s ease-in-out infinite;
}

.ai-typing-dot:nth-child(2) { animation-delay: .15s; }
.ai-typing-dot:nth-child(3) { animation-delay: .3s; }

@keyframes aiAvatarGlow {
  0% { box-shadow: 0 0 0 0 rgba(245,158,11,.5), 0 0 0 0 rgba(245,158,11,.25); }
  60% { box-shadow: 0 0 0 14px rgba(245,158,11,0), 0 0 0 26px rgba(245,158,11,0); }
  100% { box-shadow: 0 0 0 14px rgba(245,158,11,0), 0 0 0 26px rgba(245,158,11,0); }
}

.ai-avatar-pulse { animation: aiAvatarGlow 3.2s cubic-bezier(.4,0,.2,1) infinite; }

@keyframes aiHeroIn {
  from { opacity: 0; transform: translateY(18px) scale(.95); }
  to { opacity: 1; transform: none; }
}

.ai-hero-logo { animation: aiHeroIn 1.02s cubic-bezier(.16,1,.3,1) both; }

.ai-hero-title {
  animation: aiHeroIn 1.08s .18s cubic-bezier(.16,1,.3,1) both, aiHeroShimmer 13s 1.2s ease-in-out infinite;
  background: linear-gradient(90deg, #fff 0%, #fde68a 25%, #fff 50%, #fde68a 75%, #fff 100%);
  background-size: 220% auto;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

html:not(.dark) .ai-hero-title {
  background: linear-gradient(90deg, #0a0a0b 0%, #f59e0b 25%, #0a0a0b 50%, #f59e0b 75%, #0a0a0b 100%);
  background-size: 220% auto;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* "Buenos días / Buenas tardes / Buenas noches": en modo claro el blanco
   translúcido queda casi invisible sobre el fondo claro, así que se fuerza
   negro (el tamaño ya lo da la clase de Tailwind en el HTML). */
html:not(.dark) #heroGreeting {
  color: #0a0a0b;
  opacity: .8;
}

html:not(.dark) #heroSubtitle {
  color: #0a0a0b;
  opacity: .65;
}

@keyframes aiHeroShimmer {
  0% { background-position: 200% center; }
  100% { background-position: -200% center; }
}

@keyframes aiImageReveal {
  from { opacity: 0; transform: scale(.92); filter: blur(6px); }
  to { opacity: 1; transform: none; filter: blur(0); }
}

.ai-image-reveal { animation: aiImageReveal .6s cubic-bezier(.16,1,.3,1) both; }

/* Caja de "generando imagen": solo dos tonos (negro y gris oscuro) que se
   mueven despacio de fondo, sin ícono — el texto de abajo (ver
   showImageGeneratingPlaceholder en ai.js) va contando en qué paso va,
   para que la espera se sienta acompañada sin distraer con colores. */
.ai-gen-loading {
  position: relative;
  overflow: hidden;
  display: grid;
  place-items: center;
  gap: .6rem;
  isolation: isolate;
  background:
    radial-gradient(130% 110% at 18% 14%, rgba(255,255,255,.12), transparent 34%),
    radial-gradient(95% 80% at 82% 22%, rgba(255,255,255,.07), transparent 42%),
    linear-gradient(135deg, #020202 0%, #121212 22%, #2d2d2d 48%, #151515 72%, #030303 100%);
  background-size: 140% 140%, 160% 160%, 260% 260%;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.05), inset 0 -18px 32px rgba(0,0,0,.22);
  animation: aiGenLoadingShift 8.5s cubic-bezier(.4,0,.2,1) infinite, aiImageReveal .7s cubic-bezier(.16,1,.3,1) both;
}

.ai-gen-loading::before {
  content: '';
  position: absolute;
  inset: -14%;
  background:
    radial-gradient(52% 46% at 22% 30%, rgba(255,255,255,.12), transparent 66%),
    radial-gradient(44% 40% at 78% 68%, rgba(255,255,255,.08), transparent 72%);
  mix-blend-mode: screen;
  opacity: .78;
  animation: aiGenGlowFloat 9s ease-in-out infinite alternate;
  pointer-events: none;
  z-index: 0;
}

.ai-gen-loading::after {
  content: '';
  position: absolute;
  inset: 0;
  background:
    linear-gradient(112deg, transparent 26%, rgba(255,255,255,.03) 38%, rgba(255,255,255,.16) 50%, rgba(255,255,255,.05) 60%, transparent 74%);
  background-size: 230% 100%;
  animation: aiGenShimmer 3.8s cubic-bezier(.4,0,.2,1) infinite;
  pointer-events: none;
  z-index: 0;
}

@keyframes aiGenLoadingShift {
  0% { background-position: 0% 0%, 100% 20%, 0% 50%; }
  50% { background-position: 100% 20%, 0% 80%, 100% 50%; }
  100% { background-position: 0% 0%, 100% 20%, 0% 50%; }
}

@keyframes aiGenGlowFloat {
  0% {
    transform: translate3d(-2%, -1%, 0) scale(1);
    opacity: .52;
  }
  50% {
    transform: translate3d(1.5%, 2%, 0) scale(1.04);
    opacity: .82;
  }
  100% {
    transform: translate3d(3%, -2%, 0) scale(1.02);
    opacity: .6;
  }
}

@keyframes aiGenShimmer {
  0% { background-position: 210% 0%; }
  100% { background-position: -70% 0%; }
}

.ai-gen-loading-caption {
  position: relative;
  z-index: 1;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .03em;
  color: rgba(255,255,255,.94);
  text-shadow: 0 1px 14px rgba(255,255,255,.12);
  animation: aiGenCaptionPulse 2.4s cubic-bezier(.4,0,.2,1) infinite;
}

@keyframes aiGenCaptionPulse {
  0%, 100% {
    opacity: .62;
    transform: translateY(0);
  }
  50% {
    opacity: 1;
    transform: translateY(-1px);
  }
}

.ai-action-btn { transition: transform .15s ease, color .15s ease, background .15s ease; }
.ai-action-btn:active { transform: scale(.88); }
.ai-action-btn.active { color: var(--ai-word-flash); }
.ai-action-btn:disabled { opacity: .6; cursor: wait; pointer-events: none; }

/* En modo claro los íconos venían en blanco (invisibles sobre fondo claro);
   selector con más especificidad que la utilidad de Tailwind para ganarle. */
html:not(.dark) .ai-action-btn:not(.active) { color: rgba(10,10,11,.55); }
html:not(.dark) .ai-action-btn:not(.active):hover { color: #0a0a0b; }

/* Botón "Escuchar con el orbe" (ver actionsRow en ai.js): un punto
   totalmente relleno (no un anillo hueco) con un degradado que se mueve
   solo — mismo truco que .voice-orb (background-size grande + animar
   background-position), así se ve "vivo" incluso sin tocarlo. Igual en
   los dos temas, no depende de currentColor. Negro con grises (mismo
   lenguaje de color que el orbe de voz), no colores. */
.ai-read-aloud-dot {
  display: block;
  border-radius: 999px;
  background-image: linear-gradient(135deg, #000000, #3c3c3c, #9a9a9a, #d9d9d9, #3c3c3c, #000000);
  background-size: 300% 300%;
  animation: aiReadAloudMove 6s ease-in-out infinite;
}
@keyframes aiReadAloudMove {
  0% { background-position: 0% 50%; }
  50% { background-position: 100% 50%; }
  100% { background-position: 0% 50%; }
}
@media (prefers-reduced-motion: reduce) {
  .ai-read-aloud-dot { animation: none; }
}

/* Me gusta / No me gusta: efecto propio (no el rebote genérico de los
   demás botones de acción) — un salto con resplandor en el color de acento
   del tema (--ai-word-flash, el mismo "dorado/morado" del efecto de
   escritura), para que se sienta distinto a copiar/compartir/escuchar. */
@keyframes aiActionPop {
  0% { transform: scale(1); filter: drop-shadow(0 0 0 transparent); }
  40% { transform: scale(1.4); filter: drop-shadow(0 0 7px var(--ai-word-flash)); }
  100% { transform: scale(1); filter: drop-shadow(0 0 0 transparent); }
}

.ai-action-pop { animation: aiActionPop .45s cubic-bezier(.34,1.56,.64,1); }

@keyframes aiSendPulse {
  0% {
    transform: translateY(0) scale(1) rotate(0deg);
    opacity: 1;
  }
  30% {
    transform: translateY(-4px) scale(.92) rotate(-7deg);
    opacity: .88;
  }
  68% {
    transform: translateY(1px) scale(1.04) rotate(2deg);
    opacity: 1;
  }
  100% {
    transform: translateY(0) scale(1) rotate(0deg);
    opacity: 1;
  }
}

.ai-send-pop { animation: aiSendPulse .82s cubic-bezier(.22,1,.36,1); }

/* Micrófono de dictado en la casilla: mientras escucha, un pulso negro
   sutil avisa que está grabando (antes era rojo). */
@keyframes micListeningPulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(10,10,11,.4); }
  50% { box-shadow: 0 0 0 8px rgba(10,10,11,0); }
}
#micBtn.ai-mic-listening {
  background: #0a0a0b;
  color: #fff;
  border-radius: 999px;
  animation: micListeningPulse 1.4s ease-in-out infinite;
}

.brandRefCard {
  outline: 2px solid transparent;
  outline-offset: 2px;
  transition: outline-color .15s ease;
  background: rgba(255,255,255,.05);
}

.brandRefCard.active { outline-color: #fff; }

/* ===== Onboarding (primera visita) =====
   Overlay de bienvenida a pantalla completa, se ve una sola vez por
   navegador (el flag aisonOnboardingSeen en localStorage lo controla, ver
   el script inline al inicio de <head> en index.html y initOnboarding en
   ai.js). #onboarding YA es fixed/inset-0 por clases de Tailwind en el
   propio HTML — a propósito no se pisa esa posición acá con ninguna regla
   `position`, porque hacerlo (p. ej. position: relative) colapsa el
   overlay a la altura de su contenido en vez de cubrir toda la pantalla. */
#onboarding {
  padding-top: 2rem;
  /* Fondo/texto oscuros SIEMPRE (a propósito no sigue el tema claro/oscuro
     del resto del sitio, que por defecto es claro con texto oscuro — sin
     este color explícito, .onboard-title hereda ese texto oscuro y queda
     invisible sobre este fondo). */
  color: #fff;
  background:
    radial-gradient(60% 45% at 15% 8%, rgba(250,204,21,.22), transparent 60%),
    radial-gradient(55% 40% at 85% 92%, rgba(234,179,8,.2), transparent 60%),
    #070708;
}

html.onboarding-seen #onboarding { display: none; }

@keyframes onboardSkipPulse { 0%, 100% { opacity: .65; } 50% { opacity: 1; } }

.onboard-skip {
  position: absolute;
  top: 1.1rem;
  right: 1.1rem;
  z-index: 20;
  font-size: .82rem;
  font-weight: 600;
  color: rgba(255,255,255,.55);
  padding: .5rem .9rem;
  border-radius: 999px;
  background: rgba(255,255,255,.06);
  border: 1px solid rgba(255,255,255,.1);
  transition: color .15s ease, background .15s ease, transform .15s ease;
  animation: onboardSkipPulse 3.2s ease-in-out infinite;
}
.onboard-skip:hover { color: #070708; background: #facc15; transform: translateY(-1px); animation-play-state: paused; opacity: 1; }

.onboard-track {
  flex: 1;
  display: flex;
  width: 500%;
  height: 100%;
  transition: transform .45s cubic-bezier(.65,0,.35,1);
}

.onboard-slide {
  width: 20%;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 1.5rem 1.75rem 2rem;
  flex-shrink: 0;
}

.onboard-badge {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: #fde68a;
  background: rgba(250,204,21,.14);
  border: 1px solid rgba(250,204,21,.35);
  padding: .35rem .75rem;
  border-radius: 999px;
  margin-bottom: 1.4rem;
}

@keyframes onboardFloat { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-10px); } }
@keyframes onboardGlow {
  0%, 100% { box-shadow: 0 20px 45px -20px rgba(234,179,8,.5); }
  50% { box-shadow: 0 26px 55px -14px rgba(234,179,8,.85); }
}

.onboard-icon-wrap {
  width: 108px;
  height: 108px;
  border-radius: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 1.8rem;
  background: linear-gradient(135deg, rgba(250,204,21,.22), rgba(234,179,8,.12));
  border: 1px solid rgba(250,204,21,.3);
  animation: onboardFloat 3.6s ease-in-out infinite, onboardGlow 3.6s ease-in-out infinite;
}
.onboard-icon-wrap svg { width: 50px; height: 50px; }

.onboard-title {
  font-size: 1.6rem;
  font-weight: 800;
  line-height: 1.25;
  margin-bottom: .75rem;
  max-width: 22rem;
}

.onboard-text {
  font-size: .95rem;
  line-height: 1.55;
  color: rgba(255,255,255,.62);
  max-width: 24rem;
}

.onboard-text b { color: rgba(255,255,255,.88); font-weight: 700; }

.onboard-logo {
  width: 132px;
  height: 132px;
  border-radius: 32px;
  margin-bottom: 1.8rem;
  animation: onboardFloat 3.6s ease-in-out infinite, onboardGlow 3.6s ease-in-out infinite;
}

.onboard-footer {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0 1.5rem calc(env(safe-area-inset-bottom) + 1.5rem);
}

.onboard-dots { display: flex; gap: .4rem; }

.onboard-dot {
  width: 7px;
  height: 7px;
  border-radius: 999px;
  background: rgba(255,255,255,.2);
  transition: width .25s ease, background .25s ease;
}

@keyframes onboardDotPulse { 0%, 100% { opacity: 1; } 50% { opacity: .55; } }
.onboard-dot.is-active {
  width: 22px;
  background: linear-gradient(135deg,#fde047,#eab308);
  animation: onboardDotPulse 1.8s ease-in-out infinite;
}

@keyframes onboardBtnGlow {
  0%, 100% { box-shadow: 0 8px 20px -10px rgba(250,204,21,0); }
  50% { box-shadow: 0 12px 28px -8px rgba(250,204,21,.65); }
}

.onboard-next {
  font-family: 'Archivo', 'Inter', sans-serif;
  font-weight: 700;
  font-size: .92rem;
  color: #070708;
  background: #fff;
  padding: .8rem 1.6rem;
  border-radius: 999px;
  border: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: .45rem;
  transition: transform .15s ease, filter .15s ease;
  animation: onboardBtnGlow 2.4s ease-in-out infinite;
}
.onboard-next:hover { filter: brightness(.94); transform: translateY(-2px) scale(1.03); }
.onboard-next:active { transform: translateY(0) scale(.98); }
.onboard-next svg { width: 16px; height: 16px; transition: transform .2s ease; }
.onboard-next:hover svg { transform: translateX(3px); }

.onboard-next.is-final {
  background: linear-gradient(135deg,#fde047,#eab308);
  color: #070708;
}

@media (min-width: 640px) {
  .onboard-title { font-size: 1.9rem; }
  .onboard-icon-wrap { width: 124px; height: 124px; }
  .onboard-logo { width: 160px; height: 160px; }
}

/* ===== Aison AI: orbe del chat de voz =====
   Blanco sobre fondo oscuro, negro sobre fondo claro — siempre lo opuesto
   a la página, para que resalte igual en los dos temas. Escuchar/pensar/
   hablar cada uno tiene su propio movimiento fijo (no depende de leer el
   volumen real del micrófono — esa segunda captura de audio se quitó
   porque interfería con que el reconocimiento de voz escuchara bien). */
.voice-orb-btn {
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.voice-orb {
  display: block;
  height: 12.5rem;
  width: 12.5rem;
  border-radius: 999px;
  background: radial-gradient(circle at 32% 26%, #ffffff, #e4e4e4 55%, #b7b7b7 100%);
  background-size: 220% 220%;
  box-shadow:
    0 0 32px 6px rgba(255,255,255,.3),
    0 0 90px 18px rgba(255,255,255,.1);
  transform: scale(1);
  transition: transform .3s cubic-bezier(.16,1,.3,1), box-shadow .3s ease;
  /* Mismos colores de siempre — lo único que se anima acá es la posición
     del degradado dentro de la esfera, para que se vea "vivo" incluso
     quieto. Los estados de escuchar/pensar/hablar suman su propia
     animación de escala/sombra encima de esta (ver más abajo). */
  animation: voiceOrbColorMove 9s ease-in-out infinite;
}

html:not(.dark) .voice-orb {
  background: radial-gradient(circle at 32% 26%, #3c3c3c, #161616 55%, #000000 100%);
  background-size: 220% 220%;
  box-shadow:
    0 0 32px 6px rgba(0,0,0,.22),
    0 0 90px 18px rgba(0,0,0,.09);
}

@keyframes voiceOrbColorMove {
  0%, 100% { background-position: 20% 15%; }
  50% { background-position: 80% 85%; }
}

.voice-orb-btn:hover .voice-orb { filter: brightness(1.04); }
.voice-orb-btn:active .voice-orb { transform: scale(.96); }
.voice-orb-btn:disabled { cursor: not-allowed; }
.voice-orb-btn:disabled .voice-orb { opacity: .35; filter: none; }

@keyframes voiceOrbListening {
  0%, 100% { transform: scale(1); box-shadow: 0 0 32px 6px rgba(255,255,255,.3), 0 0 90px 18px rgba(255,255,255,.1); }
  50% { transform: scale(1.07); box-shadow: 0 0 52px 10px rgba(255,255,255,.42), 0 0 110px 26px rgba(255,255,255,.16); }
}
.voice-orb.is-listening { animation: voiceOrbListening 1.6s ease-in-out infinite, voiceOrbColorMove 9s ease-in-out infinite; }
html:not(.dark) .voice-orb.is-listening { animation-name: voiceOrbListeningLight, voiceOrbColorMove; }

@keyframes voiceOrbListeningLight {
  0%, 100% { transform: scale(1); box-shadow: 0 0 32px 6px rgba(0,0,0,.22), 0 0 90px 18px rgba(0,0,0,.09); }
  50% { transform: scale(1.07); box-shadow: 0 0 52px 10px rgba(0,0,0,.3), 0 0 110px 26px rgba(0,0,0,.13); }
}

@keyframes voiceOrbThinking {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.055); }
}
.voice-orb.is-thinking { animation: voiceOrbThinking 1.7s ease-in-out infinite, voiceOrbColorMove 9s ease-in-out infinite; }

@keyframes voiceOrbSpeaking {
  0%, 100% { transform: scale(1); }
  30% { transform: scale(1.09); }
  55% { transform: scale(1.01); }
  80% { transform: scale(1.12); }
}
.voice-orb.is-speaking { animation: voiceOrbSpeaking 1s ease-in-out infinite, voiceOrbColorMove 9s ease-in-out infinite; }

@media (prefers-reduced-motion: reduce) {
  .voice-orb,
  .voice-orb.is-listening, .voice-orb.is-thinking, .voice-orb.is-speaking { animation: none; }
}

/* ===== Voz/orbe: OCULTO por ahora =====
   El navegador no está leyendo bien y no hay saldo de ElevenLabs por el
   momento — se esconden los disparadores y la ventana (nunca se borra el
   código de ai.js, sigue completo por si se reactiva más adelante). Quitar
   este bloque para volver a mostrarlo todo. */
#voiceOpenBtn,
#dynamicOrbBtn,
#chatOrbWidget {
  display: none;
}
/* button.readAloudBtn (no solo .readAloudBtn): el botón también trae la
   utilidad .grid de Tailwind (display:grid) con la misma especificidad —
   sin el selector de elemento acá, cuál de las dos gana depende del orden
   de carga y por eso a veces el círculo se seguía viendo. */
button.readAloudBtn {
  display: none;
}

/* ===== Orbe dinámico (superpuesto en la esquina de la casilla) =====
   Mismo .voice-orb de siempre, un poco más grande — el sistema de estados
   (is-listening/is-thinking/is-speaking) no se toca, se reutiliza tal
   cual (ver openChatOrbWidget/setOrbStatus en ai.js). Sin caja/fondo
   propio: el "flote" lo da el drop-shadow sobre el propio orbe. El
   arrastre mueve el botón con transform (nunca sale del flujo normal) y
   siempre vuelve a este mismo lugar al soltarlo — nunca se queda donde se
   dejó (ver ai.js). */
.voice-orb--sm {
  height: 4.5rem;
  width: 4.5rem;
  filter: drop-shadow(0 8px 20px rgba(0,0,0,.35));
}

/* Posición de descanso: pegado a la esquina derecha, por ENCIMA de la
   casilla (nunca sobre ella). Cuando hay un scroll de referencias o de
   sugerencias abierto, positionChatOrb() en ai.js suma la altura de ese
   scroll acá mismo (style.bottom inline) para que el orbe quede también
   por encima de él — al cerrarse ese scroll, se saca el inline y vuelve
   a este valor por defecto.
   Entrada "materializándose": desenfocado y chico, se enfoca y crece a
   la vez que aparece — mismo lenguaje que ya usa .ai-image-reveal en el
   resto del chat (ease-out parejo, sin rebote), para que se sienta
   prolijo y no un simple parpadeo. Al cerrarse hace el camino inverso
   (misma transición, en reversa) — no es un fade brusco. */
#chatOrbWidget {
  bottom: calc(100% + .75rem);
  opacity: 0;
  transform: scale(.5) translateY(10px);
  filter: blur(8px);
  transition: opacity .45s cubic-bezier(.16,1,.3,1), transform .45s cubic-bezier(.16,1,.3,1), filter .45s cubic-bezier(.16,1,.3,1), bottom .35s cubic-bezier(.16,1,.3,1);
}
#chatOrbWidget.ai-chat-orb-in {
  opacity: 1;
  transform: scale(1) translateY(0);
  filter: blur(0);
}

#chatOrbBtn { position: relative; cursor: grab; }
#chatOrbBtn.ai-orb-dragging { cursor: grabbing; z-index: 96; }
#chatOrbBtn.ai-orb-armed .voice-orb {
  filter: drop-shadow(0 8px 22px rgba(239,68,68,.6)) saturate(1.35);
}

/* Globito de estado ("Toca para hablar", "Escuchando…", "Creando…"):
   flota pegado al orbe (es hijo de #chatOrbBtn), así lo sigue a donde sea
   que se arrastre. Se muestra/oculta con la clase .hidden desde
   setOrbStatus en ai.js. */
.ai-chat-orb-status {
  white-space: nowrap;
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: 12px;
  font-weight: 700;
  padding: .4rem .75rem;
  border-radius: 999px;
  background: rgba(28,28,31,.92);
  color: #fff;
  box-shadow: 0 10px 26px -12px rgba(0,0,0,.4);
  backdrop-filter: blur(6px);
}
html:not(.dark) .ai-chat-orb-status {
  background: rgba(255,255,255,.96);
  color: #0a0a0b;
  box-shadow: 0 10px 26px -14px rgba(0,0,0,.22);
}

/* Franja para soltar el orbe y quitarlo — ver initChatOrbDrag en ai.js. */
.ai-orb-drop-zone__badge {
  background: rgba(28,28,31,.94);
  color: rgba(255,255,255,.75);
  box-shadow: 0 10px 30px -10px rgba(0,0,0,.5);
  backdrop-filter: blur(6px);
  transition: background .15s ease, color .15s ease, transform .15s ease;
}
html:not(.dark) .ai-orb-drop-zone__badge {
  background: rgba(255,255,255,.96);
  color: rgba(0,0,0,.55);
  box-shadow: 0 10px 30px -12px rgba(0,0,0,.25);
}
#chatOrbDropZone.ai-orb-drop-zone--armed .ai-orb-drop-zone__badge {
  background: #ef4444;
  color: #fff;
  transform: scale(1.18);
}

/* Aison Publicidad: placeholder mientras cargan los artículos */
@keyframes nexosSkeletonPulse {
  0%, 100% { opacity: .35; }
  50% { opacity: .6; }
}
.nexosSkeleton {
  background: rgba(255,255,255,.08);
  animation: nexosSkeletonPulse 1.4s ease-in-out infinite;
}
html:not(.dark) .nexosSkeleton { background: rgba(0,0,0,.06); }
.nexosCard { transition: transform .2s ease; }
.nexosCard:hover { transform: scale(1.02); }

/* Aison Publicidad (.nexos-page, en el #app de publicidad.html): en modo
   claro el texto tenue (text-white/NN) quedaba blanco sobre el fondo claro
   de .stage-flat, invisible. Va scopeado a .nexos-page (no a #app a secas)
   para no tocar el resto de páginas que comparten esta misma hoja de
   estilos. La ventana de ver diseño (#articleModal) queda afuera a
   propósito: es un visor de foto siempre oscuro, no sigue el tema. */
html:not(.dark) .nexos-page .text-white { color: #0a0a0b; }
html:not(.dark) .nexos-page .text-white\/40 { color: rgba(10,10,11,.45); }
html:not(.dark) .nexos-page .text-white\/45 { color: rgba(10,10,11,.5); }
html:not(.dark) .nexos-page .text-white\/60 { color: rgba(10,10,11,.6); }
html:not(.dark) .nexos-page .hover\:text-white:hover { color: #0a0a0b; }
html:not(.dark) .nexos-page .ring-white\/15 { --tw-ring-color: rgba(0,0,0,.15); }

