/* ==========================================================================
   Chatper · chat.css — vista de chat (SPEC §6.5) y variante de comentarios (§8.3)
   Solo usa los tokens de base.css. Todo en rem/em; los espaciados verticales se
   multiplican por --density (1 cómoda · 0.72 compacta).
   Colores fijos justificados: los rótulos sobre fotos o vídeo (hora, «+N», GIF) usan
   negro translúcido y texto blanco porque van sobre el propio contenido, igual en
   ambos temas.
   ========================================================================== */

.chat {
  --chat-pad-x: 1rem;
  --chat-max: 56rem;
  --chat-media-w: 20rem;
  --chat-media-max-h: 26rem;      /* alto máximo de una imagen sola (SPEC §9.6) */
  /* Una imagen sola o las de una fila: sin «píxel a píxel», el ancho y el alto de siempre; con él (SPEC
     §14.3) se ven a su tamaño 1:1 mientras quepan en la burbuja (ver más abajo). */
  --chat-media-solo-w: var(--chat-media-w);
  --chat-media-solo-max-h: var(--chat-media-max-h);
  --bubble-radius: 1.1rem;
  --bubble-tight: 0.35rem;
  --meta-w: 2.45rem;
  --gap-group: calc(0.8rem * var(--density));
  --gap-msg: calc(0.14rem * var(--density));
  --media-scrim: rgba(10, 12, 16, 0.55);
  /* Peso del color del usuario en su nombre (.msg-author, .msg-quote-author); el resto es --text.
     Con los 15 colores de usuario: ≥ 4,5:1 sobre --bg, --surface y la cita (también en hover). */
  --name-mix: 50%;
  position: relative;
  display: flex;
  flex: 1;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  height: 100%;
  background: var(--bg);
  color: var(--text);
}

/* Barra propia (solo sin panel del dock: páginas de prueba) */
.chat-ownbar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 3rem;
  padding: 0.4rem 0.6rem 0.4rem 1rem;
  border-bottom: 1px solid var(--border);
  background: var(--bg-elevated);
}
.chat-ownbar-title {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  font-weight: 650;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.chat-ownbar-actions { display: flex; align-items: center; gap: 0.25rem; }

.chat-search-btn[aria-pressed="true"] { background: var(--surface-3); color: var(--text); }

.chat-link {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0;
  border: 0;
  background: none;
  color: var(--accent-text);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
.chat-link:hover { text-decoration: underline; }
.chat-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }

/* --------------------------------------------------------------------------
   Zona de mensajes
   -------------------------------------------------------------------------- */
.chat-body {
  position: relative;
  display: flex;
  flex: 1;
  flex-direction: column;
  min-height: 0;
}

.chat-scroll {
  position: relative;            /* offsetTop de las filas relativo al scroll */
  flex: 1;
  min-height: 0;
  overflow-x: hidden;
  overflow-y: auto;
  overflow-anchor: none;         /* la vista gestiona su propia posición */
  overscroll-behavior: contain;
  padding: 0.25rem 0 2.25rem;
  outline: none;
}
.chat-scroll:focus-visible { box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--accent) 40%, transparent); }

.chat-list {
  display: flex;
  flex-direction: column;
  max-width: var(--chat-max);
  margin: 0 auto;
  padding: 0 var(--chat-pad-x);
}

.chat-top {
  display: flex;
  justify-content: center;
  max-width: var(--chat-max);
  min-height: 0.5rem;
  margin: 0 auto;
  padding: 0.5rem var(--chat-pad-x) 0;
}
.chat-top-spacer { height: 2rem; }
.chat-loading,
.chat-start {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0;
  color: var(--text-subtle);
  font-size: 0.8125rem;
}
.chat-start { padding: 0.75rem 0 0.25rem; }
.chat-loading .spinner { width: 1rem; height: 1rem; }
.chat-load-error {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.5rem 0.75rem;
  margin: 2rem 0;
  color: var(--danger-text, var(--danger));
  font-size: 0.875rem;
  text-align: center;
}
.chat-older-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  height: 1.875rem;
  padding: 0 0.8rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  background: var(--surface);
  color: var(--text-muted);
  font: inherit;
  font-size: 0.8125rem;
  font-weight: 550;
  cursor: pointer;
}
.chat-older-btn:hover { background: var(--surface-2); color: var(--text); }
.chat-older-btn[aria-busy="true"] { cursor: progress; }
.chat-older-btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.chat-older-btn .spinner { width: 0.85rem; height: 0.85rem; }

.chat-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.35rem;
  margin: auto;
  padding: 3rem 1rem;
  color: var(--text-muted);
  text-align: center;
}
.chat-empty-icon {
  display: grid;
  place-items: center;
  width: 3.5rem;
  height: 3.5rem;
  margin-bottom: 0.4rem;
  border-radius: var(--radius-full);
  background: var(--accent-soft);
  color: var(--accent-text);
}
.chat-empty-title { color: var(--text); font-size: 1rem; font-weight: 650; }
.chat-empty-text { font-size: 0.875rem; }

/* Separadores */
.chat-day-sep {
  display: flex;
  justify-content: center;
  margin: calc(1.1rem * var(--density)) 0 calc(0.35rem * var(--density));
  pointer-events: none;
}
.chat-day-sep > span {
  padding: 0.2rem 0.75rem;
  border-radius: var(--radius-full);
  /* §17.3: con el acento */
  background: var(--accent-soft);
  color: var(--accent-text);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.01em;
}
.chat-day-sep > span::first-letter { text-transform: uppercase; }

.chat-unread-sep {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: calc(0.9rem * var(--density)) 0 calc(0.2rem * var(--density));
  color: var(--accent-text);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.chat-unread-sep::before,
.chat-unread-sep::after {
  content: "";
  flex: 1;
  height: 1px;
  background: color-mix(in srgb, var(--accent) 45%, transparent);
}

/* Mensajes de sistema */
.msg-system {
  display: flex;
  justify-content: center;
  margin: calc(0.6rem * var(--density)) 0;
}
.msg-system-text {
  max-width: min(32rem, 88%);
  padding: 0.25rem 0.8rem;
  border-radius: var(--radius-full);
  background: color-mix(in srgb, var(--surface-2) 75%, transparent);
  color: var(--text-muted);
  font-size: 0.78rem;
  line-height: 1.4;
  text-align: center;
  overflow-wrap: anywhere;
}

/* --------------------------------------------------------------------------
   Fila de mensaje y burbuja
   -------------------------------------------------------------------------- */
.msg {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  margin-top: var(--gap-msg);
  outline: none;
}
.msg.is-first { margin-top: var(--gap-group); }
.msg.is-own { justify-content: flex-end; }

.msg-avatar { flex: none; width: 2rem; padding-top: 0.05rem; }
.msg-avatar .avatar { --avatar-ring: var(--bg); }
.msg:not(.is-first) .msg-avatar > * { visibility: hidden; }

.msg-content {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  min-width: 0;
  max-width: min(38rem, 78%);
}
.msg.is-own .msg-content { align-items: flex-end; }

.msg-bubble {
  position: relative;
  max-width: 100%;
  min-width: 0;
  padding: calc(0.42rem * var(--density) + 0.08rem) 0.78rem;
  border: 1px solid color-mix(in srgb, var(--border) 65%, transparent);
  border-radius: var(--bubble-radius);
  background: var(--bubble-other);
  color: var(--bubble-other-text);
  box-shadow: var(--shadow-sm);
  font-size: 0.9375rem;
  line-height: 1.45;
  overflow-wrap: anywhere;
  transition: box-shadow var(--dur) var(--ease);
}
:root[data-theme="dark"] .msg-bubble { border-color: transparent; }
:root[data-theme="dark"] .chat { --name-mix: 55%; }
/* §19.13: en oscuro, el nombre de alguien con un color muy oscuro (el acento negro) se aclara hasta leerse (≥ 4,5:1);
   los demás colores ya pasan de esa luminosidad y no cambian. */
@supports (color: oklch(from red l c h)) {
  :root[data-theme="dark"] :is(.msg-author, .msg-quote-author, .msg-anchor) {
    color: oklch(from color-mix(in srgb, var(--user-color) var(--name-mix, 50%), var(--text)) max(l, 0.72) c h);
  }
}
.msg.is-own .msg-bubble {
  border-color: transparent;
  background: var(--bubble-own);
  color: var(--bubble-own-text);
}
/* La burbuja ya lleva el tinte del acento: la selección necesita más acento para verse. */
.msg.is-own .msg-bubble ::selection { background: color-mix(in srgb, var(--accent) 45%, transparent); }

/* Esquinas por posición en el grupo */
.msg.is-other:not(.is-first) .msg-bubble { border-top-left-radius: var(--bubble-tight); }
.msg.is-other:not(.is-last) .msg-bubble { border-bottom-left-radius: var(--bubble-tight); }
.msg.is-own:not(.is-first) .msg-bubble { border-top-right-radius: var(--bubble-tight); }
.msg.is-own:not(.is-last) .msg-bubble { border-bottom-right-radius: var(--bubble-tight); }

.msg:focus-visible .msg-bubble { box-shadow: var(--focus-ring); }
.msg.is-menu-open .msg-bubble { box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 35%, transparent); }

/* Autor: solo en el primer mensaje de un grupo ajeno (en los demás, solo para lectores de pantalla) */
.msg-author {
  overflow: hidden;
  margin-bottom: 0.1rem;
  color: color-mix(in srgb, var(--user-color) var(--name-mix, 50%), var(--text));
  font-size: 0.8125rem;
  font-weight: 650;
  line-height: 1.3;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.msg.is-own .msg-author,
.msg:not(.is-first) .msg-author {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
/* Si el grupo ajeno empieza con solo fotos/vídeo o con emojis grandes (sin burbuja), el nombre va
   encima, fuera del contenido. */
.msg.is-other.is-first.is-media-only .msg-author,
.msg.is-other.is-first.is-jumbo .msg-author { margin: 0 0 0.2rem 0.2rem; }

/* Texto con markdown */
.msg-text {
  white-space: pre-wrap;
  word-break: break-word;
}
.msg.has-text .msg-text::after {
  content: "";
  display: inline-block;
  width: var(--meta-w);
  height: 0.5em;
}
.msg-bubble.meta-own { --meta-w: 3.45rem; }
.msg-bubble.meta-edited { --meta-w: 5.4rem; }
.msg-bubble.meta-own.meta-edited { --meta-w: 6.4rem; }

.msg-text-wrap { display: flex; flex-direction: column; align-items: flex-start; }
.msg-text.is-collapsed {
  max-height: 20em;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to bottom, #000 72%, transparent);
  mask-image: linear-gradient(to bottom, #000 72%, transparent);
}
.msg-more { margin: 0.2rem var(--meta-w) 0.05rem 0; font-size: 0.8125rem; }

.md-strong { font-weight: 700; }
.md-del { opacity: 0.85; }
.md-code {
  padding: 0.08em 0.35em;
  border-radius: 5px;
  background: color-mix(in srgb, currentColor 11%, transparent);
  font-family: var(--font-mono);
  font-size: 0.86em;
  overflow-wrap: anywhere;
}
.md-pre {
  max-width: 100%;
  margin: 0.3rem 0;
  padding: 0.55rem 0.75rem;
  overflow-x: auto;
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, currentColor 8%, transparent);
  font-size: 0.8125rem;
  line-height: 1.5;
  white-space: pre;
  word-break: normal;
  overflow-wrap: normal;
}
.md-pre code { font-family: var(--font-mono); }
.md-link {
  color: var(--accent-text);
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, currentColor 45%, transparent);
  text-underline-offset: 2px;
  overflow-wrap: anywhere;
}
.md-link:hover { text-decoration-color: currentColor; }
.md-mention { color: var(--accent-text); font-weight: 600; }
.md-mention.is-me {
  padding: 0 0.2em;
  border-radius: 4px;
  background: var(--accent-soft);
}
/* La burbuja propia ya lleva el tinte del acento: enlaces y menciones siguen en --accent-text
   (≥ 4,6:1 sobre ella en ambos temas) y mi mención va sobre el fondo «hundido». */
.msg.is-own .md-mention.is-me { background: var(--bubble-own-inset); }

/* Hora, «editado» y estado */
.msg-meta {
  display: inline-flex;
  align-items: center;
  gap: 0.2rem;
  color: var(--text-subtle);
  font-size: 0.6875rem;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  white-space: nowrap;
  user-select: none;
}
.msg.has-text .msg-meta {
  position: absolute;
  right: 0.7rem;
  bottom: calc(0.38rem * var(--density) + 0.1rem);
}
.msg:not(.has-text):not(.is-media-only) .msg-meta {
  display: flex;
  justify-content: flex-end;
  margin-top: 0.25rem;
}
/* La hora es texto pequeño: --bubble-own-meta da ≥ 4,8:1 sobre la burbuja propia con todos los
   acentos (claro: --text-muted; oscuro: el texto un 22 % hacia el fondo de la burbuja). */
.msg.is-own .msg-meta { color: var(--bubble-own-meta); }
.msg-edited { font-style: italic; }
.msg-status { display: inline-flex; margin-left: 0.05rem; }
.msg-status svg { width: 0.95rem; height: 0.95rem; }
.msg-status-read { display: none; }
.msg.is-read .msg-status-sent { display: none; }
.msg.is-read .msg-status-read { display: block; }

/* Solo imágenes / vídeo: sin burbuja y con la hora encima */
.msg.is-media-only .msg-bubble {
  padding: 0;
  border: 0;
  background: transparent;
  box-shadow: none;
}
.msg.is-media-only .msg-meta {
  position: absolute;
  right: 0.45rem;
  bottom: 0.45rem;
  padding: 0.22rem 0.45rem;
  border-radius: var(--radius-full);
  background: var(--media-scrim);
  color: #fff;
  pointer-events: none;
}
/* Con vídeo, la pastilla taparía la barra de controles nativa: la hora va debajo, en su sitio. */
.msg.is-media-only:has(.att-video) .msg-meta {
  position: static;
  display: flex;
  justify-content: flex-end;
  margin-top: 0.25rem;
  padding: 0;
  background: none;
  color: var(--text-subtle);
}
/* Imágenes pequeñas (una sola o en fila): la pastilla de la hora las taparía; va debajo. */
.msg.is-media-only:has(.msg-media.is-small) .msg-meta {
  position: static;
  display: flex;
  justify-content: flex-end;
  margin-top: 0.25rem;
  padding: 0;
  background: none;
  color: var(--text-subtle);
}
.msg.is-media-only .att-grid,
.msg.is-media-only .att-video { border-radius: var(--att-r, var(--bubble-radius)); }
.msg.is-media-only.is-other:not(.is-first) .att-grid,
.msg.is-media-only.is-other:not(.is-first) .att-video { border-top-left-radius: var(--att-r-tight, var(--bubble-tight)); }
.msg.is-media-only.is-other:not(.is-last) .att-grid,
.msg.is-media-only.is-other:not(.is-last) .att-video { border-bottom-left-radius: var(--att-r-tight, var(--bubble-tight)); }
.msg.is-media-only.is-own:not(.is-first) .att-grid,
.msg.is-media-only.is-own:not(.is-first) .att-video { border-top-right-radius: var(--att-r-tight, var(--bubble-tight)); }
.msg.is-media-only.is-own:not(.is-last) .att-grid,
.msg.is-media-only.is-own:not(.is-last) .att-video { border-bottom-right-radius: var(--att-r-tight, var(--bubble-tight)); }

/* Emojis grandes */
.msg.is-jumbo .msg-bubble {
  padding: 0 0.1rem;
  border: 0;
  background: transparent;
  box-shadow: none;
  color: var(--text);
}
.msg-jumbo {
  font-size: 2.4rem;
  line-height: 1.2;
  letter-spacing: 0.05em;
  white-space: nowrap;
}
.msg-jumbo-1 { font-size: 3rem; }
/* §37: en los mensajes de solo emojis, la imagen a su tamaño (96 px = 2× de 48) */
.msg-jumbo img.emoji { width: 1.1em; height: 1.1em; vertical-align: -0.15em; }
.msg-jumbo-3 { font-size: 2.1rem; }
.msg.is-jumbo .msg-meta {
  display: flex;
  justify-content: flex-end;
  margin-top: 0.1rem;
  color: var(--text-subtle);
}

/* Eliminado */
.msg.is-deleted .msg-bubble {
  border: 1px dashed var(--border-strong);
  background: transparent;
  box-shadow: none;
  color: var(--text-subtle);
}
.msg.is-deleted .msg-meta { color: var(--text-subtle); }
.msg-deleted {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.875rem;
  font-style: italic;
}
.msg.is-deleted .msg-deleted::after { content: ""; display: inline-block; width: var(--meta-w); }
.msg.is-deleted .msg-meta { position: absolute; right: 0.7rem; bottom: calc(0.38rem * var(--density) + 0.12rem); margin: 0; }
.msg.is-deleted .msg-status { display: none; }

/* El aviso caducó con la vista delante (SPEC §9.17): se recoge (alto y márgenes a 0) y se desvanece;
   chat-view.js le pone antes su alto actual y mantiene anclado lo que se lee. */
.chat-list > .is-vanishing {
  height: 0 !important;
  margin-top: 0 !important;
  margin-bottom: 0 !important;
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
  transition: height 260ms var(--ease), margin 260ms var(--ease), opacity 180ms var(--ease);
}

/* Resaltado al saltar a un mensaje */
.msg.is-highlight::before {
  content: "";
  position: absolute;
  inset: -0.2rem calc(-1 * var(--chat-pad-x));
  z-index: -1;
  background: var(--accent-soft);
  animation: chat-flash 1.8s var(--ease) forwards;
  pointer-events: none;
}
.msg.is-highlight { z-index: 0; }
@keyframes chat-flash {
  0%, 35% { opacity: 1; }
  100% { opacity: 0; }
}

/* Envío optimista */
.msg.is-pending .msg-bubble { opacity: 0.86; }
.msg.is-pending .msg-status svg { width: 0.8rem; height: 0.8rem; }
.msg-sending {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 0.25rem 0.75rem;
  margin-top: 0.15rem;
  color: var(--text-subtle);
  font-size: 0.6875rem;
  opacity: 0;
  animation: chat-fade-in var(--dur-in) var(--ease) 1.2s forwards;
}
.msg-sending .chat-link { font-size: 0.75rem; }
.msg.is-failed .msg-bubble {
  opacity: 1;
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--danger) 55%, transparent);
}
.msg-failed {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 0.25rem 0.75rem;
  margin-top: 0.3rem;
  color: var(--danger-text, var(--danger));
  font-size: 0.75rem;
}
.msg-failed .chat-link { font-size: 0.75rem; }
@keyframes chat-fade-in { to { opacity: 1; } }

/* --------------------------------------------------------------------------
   Cita (respuesta)
   -------------------------------------------------------------------------- */
.msg-quote {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  min-width: 8rem;
  max-width: 100%;
  margin: 0.15rem 0 0.35rem;
  padding: 0.28rem 0.6rem 0.3rem;
  border: 0;
  border-left: 3px solid color-mix(in srgb, var(--user-color) 85%, var(--text));
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--user-color) 11%, transparent);
  color: inherit;
  font: inherit;
  font-size: 0.8125rem;
  line-height: 1.35;
  text-align: left;
  cursor: pointer;
}
/* El nombre y el texto, uno encima de otro; a la derecha, la imagen citada (§35) */
.msg-quote-body { display: flex; flex: 1; flex-direction: column; align-items: flex-start; min-width: 0; }
.msg-quote-thumb,
.composer-context-thumb {
  flex: none;
  width: auto;
  height: 2.5rem;
  max-width: 4rem;
  border-radius: 0.3rem;
  object-fit: cover;
}
.composer-context-thumb[hidden] { display: none; }
button.msg-quote:hover { background: color-mix(in srgb, var(--user-color) 18%, transparent); }
.msg-quote:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.msg-quote-author {
  max-width: 100%;
  overflow: hidden;
  color: color-mix(in srgb, var(--user-color) var(--name-mix, 50%), var(--text));
  font-weight: 650;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.msg-quote-text {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  max-width: 100%;
  min-width: 0;
  overflow: hidden;
  opacity: 0.85;
  white-space: nowrap;
}
.msg-quote-text > svg { flex: none; }
/* La elipsis solo funciona en un elemento propio (no en el texto suelto de un flex) */
.msg-quote-label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.msg-quote-text.is-deleted { font-style: italic; }
.composer-context .msg-quote {
  border-left-color: color-mix(in srgb, var(--bubble-own-text) 80%, transparent);
  background: color-mix(in srgb, var(--bubble-own-text) 14%, transparent);
}
/* En la burbuja propia (tinte suave del acento) la cita va sobre el fondo «hundido»
   (--bubble-own-inset: más claro en claro, más oscuro en oscuro), con la barra del color del
   autor citado; el nombre va en el color del texto y la cita en el de la hora (≥ 5:1). */
.msg.is-own .msg-quote { background: var(--bubble-own-inset); }
.msg.is-own button.msg-quote:hover { background: color-mix(in srgb, var(--user-color) 12%, var(--bubble-own-inset)); }
.msg.is-own .msg-quote-author { color: inherit; }
.msg.is-own .msg-quote-text { opacity: 1; color: var(--bubble-own-meta); }

/* --------------------------------------------------------------------------
   Adjuntos
   -------------------------------------------------------------------------- */
.msg-media {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  max-width: 100%;
  margin: 0.15rem 0 0.3rem;
}
.msg-bubble > .msg-media:last-child { margin-bottom: 0.1rem; }
/* Lo que sea más estrecho que la burbuja propia va a su lado (derecha), como la burbuja. */
.msg.is-own .msg-media:not(.is-pending) { align-items: flex-end; }
.msg.is-media-only .msg-media { margin: 0; }
.msg.has-media.has-text .msg-media { margin-bottom: 0.35rem; }

.att { position: relative; max-width: 100%; }

/* Imágenes (SPEC §9.6 y §14.3): nunca más grandes que su tamaño natural (--nat-w/--nat-h en px CSS,
   de --img-w/--img-h que pone attachments.js con file.width/height; y --att-ratio). */
.att-grid {
  display: grid;
  gap: 2px;
  width: var(--chat-media-w);
  max-width: 100%;
  overflow: hidden;
  border-radius: var(--att-r, calc(var(--bubble-radius) - 0.35rem));
  background: var(--surface-3);
}
/* Una sola: ancho = mín(natural, ancho máximo, alto máximo × proporción). Sin porcentajes en width
   (con max-width basta): así la burbuja se ajusta al ancho real de la imagen. «Natural» = --nat-w (px
   CSS, .px-nat de base.css: con píxel a píxel, natural / DPR); sin tamaño conocido, el ancho de siempre. */
.att-grid-1 {
  width: min(var(--nat-w, var(--chat-media-w)), var(--chat-media-solo-w), calc(var(--chat-media-solo-max-h) * var(--att-ratio, 1.3333)));
  aspect-ratio: var(--att-ratio, 4 / 3);
}
/* Pequeña: esquinas proporcionadas (una de 40 px con 1,1rem de radio sería casi un círculo). */
.att-grid.is-small { --att-r: min(var(--radius), 18%); --att-r-tight: min(var(--bubble-tight), 18%); }
.att-grid-2,
.att-grid-3,
.att-grid-4 { grid-template-columns: 1fr 1fr; }
.att-grid-2 .att { aspect-ratio: 4 / 5; }
.att-grid-3 .att { aspect-ratio: 1; }
.att-grid-3 .att:first-child { grid-column: span 2; aspect-ratio: 2 / 1; }
.att-grid-4 .att { aspect-ratio: 1; }

/* Varias pequeñas: en fila, cada una a su tamaño real, alineadas al lado de la burbuja. Las líneas
   las reparte attachments.js (la burbuja mide lo que la línea más larga); si la columna es aún más
   estrecha, cada línea se parte a su vez. */
.att-row {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.25rem;
  max-width: 100%;
}
.att-row-line {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  max-width: 100%;
}
.msg.is-own .att-row { align-items: flex-end; }
.msg.is-own .att-row-line { justify-content: flex-end; }
.att-row-line > .att-image {
  flex: none;
  width: var(--nat-w);
  max-width: 100%;
  aspect-ratio: var(--att-ratio, 1);
  border-radius: min(var(--radius), 18%);
}

.att-image { overflow: hidden; background: var(--surface-3); }
.att-grid-1 .att-image { height: 100%; }
.att-open {
  display: block;
  width: 100%;
  height: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
}
.att-open img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  -webkit-touch-callout: none;
  transition: transform 260ms var(--ease), filter 260ms var(--ease);
}
/* Mosaico: recorta solo si la imagen es mayor que la celda en ambas dimensiones; si no, se reduce
   entera (o se queda a su tamaño) centrada sobre el fondo suave de la celda. */
.att-image.is-cover img { object-fit: cover; }
.att-image.is-fit-down img { object-fit: scale-down; }
.att-open:hover img { filter: brightness(1.04); }
.att-open:focus-visible { outline: none; box-shadow: inset 0 0 0 3px var(--accent); }
.att-broken {
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
  min-height: 6rem;
  color: var(--text-subtle);
}
.att-plus {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background: var(--media-scrim);
  color: #fff;
  font-size: 1.6rem;
  font-weight: 700;
}
.att-badge {
  position: absolute;
  top: 0.4rem;
  left: 0.4rem;
  padding: 0.1rem 0.35rem;
  border-radius: 4px;
  background: var(--media-scrim);
  color: #fff;
  font-size: 0.625rem;
  font-weight: 750;
  letter-spacing: 0.06em;
  pointer-events: none;
}

/* «Ver en grande» del vídeo (arriba a la izquierda: la esquina derecha es de la mini barra del
   mensaje). Los adjuntos ya no tienen menú propio: todo va en el menú del mensaje (SPEC §9.2). */
.att-expand {
  position: absolute;
  top: 0.35rem;
  left: 0.35rem;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 1.75rem;
  height: 1.75rem;
  padding: 0;
  border: 0;
  border-radius: var(--radius-full);
  background: var(--media-scrim);
  color: #fff;
  opacity: 0;
  cursor: pointer;
  transition: opacity var(--dur) var(--ease), background-color var(--dur) var(--ease);
}
.att:hover > .att-expand,
.att:focus-within > .att-expand { opacity: 1; }
.att-expand:focus-visible { opacity: 1; outline: 2px solid var(--accent); outline-offset: 1px; }

.att.is-dragging { opacity: 0.55; }
.att.is-file-draggable { cursor: grab; }
.att.is-file-draggable .att-open { cursor: zoom-in; }

/* Vídeo (SPEC §9.16): entero, con su proporción real (--att-ratio y --att-w, el ancho natural, los pone
   attachments.js con los metadatos) y el mismo tope que una imagen sola: ancho = mín(natural, ancho de
   los adjuntos, alto máximo × proporción). Nunca se recorta (contain) y los controles nativos, que van
   dentro, se ven enteros. */
.att-video {
  width: min(var(--att-w, var(--chat-media-w)), var(--chat-media-w), calc(var(--chat-media-max-h) * var(--att-ratio, 1.7778)));
  max-width: 100%;
  aspect-ratio: var(--att-ratio, 16 / 9);
  overflow: hidden;
  border-radius: calc(var(--bubble-radius) - 0.35rem);
  background: #000;
}
.att-video video { display: block; width: 100%; height: 100%; object-fit: contain; }

/* Audio */
.att-audio { width: 19rem; max-width: 100%; }
/* Sin el mínimo de 13rem del componente: en columnas estrechas la burbuja es más estrecha. */
.att-audio .audio-player { width: 100%; min-width: 0; }
.att-audio .audio-player__wave { min-width: 1.5rem; }
@container chat-scroll (max-width: 22rem) {
  .att-audio .audio-player { gap: 0.5rem; padding-right: 0.5rem; }
  .att-audio .audio-player__row { gap: 0.35rem; }
  .att-audio .audio-player__speed { display: none; }
}
.msg-bubble .att-audio { margin-right: 0; }
.msg.has-media .msg-bubble:has(.att-audio) { overflow: visible; }
/* En la burbuja propia el reproductor conserva el botón de play en el color del acento (como en
   las ajenas) y va sobre el fondo «hundido» de la burbuja. */
.msg.is-own .audio-player {
  --ap-bg: var(--bubble-own-inset);
  --ap-fg: var(--bubble-own-text);
  --ap-track: color-mix(in srgb, var(--bubble-own-text) 26%, transparent);
  --ap-chip: color-mix(in srgb, var(--bubble-own-text) 10%, transparent);
}

/* Tarjeta de archivo */
.att-file {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  width: 20rem;
  max-width: 100%;
  padding: 0.35rem;
  border-radius: var(--radius);
  background: color-mix(in srgb, currentColor 6%, transparent);
}
.att-file-main {
  display: flex;
  flex: 1;
  align-items: center;
  gap: 0.6rem;
  min-width: 0;
  padding: 0.1rem 0.15rem;
  border-radius: var(--radius-sm);
  color: inherit;
  text-decoration: none;
}
.att-file-main:hover { text-decoration: none; }
.att-file-main:hover .att-file-name { text-decoration: underline; }
.att-file-main:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.att-file-icon {
  display: grid;
  flex: none;
  place-items: center;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: var(--radius);
  background: var(--accent-soft);
  color: var(--accent-text);
}
.msg.is-own .att-file { background: var(--bubble-own-inset); }
.att-file-text { display: flex; flex: 1; flex-direction: column; min-width: 0; line-height: 1.3; }
/* Nombre: una línea con «…»; si no cabe, al pasar por encima se desplaza (marquee.js, SPEC §9.15).
   La caja .att-file-name-clip lo recorta mientras se mueve. */
.att-file-name-clip { position: relative; display: block; min-width: 0; overflow: hidden; font-size: 0.875rem; line-height: 1.3; }
/* Sin animación (prefers-reduced-motion: marquee.js pone .is-marquee-full): el nombre completo en un
   globo encima de su sitio. Antes pasaba a varias líneas y la tarjeta crecía, lo que movía los
   mensajes de alrededor al pasar el ratón. El hueco conserva su línea. */
.att-file-name-clip:has(> .is-marquee-full) { z-index: 3; min-height: 1.3em; overflow: visible; }
.att-file-name.is-marquee-full {
  position: absolute;
  top: -0.2rem;
  left: -0.35rem;
  right: -0.35rem;
  padding: 0.2rem 0.35rem;
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
  box-shadow: 0 0 0 1px var(--border-strong), var(--shadow);
}
.att-file-name {
  display: block;
  overflow: hidden;
  font-size: 0.875rem;
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.att-file-meta {
  overflow: hidden;
  color: var(--text-muted);
  font-size: 0.75rem;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.att-download {
  display: grid;
  flex: none;
  place-items: center;
  width: 2.1rem;
  height: 2.1rem;
  border-radius: var(--radius-full);
  color: inherit;
  opacity: 0.8;
}
.att-download:hover { background: color-mix(in srgb, currentColor 12%, transparent); opacity: 1; text-decoration: none; }
.att-download:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
/* Columnas estrechas del dock (hasta 240 px): «Descargar» sigue en el menú del mensaje y el nombre
   y el tamaño conservan el ancho que necesitan. */
@container chat-scroll (max-width: 20rem) {
  .chat-list { --chat-pad-x: 0.6rem; }
  .msg-content { max-width: 88%; }
  .att-file { gap: 0.1rem; padding: 0.25rem; }
  .att-file-main { gap: 0.45rem; padding: 0.1rem; }
  .att-file-icon { width: 2rem; height: 2rem; }
  .att-file-icon svg { width: 1.125rem; height: 1.125rem; }
  .att-file > .att-download { display: none; }
}

/* Adjuntos de un envío en curso */
.msg-media.is-pending { flex-direction: row; flex-wrap: wrap; gap: 0.25rem; }
.att-pending {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius);
}
.att-pending-image,
.att-pending-video {
  width: 7rem;
  height: 7rem;
  background: var(--surface-3);
}
/* Un vídeo solo mientras se envía: entero, con su proporción y el mismo tope que el ya enviado (§9.16). */
.msg-media.is-pending:not(.is-multi) .att-pending-video { width: auto; max-width: min(100%, var(--chat-media-w)); height: auto; background: #000; }
.att-pending img,
.att-pending video { display: block; width: 100%; height: 100%; max-height: 22rem; object-fit: cover; }
.msg-media.is-pending:not(.is-multi) .att-pending-video video {
  width: auto;
  max-width: 100%;
  height: auto;
  max-height: var(--chat-media-max-h);
  object-fit: contain;
}
/* Sin ampliar (SPEC §9.6): en la ficha cuadrada, recorte solo si la imagen la supera en ambas
   dimensiones (lo decide el JS al cargar); sola, a su tamaño natural como máximo. */
.att-pending-image img { object-fit: scale-down; }
.att-pending-image.is-cover img { object-fit: cover; }
.msg-media.is-pending:not(.is-multi) .att-pending-image {
  display: grid;
  place-items: center;
  width: auto;
  min-width: 3rem;
  max-width: min(100%, var(--chat-media-solo-w));
  height: auto;
  min-height: 3rem;
}
/* El tamaño propio del blob: ya es el natural de píxel a píxel (srcset de densidad, media-src.js). */
.msg-media.is-pending:not(.is-multi) .att-pending-image img { width: auto; max-width: 100%; height: auto; max-height: var(--chat-media-solo-max-h); }
.att-pending-audio,
.att-pending-file {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  width: 18rem;
  max-width: 100%;
  padding: 0.45rem 0.5rem 0.75rem;
  background: color-mix(in srgb, currentColor 6%, transparent);
}
.att-progress {
  position: absolute;
  right: 0.5rem;
  bottom: 0.4rem;
  left: 0.5rem;
  height: 0.25rem;
  overflow: hidden;
  border-radius: var(--radius-full);
  background: color-mix(in srgb, var(--surface) 70%, transparent);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--bubble-own-text) 12%, transparent);
  transition: opacity var(--dur) var(--ease);
}
.att-progress::after {
  content: "";
  display: block;
  width: calc(var(--p, 0) * 1%);
  height: 100%;
  border-radius: inherit;
  background: var(--accent);
  transition: width 200ms linear;
}
.att-pending.is-done .att-progress { opacity: 0; }
.att-pending.is-error .att-progress::after { background: var(--danger); width: 100%; }

/* --------------------------------------------------------------------------
   Reacciones
   -------------------------------------------------------------------------- */
.msg-reactions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  margin-top: 0.3rem;
}
.msg.is-own .msg-reactions { justify-content: flex-end; }
.reaction-chip,
.reaction-add {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  height: 1.65rem;
  padding: 0 0.55rem 0 0.45rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  background: var(--surface);
  color: var(--text-muted);
  font: inherit;
  font-size: 0.8125rem;
  font-weight: 550;
  line-height: 1;
  cursor: pointer;
  transition: background-color var(--dur) var(--ease), border-color var(--dur) var(--ease), transform 90ms var(--ease);
}
.reaction-chip:hover { border-color: var(--border-strong); background: var(--surface-2); }
.reaction-chip:active { transform: scale(0.94); }
.reaction-chip.is-mine {
  border-color: color-mix(in srgb, var(--accent) 50%, transparent);
  background: var(--accent-soft);
  color: var(--accent-text);
  font-weight: 650;
}
.reaction-chip:focus-visible,
.reaction-add:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.reaction-emoji { font-size: 1rem; line-height: 1; }
.reaction-count { font-variant-numeric: tabular-nums; }
.reaction-add {
  justify-content: center;
  width: 1.9rem;
  padding: 0;
  opacity: 0;
}
.msg:hover .reaction-add,
.reaction-add:focus-visible { opacity: 1; }

/* --------------------------------------------------------------------------
   Tarea del mensaje (SPEC §20.6 y §24.1): etiqueta bajo la burbuja que abre la pestaña Tareas
   («☐ Tarea · Ana · 12 oct», «✓ Hecha»). Vencida en rojo suave; para hoy, en el acento.
   -------------------------------------------------------------------------- */
.msg-task-row { display: flex; max-width: 100%; margin-top: 0.3rem; }
.msg.is-own .msg-task-row { justify-content: flex-end; }
.msg-task {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  min-width: 0;
  max-width: 100%;
  height: 1.6rem;
  padding: 0 0.6rem 0 0.5rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  background: var(--surface);
  color: var(--text-muted);
  font: inherit;
  font-size: 0.78rem;
  font-weight: 550;
  line-height: 1;
  cursor: pointer;
  animation: cp-soft-in var(--dur-in) var(--ease) both;
  transition: background-color var(--dur) var(--ease), border-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
.msg-task svg { width: 0.85rem; height: 0.85rem; flex-shrink: 0; color: var(--accent-text); }
.msg-task-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.msg-task:hover { border-color: color-mix(in srgb, var(--accent) 40%, var(--border)); background: var(--surface-2); color: var(--text); }
.msg-task:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.msg-task.is-done { border-color: transparent; background: var(--accent-soft); color: var(--accent-text); }
.msg-task.is-today { border-color: color-mix(in srgb, var(--accent) 35%, transparent); background: var(--accent-soft); color: var(--accent-text); }
.msg-task.is-overdue { border-color: transparent; background: var(--danger-soft); color: var(--danger-text); }
.msg-task.is-overdue svg { color: currentColor; }

/* --------------------------------------------------------------------------
   Barra de acciones al pasar el ratón y menú del mensaje
   -------------------------------------------------------------------------- */
/* Mini barra [reaccionar][responder][⋯] (SPEC §9.2): flota SOBRE la esquina superior derecha de la
   burbuja (encima de la imagen si empieza por una), superpuesta a su borde superior: siempre en el
   mismo sitio, sea cual sea el ancho del mensaje. Va dentro de .msg-bubble y se ancla por abajo
   (sobresale lo que mide menos --msg-tb-overlap). Pegada al borde superior de la lista (sin sitio
   encima) entra en la burbuja, en la misma esquina (.is-inside). */
.chat-scroll { container: chat-scroll / inline-size; }
.msg-toolbar {
  --msg-tb-overlap: 0.55rem;
  --msg-tb-w: calc(3 * 1.9rem + 2 * 0.05rem + 2 * 0.15rem + 2px);
  position: absolute;
  right: 0.45rem;
  bottom: calc(100% - var(--msg-tb-overlap));
  z-index: 3;
  display: flex;
  box-sizing: border-box;
  width: var(--msg-tb-w);
  gap: 0.05rem;
  padding: 0.15rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
  color: var(--text);
  font-size: 1rem;
  line-height: 1;
  white-space: nowrap;
  animation: cp-pop-in var(--dur-in) var(--ease);
  -webkit-user-select: none;
  user-select: none;
}
/* Burbuja ajena más estrecha que la barra (p. ej. «ok»): la barra empieza en su borde izquierdo y
   sobresale hacia la derecha (hacia el hueco libre), sin tapar el avatar ni el nombre. */
.msg.is-other .msg-toolbar { right: auto; left: max(0px, calc(100% - var(--msg-tb-w) - 0.45rem)); }
/* Emojis grandes (sin burbuja): la barra queda encima, casi sin solaparse. */
.msg.is-jumbo .msg-toolbar { --msg-tb-overlap: 0.15rem; }
/* El primer mensaje ajeno de solo fotos/vídeo lleva el nombre ENCIMA, dentro de la burbuja
   transparente: la barra baja esa línea para quedar sobre la imagen. */
.msg.is-other.is-first.is-media-only .msg-toolbar { bottom: calc(100% - var(--msg-tb-overlap) - 0.8125rem * 1.3 - 0.2rem); }
.msg-toolbar.is-inside,
.msg.is-other.is-first.is-media-only .msg-toolbar.is-inside { top: 0.3rem; bottom: auto; }
.msg.is-other.is-first.is-media-only .msg-toolbar.is-inside { top: calc(0.3rem + 0.8125rem * 1.3 + 0.2rem); }
.msg-tool {
  display: grid;
  place-items: center;
  width: 1.9rem;
  height: 1.9rem;
  padding: 0;
  border: 0;
  border-radius: 7px;
  background: none;
  color: var(--text-muted);
  cursor: pointer;
}
.msg-tool:hover,
.msg-tool[aria-expanded="true"] { background: var(--surface-2); color: var(--text); }
.msg-tool:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* Menú del mensaje: openMenu (ui.js) con la fila de reacciones rápidas encima; los submenús de
   cada adjunto son menús normales de ui.js. Solo reacciones (botón 😀): popover. */
.menu.msg-menu { min-width: 13.5rem; max-width: min(21.5rem, calc(100vw - 1rem)); }
.msg-react-popover { padding: 0.3rem; }
.msg-react-popover .msg-menu-reactions { padding: 0; }
.msg-menu-reactions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.1rem;
  padding: 0.1rem 0.1rem 0.3rem;
}
.menu > .msg-menu-reactions:not(:last-child) { margin-bottom: 0.3rem; border-bottom: 1px solid var(--border); }
/* Encabezado del adjunto (un solo adjunto): su nombre tal cual, sin mayúsculas */
.msg-menu .menu-header { text-transform: none; letter-spacing: 0; font-size: 0.75rem; }
.msg-menu-file { display: flex; align-items: center; gap: 0.4rem; min-width: 0; }
.msg-menu-file > svg { flex: none; width: 0.9rem; height: 0.9rem; }
.msg-menu-file > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.msg-menu-emoji {
  display: grid;
  place-items: center;
  width: 2.1rem;
  height: 2.1rem;
  padding: 0;
  border: 0;
  border-radius: var(--radius-full);
  background: none;
  color: var(--text-muted);
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
  transition: transform 120ms var(--ease), background-color var(--dur) var(--ease);
}
.msg-menu-emoji:hover { background: var(--surface-2); transform: scale(1.15); }
.msg-menu-emoji:focus { outline: none; }
.msg-menu-emoji:focus-visible { box-shadow: var(--focus-ring); }
.msg-menu-emoji.is-mine { background: var(--accent-soft); }

/* --------------------------------------------------------------------------
   Escribiendo… y botón «ir al final»
   -------------------------------------------------------------------------- */
.chat-typing {
  position: absolute;
  bottom: 0.4rem;
  left: max(var(--chat-pad-x), calc((100% - var(--chat-max)) / 2 + var(--chat-pad-x)));
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  max-width: calc(100% - 5rem);
  padding: 0.28rem 0.7rem 0.28rem 0.55rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  color: var(--text-muted);
  font-size: 0.78rem;
  pointer-events: none;
  animation: chat-fade-in var(--dur-in) var(--ease) both;
  opacity: 0;
}
.chat-typing > span:last-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-typing-dots { display: inline-flex; gap: 0.18rem; }
.chat-typing-dots i {
  display: block;
  width: 0.32rem;
  height: 0.32rem;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.35;
  animation: chat-dot 1.2s infinite ease-in-out;
}
.chat-typing-dots i:nth-child(2) { animation-delay: 0.15s; }
.chat-typing-dots i:nth-child(3) { animation-delay: 0.3s; }
@keyframes chat-dot {
  0%, 60%, 100% { opacity: 0.3; transform: translateY(0); }
  30% { opacity: 1; transform: translateY(-0.15rem); }
}

.chat-jump {
  position: absolute;
  right: max(1rem, calc((100% - var(--chat-max)) / 2 + 1rem));
  bottom: 0.9rem;
  z-index: 2;
  display: grid;
  place-items: center;
  width: 2.6rem;
  height: 2.6rem;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  background: var(--surface);
  box-shadow: var(--shadow);
  color: var(--text-muted);
  cursor: pointer;
  animation: cp-pop-in var(--dur-in) var(--ease);
}
.chat-jump:hover { background: var(--surface-2); color: var(--text); }
.chat-jump:focus-visible { outline: none; box-shadow: var(--shadow), var(--focus-ring); }
.chat-jump-count {
  position: absolute;
  top: -0.45rem;
  right: -0.3rem;
  display: grid;
  place-items: center;
  min-width: 1.3rem;
  height: 1.3rem;
  padding: 0 0.3rem;
  border-radius: var(--radius-full);
  background: var(--accent);
  color: var(--accent-contrast);
  font-size: 0.6875rem;
  font-weight: 700;
}

/* --------------------------------------------------------------------------
   Tarjeta del item (hilos, §8.3)
   -------------------------------------------------------------------------- */
.chat-thread-slot:empty { display: none; }
.chat-thread-slot { padding: 0.6rem var(--chat-pad-x) 0; }
.chat-thread-card {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  width: 100%;
  max-width: var(--chat-max);
  margin: 0 auto;
  padding: 0.45rem 0.75rem 0.45rem 0.45rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: background-color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.chat-thread-card:hover { border-color: var(--border-strong); background: var(--surface-2); }
.chat-thread-card:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.chat-thread-thumb {
  display: grid;
  flex: none;
  place-items: center;
  width: 3rem;
  height: 3rem;
  overflow: hidden;
  border-radius: var(--radius);
  background: var(--surface-2);
  color: var(--text-muted);
}
/* Miniatura (SPEC §9.18): recorta (cover) solo si la imagen llena el hueco en las dos dimensiones; si
   es más pequeña (< 3rem) se ve entera a su tamaño, centrada, sin ampliar (lo decide chat-view.js). */
.chat-thread-thumb img { width: 100%; height: 100%; object-fit: scale-down; }
.chat-thread-thumb img.is-cover { object-fit: cover; }
.chat-thread-info { display: flex; flex: 1; flex-direction: column; min-width: 0; line-height: 1.35; }
.chat-thread-title { overflow: hidden; font-weight: 650; text-overflow: ellipsis; white-space: nowrap; }
.chat-thread-meta {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  min-width: 0;
  overflow: hidden;
  color: var(--text-muted);
  font-size: 0.78rem;
  white-space: nowrap;
}
.chat-thread-meta > svg { flex: none; }
.chat-thread-meta-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.chat-thread-open {
  display: inline-flex;
  flex: none;
  align-items: center;
  gap: 0.15rem;
  color: var(--accent-text);
  font-size: 0.8125rem;
  font-weight: 600;
}

/* --------------------------------------------------------------------------
   Búsqueda
   -------------------------------------------------------------------------- */
.chat-search {
  position: relative;
  z-index: 4;
  display: flex;
  flex: none;
  flex-direction: column;
  max-height: min(28rem, 60%);
  border-bottom: 1px solid var(--border);
  background: var(--bg-elevated);
  box-shadow: var(--shadow-sm);
  animation: chat-slide-down var(--dur-in) var(--ease);
}
@keyframes chat-slide-down {
  from { opacity: 0; transform: translateY(-0.4rem); }
  to { opacity: 1; transform: none; }
}
.chat-search-bar {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin: 0.55rem 0.75rem 0.35rem;
  padding: 0 0.25rem 0 0.7rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}
.chat-search-bar:focus-within { border-color: color-mix(in srgb, var(--accent) 55%, var(--border)); box-shadow: var(--focus-ring); }
.chat-search-icon { color: var(--text-subtle); }
.chat-search-input {
  flex: 1;
  min-width: 0;
  height: 2.3rem;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--text);
  font-size: 0.9375rem;
  outline: none;
}
/* Sin la «×» nativa de type=search: ya está el botón de cerrar la búsqueda. */
.chat-search-input::-webkit-search-cancel-button,
.chat-search-input::-webkit-search-decoration { -webkit-appearance: none; appearance: none; display: none; }
.chat-search-spinner { width: 1rem; height: 1rem; color: var(--accent); }
.chat-search-status { padding: 0 1rem 0.35rem; color: var(--text-subtle); font-size: 0.78rem; }
.chat-search-status:empty { display: none; }
.chat-search-results { display: flex; flex-direction: column; min-height: 0; overflow-y: auto; padding: 0 0.5rem 0.4rem; }
.chat-search-results:empty { display: none; }
.chat-search-item {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  width: 100%;
  padding: 0.5rem 0.55rem;
  border: 0;
  border-radius: var(--radius);
  background: none;
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.chat-search-item:hover,
.chat-search-item:focus-visible { background: var(--surface-2); outline: none; }
.chat-search-item:focus-visible { box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--accent) 45%, transparent); }
.chat-search-item-body { display: flex; flex: 1; flex-direction: column; gap: 0.1rem; min-width: 0; }
.chat-search-item-head { display: flex; align-items: baseline; justify-content: space-between; gap: 0.5rem; color: var(--text-subtle); font-size: 0.75rem; }
.chat-search-item-name { overflow: hidden; color: var(--text); font-size: 0.8125rem; font-weight: 650; text-overflow: ellipsis; white-space: nowrap; }
.chat-search-item-text {
  display: -webkit-box;
  overflow: hidden;
  color: var(--text-muted);
  font-size: 0.85rem;
  line-height: 1.4;
  overflow-wrap: anywhere;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
}
.chat-search-item-text mark {
  padding: 0 0.1em;
  border-radius: 3px;
  background: color-mix(in srgb, var(--warning) 38%, transparent);
  color: var(--text);
}
.chat-search-more { align-self: center; margin: 0 0 0.6rem; font-size: 0.8125rem; }

/* --------------------------------------------------------------------------
   Composer: UNA sola caja (.composer-box) con, de arriba abajo, la barra de
   respuesta/edición, la bandeja de adjuntos sin enviar, y el campo con sus
   botones. Lo adjuntado o pegado queda dentro de la caja hasta pulsar Enter
   (o Enviar): la caja se realza con el acento y el botón muestra cuántos van.
   -------------------------------------------------------------------------- */
.composer {
  position: relative;
  flex: none;
  /* Abajo, 1,35 rem (SPEC §36: unos 10 px más arriba que antes) */
  padding: 0.35rem var(--chat-pad-x) calc(1.35rem + env(safe-area-inset-bottom, 0px));
  background: var(--bg);
}
.composer > * { max-width: var(--chat-max); margin-right: auto; margin-left: auto; }

.composer-box {
  --composer-tile: 4.75rem;
  position: relative;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--border);
  border-radius: 1.45rem;
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease), border-radius var(--dur) var(--ease);
}
/* Con algo encima del campo (respuesta o adjuntos) la caja crece: radio menos redondo. */
.composer.has-files .composer-box,
.composer.has-context .composer-box { border-radius: 1.15rem; }
.composer-box:focus-within {
  border-color: color-mix(in srgb, var(--accent) 50%, var(--border));
  box-shadow: var(--shadow-sm), var(--focus-ring);
}
/* Adjuntos preparados: anillo sutil del acento aunque el foco esté en otra parte. */
.composer.has-files .composer-box {
  border-color: color-mix(in srgb, var(--accent) 60%, var(--border));
  box-shadow: var(--shadow-sm), 0 0 0 1px color-mix(in srgb, var(--accent) 35%, transparent);
}
.composer.has-files .composer-box:focus-within { box-shadow: var(--shadow-sm), var(--focus-ring); }
/* Al pegar o soltar: una onda breve desde el borde de la caja */
.composer-box::after {
  content: "";
  position: absolute;
  inset: -1px;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
}
.composer.is-flash .composer-box::after { animation: composer-flash 650ms var(--ease); }
@keyframes composer-flash {
  from { opacity: 1; box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 55%, transparent); }
  to { opacity: 0; box-shadow: 0 0 0 0.65rem color-mix(in srgb, var(--accent) 0%, transparent); }
}

.composer-row {
  display: flex;
  align-items: flex-end;
  gap: 0.15rem;
  padding: 0.3rem;
}
.composer-btn {
  display: grid;
  flex: none;
  place-items: center;
  width: 2.3rem;
  height: 2.3rem;
  padding: 0;
  border: 0;
  border-radius: var(--radius-full);
  background: none;
  color: var(--text-muted);
  cursor: pointer;
  transition: background-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
.composer-btn:hover,
.composer-btn[aria-expanded="true"] { background: var(--surface-2); color: var(--text); }
.composer-btn:focus-visible { outline: none; box-shadow: var(--focus-ring); }
/* El color lo da el campo y lo heredan el textarea y la copia con los emojis encima (§43, emoji-field.js): cambian a la
   vez con el tema, el contraste y su transición */
.composer-field { display: flex; flex: 1; min-width: 0; color: var(--text); }
.composer-input {
  flex: 1;
  width: 100%;
  min-height: 2.3rem;
  margin: 0;
  padding: 0.5rem 0.35rem;
  border: 0;
  background: transparent;
  color: inherit;
  font-size: 0.9375rem;
  line-height: 1.35;
  resize: none;
  outline: none;
  overflow-y: hidden;
}
.composer-input::placeholder {
  overflow: hidden;
  color: var(--text-subtle);
  white-space: nowrap;           /* en columnas estrechas no parte «Escribe un mensaje…» en dos líneas */
  text-overflow: ellipsis;
}
/* Columnas estrechas del dock: botones algo más compactos para dejar sitio al texto. */
.composer { container: composer / inline-size; }
@container composer (max-width: 22rem) {
  .composer-row { gap: 0; padding: 0.2rem; }
  .composer-btn,
  .composer-send { width: 2.05rem; height: 2.05rem; }
  .composer-input { min-height: 2.05rem; padding: 0.4rem 0.25rem; }
  .composer-box { --composer-tile: 4rem; }
  .composer-tray { padding: 0.45rem 0.45rem 0.1rem; }
  .composer-file.is-doc { width: 10rem; }
  .composer-send.has-count { padding: 0 0.55rem 0 0.45rem; }
}
.composer-send {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  gap: 0.3rem;
  width: 2.3rem;
  height: 2.3rem;
  padding: 0;
  border: 0;
  border-radius: var(--radius-full);
  background: var(--accent);
  color: var(--accent-contrast);
  cursor: pointer;
  transition: background-color var(--dur) var(--ease), transform 90ms var(--ease), opacity var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.composer-send:hover:not(:disabled) { background: var(--accent-hover); }
.composer-send:active:not(:disabled) { transform: scale(0.93); }
.composer-send:disabled { background: var(--surface-3); color: var(--text-subtle); cursor: default; }
.composer-send:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.composer-save-icon { display: none; }
.composer.is-editing .composer-send-icon { display: none; }
.composer.is-editing .composer-save-icon { display: block; }
/* Con adjuntos preparados: píldora «➤ 2» con un halo del acento, que llama a enviar. */
.composer-send.has-count {
  width: auto;
  min-width: 2.3rem;
  padding: 0 0.75rem 0 0.65rem;
  box-shadow: 0 0 0 0.2rem var(--accent-soft);
  animation: composer-send-in 240ms var(--ease);
}
.composer-send.has-count:focus-visible { box-shadow: var(--focus-ring); }
.composer-send-count { font-size: 0.875rem; font-weight: 700; font-variant-numeric: tabular-nums; line-height: 1; }
@keyframes composer-send-in {
  from { transform: scale(0.85); }
  to { transform: none; }
}

.composer-context {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin: 0.35rem 0.35rem 0;
  padding: 0.3rem 0.25rem 0.3rem 0.65rem;
  border-left: 3px solid var(--accent);
  border-radius: 0.5rem 0.85rem 0.85rem 0.5rem;
  background: var(--surface-2);
  animation: chat-slide-up var(--dur-in) var(--ease);
}
@keyframes chat-slide-up {
  from { opacity: 0; transform: translateY(0.3rem); }
  to { opacity: 1; transform: none; }
}
.composer-context-icon { display: grid; flex: none; color: var(--accent-text); }
.composer-context-body { display: flex; flex: 1; flex-direction: column; min-width: 0; line-height: 1.35; }
.composer-context-title { color: var(--accent-text); font-size: 0.8125rem; font-weight: 650; }
.composer-context-text {
  overflow: hidden;
  color: var(--text-muted);
  font-size: 0.8125rem;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Bandeja de adjuntos sin enviar (dentro de la caja, encima del campo) */
.composer-tray {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  min-width: 0;
  padding: 0.55rem 0.6rem 0.15rem;
}
.composer-tray.is-entering { animation: composer-tray-in 220ms var(--ease); }
@keyframes composer-tray-in {
  from { opacity: 0; transform: translateY(0.35rem); }
  to { opacity: 1; transform: none; }
}
/* Recién enviado: «Enviando…» un instante y la bandeja se recoge */
.composer-tray.is-sending .composer-files { opacity: 0.5; transition: opacity 200ms var(--ease); }
.composer-tray.is-sending .composer-tray-icon { display: none; }
.composer-tray.is-leaving { animation: composer-tray-out 160ms var(--ease) forwards; }
@keyframes composer-tray-out {
  to { opacity: 0; transform: translateY(-0.3rem); }
}
.composer-tray-head {
  display: flex;
  flex-wrap: wrap;               /* en columnas muy estrechas, «Quitar todos» baja a otra línea */
  align-items: center;
  gap: 0.1rem 0.4rem;
  min-width: 0;
  min-height: 1.5rem;
  padding: 0 0.1rem 0 0.2rem;
  color: var(--text-muted);
  font-size: 0.75rem;
  line-height: 1.35;
}
.composer-tray-icon { display: grid; flex: none; color: var(--accent-text); }
.composer-tray-status { flex: 1 1 11rem; min-width: 0; margin: 0; }
/* Cada trozo se parte entero («Enter para enviar» no se separa) */
.composer-tray-count,
.composer-tray-errors,
.composer-tray-hint { white-space: nowrap; }
.composer-tray-hint.is-text { white-space: normal; }
.composer-tray-count { color: var(--text); font-weight: 650; }
.composer-tray-errors { color: var(--danger-text); font-weight: 650; }
.composer-tray-hint .kbd { margin: 0 0.05em; font-size: 0.9em; }
.composer-tray-sending { display: inline-flex; align-items: center; gap: 0.35rem; color: var(--accent-text); font-weight: 650; }
.composer-tray-spin { animation: cp-spin 0.9s linear infinite; }
.composer-tray-clear {
  flex: none;
  margin-left: auto;
  padding: 0.15rem 0.45rem;
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--text-muted);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  transition: background-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
.composer-tray-clear:hover { background: var(--danger-soft); color: var(--danger-text); }
.composer-tray-clear:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.composer.is-editing .composer-tray .composer-files { opacity: 0.6; }

.composer-files {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  min-width: 0;
  margin: 0;
  padding: 0.1rem 0.1rem 0.35rem;
  overflow-x: auto;
  scrollbar-width: thin;
}
.composer-file {
  position: relative;
  display: flex;
  flex: none;
  flex-direction: column;
  gap: 0.2rem;
  width: var(--composer-tile);
  animation: cp-pop-in var(--dur-in) var(--ease);
}
.composer-file-preview {
  position: relative;
  display: grid;
  place-items: center;
  width: 100%;
  height: var(--composer-tile);
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-2);
  color: var(--text-muted);
}
.composer-file-preview img,
.composer-file-preview video { width: 100%; height: 100%; object-fit: cover; }
/* Imágenes: sin ampliar (SPEC §9.6); el recorte (cover) solo si superan la ficha (lo decide el JS). */
.composer-file-preview img { object-fit: scale-down; }
.composer-file-preview.is-cover img { object-fit: cover; }
.composer-file-icon { display: grid; place-items: center; color: var(--accent-text); }
.composer-file-text { display: flex; flex-direction: column; gap: 0.05rem; min-width: 0; }
.composer-file-name {
  overflow: hidden;
  color: var(--text-muted);
  font-size: 0.6875rem;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.composer-file-meta { color: var(--text-subtle); font-size: 0.6875rem; line-height: 1.25; font-variant-numeric: tabular-nums; }
.composer-file.is-error .composer-file-meta {
  display: -webkit-box;
  overflow: hidden;
  color: var(--danger-text);
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
}
/* Documentos y audio: tarjeta con icono, nombre y tamaño (a la altura de las miniaturas) */
.composer-file.is-doc {
  flex-direction: row;
  align-items: center;
  gap: 0.55rem;
  width: 12rem;
  height: var(--composer-tile);
  padding: 0.45rem 1.75rem 0.45rem 0.45rem;
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-2);
}
.composer-file.is-doc .composer-file-preview {
  flex: none;
  width: 2.5rem;
  height: 2.5rem;
  border: 0;
  border-radius: var(--radius-sm);
  background: var(--accent-soft);
}
.composer-file.is-doc .composer-file-name {
  display: -webkit-box;
  color: var(--text);
  font-size: 0.75rem;
  font-weight: 550;
  line-height: 1.25;
  white-space: normal;
  overflow-wrap: anywhere;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
}
.composer-file.is-doc.is-error { border-color: var(--danger); }
.composer-file.is-doc.is-error .composer-file-name { -webkit-line-clamp: 1; }
.composer-file.is-doc .composer-file-progress { right: 0.5rem; bottom: 0.3rem; left: 0.5rem; }
.composer-file-progress {
  position: absolute;
  right: 0.4rem;
  bottom: 0.4rem;
  left: 0.4rem;
  height: 0.25rem;
  overflow: hidden;
  border-radius: var(--radius-full);
  background: color-mix(in srgb, var(--surface) 75%, transparent);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--text) 10%, transparent);
  opacity: 0;
  transition: opacity var(--dur) var(--ease);
}
.composer-file-progress::after {
  content: "";
  display: block;
  width: var(--p, 0%);
  height: 100%;
  border-radius: inherit;
  background: var(--accent);
  transition: width 200ms linear;
}
.composer-file.is-uploading .composer-file-progress { opacity: 1; }
.composer-file.is-media.is-error .composer-file-preview { border-color: var(--danger); }
.composer-file-retry,
.composer-file-alert {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
  padding: 0;
  border: 0;
  border-radius: inherit;
  background: color-mix(in srgb, var(--surface) 72%, transparent);
  color: var(--danger-text);
}
.composer-file-retry { cursor: pointer; transition: background-color var(--dur) var(--ease); }
.composer-file-retry:hover { background: color-mix(in srgb, var(--surface) 55%, transparent); }
.composer-file-retry:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--danger); }
/* Quitar (×): esquina superior derecha, dentro de la ficha. Sobre la foto va en negro translúcido
   con blanco (como los demás rótulos sobre imágenes); en las tarjetas, discreto. */
.composer-file-remove {
  position: absolute;
  top: 0.25rem;
  right: 0.25rem;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 1.375rem;
  height: 1.375rem;
  padding: 0;
  border: 0;
  border-radius: var(--radius-full);
  background: var(--media-scrim);
  color: #fff;
  cursor: pointer;
  transition: background-color var(--dur) var(--ease), transform 90ms var(--ease);
}
.composer-file-remove::before { content: ""; position: absolute; inset: -0.3rem; } /* zona táctil */
.composer-file-remove:hover { background: color-mix(in srgb, var(--media-scrim) 70%, #000); }
.composer-file-remove:active { transform: scale(0.9); }
.composer-file-remove:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.composer-file.is-doc .composer-file-remove { top: 0.3rem; right: 0.3rem; background: transparent; color: var(--text-muted); }
.composer-file.is-doc .composer-file-remove:hover { background: var(--surface-3); color: var(--text); }
.composer-tray.is-sending .composer-file-remove { visibility: hidden; }

.composer-recorder { padding: 0.3rem; }
.composer-recorder .voice-recorder { min-height: 2.3rem; padding: 0; background: transparent; }

/* Arrastrar archivos encima */
.chat.is-file-dragover .composer-box {
  border-color: var(--accent);
  box-shadow: var(--shadow-sm), var(--focus-ring);
}

/* --------------------------------------------------------------------------
   Variante «comments» (detalle de un item)
   -------------------------------------------------------------------------- */
.chat-comments {
  --chat-pad-x: 0.15rem;
  --chat-max: none;
  --chat-media-w: 13rem;
  --chat-media-max-h: 18rem;
  --chat-media-solo-w: var(--chat-media-w);
  --chat-media-solo-max-h: var(--chat-media-max-h);
  --bubble-radius: 0.95rem;
  --meta-w: 2.3rem;
  min-height: 14rem;
  background: transparent;
}
.chat-comments .chat-scroll { padding: 0 0 1.9rem; }
.chat-comments .chat-top { padding-top: 0.25rem; }
.chat-comments .msg-avatar { width: 1.5rem; }
.chat-comments .msg-content { max-width: 86%; }
.chat-comments .msg-bubble { padding: calc(0.32rem * var(--density) + 0.06rem) 0.65rem; font-size: 0.875rem; }
.chat-comments .msg.has-text .msg-meta { right: 0.6rem; bottom: calc(0.3rem * var(--density) + 0.08rem); }
.chat-comments .msg-jumbo { font-size: 2rem; }
.chat-comments .msg-jumbo-1 { font-size: 2.4rem; }
.chat-comments .chat-day-sep { margin-top: 0.6rem; }
.chat-comments .composer { padding: 0.4rem 0 0; background: transparent; }
.chat-comments .composer-box { --composer-tile: 3.75rem; border-radius: 1.2rem; }
.chat-comments .composer.has-files .composer-box,
.chat-comments .composer.has-context .composer-box { border-radius: 1rem; }
.chat-comments .composer-btn,
.chat-comments .composer-send { width: 2.05rem; height: 2.05rem; }
.chat-comments .composer-send.has-count { width: auto; padding: 0 0.6rem 0 0.5rem; }
.chat-comments .composer-input { min-height: 2.05rem; padding: 0.4rem 0.3rem; font-size: 0.875rem; }
.chat-comments .composer-tray { gap: 0.3rem; padding: 0.45rem 0.45rem 0.1rem; }
.chat-comments .composer-file.is-doc { width: 10.5rem; padding-top: 0.35rem; padding-bottom: 0.35rem; }
.chat-comments .composer-file.is-doc .composer-file-preview { width: 2.1rem; height: 2.1rem; }
.chat-comments .composer-file-name { font-size: 0.6875rem; }
.chat-comments .composer-context { margin: 0.3rem 0.3rem 0; }
.chat-comments .chat-empty { padding: 1.5rem 0.5rem; }
.chat-comments .chat-empty-icon { width: 2.75rem; height: 2.75rem; }
.chat-comments .chat-typing { left: 0.15rem; }
.chat-comments .chat-jump { right: 0.5rem; bottom: 0.5rem; width: 2.2rem; height: 2.2rem; }

/* --------------------------------------------------------------------------
   Pantallas estrechas y táctiles
   -------------------------------------------------------------------------- */
/* Píxel a píxel (SPEC §14.3): una imagen sola (o las de una fila) se ve a su tamaño 1:1 mientras quepa
   en la burbuja (38rem = el máximo de .msg-content; con max-width: 100 % manda la burbuja, mín(38rem,
   78 %) de la columna); de alto, mín(75vh, 48rem), para que una vertical no ocupe toda la pantalla. El
   mosaico de varias grandes sigue con --chat-media-w. */
/* Preferencia «Tamaño de las imágenes en el chat» (<html data-chat-image-size>; mismos valores que
   CHAT_IMAGE_SIZES de chat/attachments.js). «Medianas» es el valor por defecto. */
.chat { --chat-media-solo-w: 26rem; --chat-media-solo-max-h: min(60vh, 32rem); }
.chat-comments { --chat-media-solo-w: 20rem; --chat-media-solo-max-h: min(55vh, 24rem); }
:root[data-chat-image-size="large"] .chat { --chat-media-solo-w: 38rem; --chat-media-solo-max-h: min(75vh, 48rem); }
:root[data-chat-image-size="large"] .chat-comments { --chat-media-solo-w: 30rem; --chat-media-solo-max-h: min(60vh, 30rem); }
:root[data-chat-image-size="small"] .chat { --chat-media-solo-w: 16rem; --chat-media-solo-max-h: min(50vh, 20rem); --chat-media-w: 16rem; }
:root[data-chat-image-size="small"] .chat-comments { --chat-media-solo-w: 13rem; --chat-media-solo-max-h: min(45vh, 16rem); }

@media (max-width: 640px) {
  .chat { --chat-pad-x: 0.6rem; --chat-media-w: 16rem; }
  .msg-content { max-width: 84%; }
  .msg-avatar { width: 1.75rem; }
  .composer-btn { width: 2.15rem; }
}

@media (hover: none) {
  /* En táctil, las acciones de los adjuntos están en la pulsación larga (menú del mensaje) */
  .att-expand { opacity: 0.92; }
  .reaction-add { display: none; }
  .msg-bubble { -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
  .md-pre { -webkit-user-select: text; user-select: text; }
}

@media (prefers-reduced-motion: reduce) {
  .chat *,
  .chat *::before,
  .chat *::after { animation-duration: 1ms !important; animation-delay: 0s !important; transition-duration: 1ms !important; }
  .composer-tray-spin { animation: none !important; }
  .composer.is-flash .composer-box::after { animation: none; }
  .msg-sending { opacity: 1; }
  .chat-typing { opacity: 1; }
}

/* ==========================================================================
   Ronda 5 (SPEC §13): votaciones, fijados, enlaces internos y comentarios
   clavados en la imagen. Colores suaves con los tokens de siempre; dentro de la
   burbuja propia (tinte del acento) las superficies van en --bubble-own-inset y
   el texto secundario en --bubble-own-meta.
   ========================================================================== */

/* Aviso con acción («Deshacer», «Ir al chat») */
.chat-toast-body { display: flex; align-items: center; gap: 0.85rem; }
.chat-toast-text { min-width: 0; }
.chat-toast-action {
  flex: none;
  padding: 0.25rem 0.6rem;
  border: 0;
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--toast-text) 12%, transparent);
  color: color-mix(in srgb, var(--accent) 45%, var(--toast-text));
  font: inherit;
  font-size: 0.8125rem;
  font-weight: 700;
  cursor: pointer;
}
.chat-toast-action:hover { background: color-mix(in srgb, var(--toast-text) 20%, transparent); }
.chat-toast-action:focus-visible { outline: 2px solid var(--toast-text); outline-offset: 1px; }

/* --------------------------------------------------------------------------
   Votación (tarjeta dentro de la burbuja)
   -------------------------------------------------------------------------- */
.msg.has-poll .msg-content { flex: 0 1 24rem; }
.msg.has-poll:has(.poll.is-images) .msg-content { flex-basis: 28rem; }
.msg.has-poll .msg-bubble { width: 100%; }
.poll {
  --poll-inset: var(--surface-2);
  --poll-fill: color-mix(in srgb, var(--accent) 16%, transparent);
  --poll-fill-mine: color-mix(in srgb, var(--accent) 30%, transparent);
  --poll-muted: var(--text-muted);
  --poll-strong: var(--text);       /* lo que puede quedar sobre la barra (porcentaje): ≥ 4,5:1 también ahí */
  display: flex;
  flex-direction: column;
  min-width: 0;
  padding: 0.15rem 0 0.1rem;
}
.msg.is-own .poll { --poll-inset: var(--bubble-own-inset); --poll-muted: var(--bubble-own-meta); --poll-strong: var(--bubble-own-text); }
:root[data-theme="dark"] .poll { --poll-fill: color-mix(in srgb, var(--accent) 18%, transparent); --poll-fill-mine: color-mix(in srgb, var(--accent) 28%, transparent); }
.poll-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem 0.4rem;
  color: var(--poll-muted);
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.3;
}
.poll-icon { display: grid; color: var(--accent-text); }
.poll-state { margin-left: auto; }
.poll-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.1rem 0.45rem;
  border-radius: var(--radius-full);
  background: var(--poll-inset);
  color: var(--poll-muted);
  font-size: 0.7rem;
  font-weight: 650;
  white-space: nowrap;
}
.poll-chip.is-closed { background: var(--surface-3); color: var(--text); }
.msg.is-own .poll-chip.is-closed { background: var(--bubble-own-inset); color: var(--bubble-own-text); }
.poll-question {
  margin: 0.3rem 0 0.55rem;
  font-size: 1rem;
  font-weight: 650;
  line-height: 1.35;
  overflow-wrap: anywhere;
}
.poll-fieldset { min-width: 0; margin: 0; padding: 0; border: 0; }
.poll-options { display: flex; flex-direction: column; gap: 0.35rem; }

/* Una opción: fila con la barra de resultado detrás */
.poll-choice {
  position: relative;
  z-index: 0;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 2.35rem;
  padding: 0.35rem 0.6rem;
  overflow: hidden;
  border-radius: var(--radius-sm);
  background: var(--poll-inset);
  cursor: pointer;
  transition: box-shadow var(--dur) var(--ease);
}
.poll-choice:hover { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 45%, transparent); }
.poll.is-closed .poll-choice { cursor: default; }
.poll.is-closed .poll-choice:hover { box-shadow: none; }
.poll-input {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  opacity: 0;
  pointer-events: none;
}
.poll-check {
  display: grid;
  flex: none;
  place-items: center;
  width: 1.15rem;
  height: 1.15rem;
  border: 2px solid var(--border-strong);
  border-radius: 50%;
  background: var(--surface);
  color: transparent;
  transition: background-color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.poll-check.is-box { border-radius: 0.3rem; }
.poll-check svg { width: 0.75rem; height: 0.75rem; stroke-width: 3; }
.poll-input:checked + .poll-check { border-color: var(--accent); background: var(--accent); color: var(--accent-contrast); }
.poll-input:focus-visible + .poll-check { box-shadow: var(--focus-ring); }
.poll-input:disabled + .poll-check { opacity: 0.75; }
.poll.is-closed .poll-input:not(:checked) + .poll-check { visibility: hidden; width: 0; margin-right: -0.5rem; border-width: 0; }
.poll-label {
  flex: 1;
  min-width: 0;
  font-size: 0.875rem;
  line-height: 1.35;
  overflow-wrap: break-word;   /* palabras enteras (con «anywhere» la columna se encogía y partía «Miniatura») */
  hyphens: auto;
}
.poll-faces { display: inline-flex; flex: none; align-items: center; padding-left: 0.3rem; }
.poll-faces:empty { display: none; }
.poll-face { --avatar-ring: var(--poll-inset); margin-left: -0.3rem; }
.poll-more { margin-left: 0.15rem; color: var(--poll-strong); font-size: 0.7rem; font-weight: 650; }
.poll-pct {
  flex: none;
  min-width: 2.6rem;
  color: var(--poll-strong);
  font-size: 0.8125rem;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  text-align: right;
}
.poll-bar { position: absolute; inset: 0; z-index: -1; pointer-events: none; }
.poll-bar > i {
  display: block;
  width: var(--pct, 0%);
  height: 100%;
  background: var(--poll-fill);
  transition: width 320ms var(--ease);
}
.poll-opt.is-mine .poll-bar > i { background: var(--poll-fill-mine); }
.poll-opt.is-mine .poll-label { font-weight: 600; }
.poll-opt.is-winner .poll-label { font-weight: 700; }
.poll-opt.is-winner .poll-pct { font-weight: 750; }

/* Opciones de imagen: cuadrícula (todas imágenes) o miniatura a la izquierda (mezcla) */
.poll.is-images .poll-options { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.5rem; }
.poll-opt.is-image { display: flex; flex-direction: column; gap: 0.3rem; min-width: 0; }
.poll-opt.is-image .poll-choice { min-height: 2.1rem; padding: 0.3rem 0.5rem; }
.poll-opt.is-image .poll-label { font-size: 0.8125rem; }
.poll-opt.is-image .poll-pct { min-width: 0; }
.poll-opt.is-image .poll-faces { display: none; } /* en la cuadrícula no caben: van en el texto para lectores */
.poll-opt.has-thumb { display: flex; align-items: stretch; gap: 0.4rem; }
.poll-opt.has-thumb .poll-choice { flex: 1; }
.poll-img {
  position: relative;
  display: grid;
  flex: none;
  place-items: center;
  padding: 0;
  overflow: hidden;
  border: 0;
  border-radius: var(--radius-sm);
  background: var(--poll-inset);
  color: var(--poll-muted);
  cursor: zoom-in;
}
.poll-img.is-large { width: 100%; aspect-ratio: 1; }
.poll-img.is-thumb { width: 2.75rem; min-height: 2.35rem; }
/* Sin ampliar (SPEC §9.6): entera y como mucho a su tamaño natural; recorte solo si llena el hueco. */
.poll-img img {
  max-width: min(100%, var(--nat-w, 100%));
  max-height: min(100%, var(--nat-h, 100%));
  object-fit: scale-down;
}
.poll-img.is-large img { width: auto; height: auto; }
.poll-img.is-cover img { width: 100%; height: 100%; max-width: none; max-height: none; object-fit: cover; }
.poll-img:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.poll-opt.is-mine .poll-img { box-shadow: 0 0 0 2px var(--accent); }
.poll-img-broken { display: grid; place-items: center; }

.poll-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.2rem 0.9rem;
  margin-top: 0.55rem;
  color: var(--poll-muted);
  font-size: 0.78rem;
}
.poll-total { margin-right: auto; font-variant-numeric: tabular-nums; }
.poll-foot .chat-link { font-size: 0.78rem; }
.poll-close { color: var(--poll-muted); }
.poll-close:hover { color: var(--text); }

@container chat-scroll (max-width: 24rem) {
  .msg.has-poll .msg-content { flex-basis: 100%; }
  .poll.is-images .poll-options { gap: 0.35rem; }
  .poll-pct { min-width: 2.2rem; }
}

/* --------------------------------------------------------------------------
   Diálogo «Crear votación» y selector de imágenes de Archivos
   -------------------------------------------------------------------------- */
.poll-edit { display: flex; flex-direction: column; gap: 1rem; }
.poll-edit-alerts { display: flex; flex-direction: column; gap: 0.5rem; }
.poll-edit-alerts:empty { display: none; }
.poll-edit-list { display: flex; flex-direction: column; gap: 0.45rem; margin: 0.35rem 0 0; padding: 0; list-style: none; }
.poll-edit-row { display: flex; align-items: center; gap: 0.5rem; }
.poll-edit-num {
  display: grid;
  flex: none;
  place-items: center;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  background: var(--surface-2);
  color: var(--text-muted);
  font-size: 0.75rem;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
}
.poll-edit-input { flex: 1; min-width: 0; }
.poll-edit-thumb {
  position: relative;
  display: grid;
  flex: none;
  place-items: center;
  width: 2.6rem;
  height: 2.6rem;
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--text-muted);
}
.poll-edit-thumb img { max-width: 100%; max-height: 100%; object-fit: scale-down; }
.poll-edit-thumb.is-cover img { width: 100%; height: 100%; object-fit: cover; }
.poll-edit-thumb.is-error { border-color: var(--danger); }
.poll-edit-progress {
  position: absolute;
  right: 0.2rem;
  bottom: 0.2rem;
  left: 0.2rem;
  height: 0.2rem;
  overflow: hidden;
  border-radius: var(--radius-full);
  background: color-mix(in srgb, var(--surface) 70%, transparent);
  opacity: 0;
}
.poll-edit-progress::after { content: ""; display: block; width: var(--p, 0%); height: 100%; background: var(--accent); }
.poll-edit-thumb.is-uploading .poll-edit-progress { opacity: 1; }
.poll-edit-remove { flex: none; color: var(--text-muted); }
.poll-edit-actions { display: flex; flex-wrap: wrap; gap: 0.35rem; margin-top: 0.45rem; }
.poll-edit-hint { margin: 0.35rem 0 0; color: var(--text-subtle); font-size: 0.8125rem; }
.poll-edit-hint.is-warning { color: var(--warning-text); }
.poll-edit-error:empty { display: none; }
.poll-edit-switch {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}
.poll-edit-switch label { display: flex; flex-direction: column; gap: 0.1rem; cursor: pointer; }
.poll-edit-switch-title { font-weight: 600; }
.poll-edit-switch-desc { color: var(--text-muted); font-size: 0.8125rem; }
.poll-edit-date { margin-top: 0.45rem; }

.poll-pick { display: flex; flex-direction: column; gap: 0.75rem; min-height: 18rem; }
.poll-pick-bar { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.poll-pick-searchbox {
  display: flex;
  flex: 1 1 14rem;
  align-items: center;
  gap: 0.4rem;
  padding-left: 0.65rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text-subtle);
}
.poll-pick-searchbox:focus-within { border-color: color-mix(in srgb, var(--accent) 55%, var(--border)); box-shadow: var(--focus-ring); }
.poll-pick-search.input { flex: 1; min-width: 0; border: 0; box-shadow: none; background: transparent; }
.poll-pick-search.input:focus { box-shadow: none; outline: none; }
.poll-pick-status { margin: 0; color: var(--text-muted); font-size: 0.875rem; }
.poll-pick-status:empty { display: none; }
.poll-pick-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr)); gap: 0.6rem; }
.poll-pick-tile {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  min-width: 0;
  padding: 0.35rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.poll-pick-tile:hover { border-color: var(--border-strong); }
.poll-pick-tile:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.poll-pick-tile.is-selected { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.poll-pick-tile.is-full { opacity: 0.55; }
.poll-pick-thumb {
  display: grid;
  place-items: center;
  width: 100%;
  aspect-ratio: 1;
  overflow: hidden;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--text-muted);
}
.poll-pick-thumb img { max-width: 100%; max-height: 100%; object-fit: scale-down; }
.poll-pick-thumb.is-cover img { width: 100%; height: 100%; object-fit: cover; }
.poll-pick-check {
  position: absolute;
  top: 0.55rem;
  right: 0.55rem;
  display: grid;
  place-items: center;
  width: 1.45rem;
  height: 1.45rem;
  border: 2px solid var(--surface);
  border-radius: 50%;
  background: color-mix(in srgb, var(--surface) 70%, transparent);
  box-shadow: var(--shadow-sm);
  color: transparent;
}
.poll-pick-tile.is-selected .poll-pick-check { background: var(--accent); color: var(--accent-contrast); }
.poll-pick-title { overflow: hidden; font-size: 0.8125rem; font-weight: 550; text-overflow: ellipsis; white-space: nowrap; }
.poll-pick-more { align-self: center; }
.poll-pick-modal .modal-footer { align-items: center; }
.poll-pick-count { margin-right: auto; color: var(--text-muted); font-size: 0.8125rem; }

/* --------------------------------------------------------------------------
   Fijados: chincheta en la burbuja, barra bajo la cabecera y panel con la lista
   -------------------------------------------------------------------------- */
.msg-pinned { display: inline-flex; align-items: center; margin-right: 0.1rem; color: var(--accent-text); }
.msg-pinned svg { width: 0.75rem; height: 0.75rem; }
.msg.is-own .msg-pinned { color: var(--bubble-own-meta); }
.msg.is-media-only .msg-pinned { color: inherit; }
.msg-bubble.meta-pinned { --meta-w: 3.45rem; }
.msg-bubble.meta-own.meta-pinned { --meta-w: 4.45rem; }
.msg-bubble.meta-edited.meta-pinned { --meta-w: 6.4rem; }
.msg-bubble.meta-own.meta-edited.meta-pinned { --meta-w: 7.4rem; }

.chat-pins {
  display: flex;
  flex: none;
  align-items: center;
  gap: 0.45rem;
  width: 100%;
  min-height: 2.1rem;
  padding: 0.3rem 0.75rem 0.3rem var(--chat-pad-x);
  border: 0;
  border-bottom: 1px solid var(--border);
  background: var(--bg-elevated);
  color: var(--text-muted);
  font: inherit;
  font-size: 0.8125rem;
  text-align: left;
  cursor: pointer;
  transition: background-color var(--dur) var(--ease);
}
.chat-pins[hidden] { display: none; }
.chat-pins:hover, .chat-pins.is-open { background: var(--surface-2); }
.chat-pins:focus-visible { outline: none; box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--accent) 55%, transparent); }
.chat-pins-icon { display: grid; flex: none; color: var(--accent-text); }
.chat-pins-count { flex: none; color: var(--text); font-weight: 650; }
.chat-pins-last { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-pins-last::before { content: "· "; }
.chat-pins-chevron { display: grid; flex: none; margin-left: auto; transition: transform var(--dur) var(--ease); }
.chat-pins.is-open .chat-pins-chevron { transform: rotate(180deg); }

.chat-pins-panel {
  position: relative;
  z-index: 4;
  display: flex;
  flex: none;
  flex-direction: column;
  max-height: min(26rem, 60%);
  border-bottom: 1px solid var(--border);
  background: var(--bg-elevated);
  box-shadow: var(--shadow-sm);
  animation: chat-slide-down var(--dur-in) var(--ease);
}
.chat-pins-panel[hidden] { display: none; }
.chat-pins-panel-head { display: flex; align-items: center; justify-content: space-between; padding: 0.4rem 0.5rem 0.2rem 1rem; }
.chat-pins-panel-title { display: flex; align-items: center; gap: 0.4rem; margin: 0; font-size: 0.875rem; font-weight: 650; }
.chat-pins-panel-title svg { color: var(--accent-text); }
.chat-pins-status { margin: 0; padding: 0 1rem 0.6rem; color: var(--text-subtle); font-size: 0.8125rem; }
.chat-pins-status:empty { display: none; }
.chat-pins-list { display: flex; flex-direction: column; min-height: 0; margin: 0; padding: 0 0.5rem 0.5rem; overflow-y: auto; list-style: none; }
.chat-pins-item { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 0 0.25rem; border-radius: var(--radius); }
.chat-pins-item:hover { background: var(--surface-2); }
.chat-pins-item-main {
  display: flex;
  flex: 1 1 15rem;
  align-items: flex-start;
  gap: 0.6rem;
  min-width: 0;
  padding: 0.5rem 0.4rem 0.5rem 0.55rem;
  border: 0;
  border-radius: var(--radius);
  background: none;
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.chat-pins-item-main:focus-visible { outline: none; box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--accent) 45%, transparent); }
.chat-pins-avatar { flex: none; margin-top: 0.1rem; }
.chat-pins-item-body { display: flex; flex: 1; flex-direction: column; gap: 0.1rem; min-width: 0; }
.chat-pins-item-head { display: flex; align-items: baseline; gap: 0.5rem; color: var(--text-subtle); font-size: 0.75rem; }
.chat-pins-item-name { overflow: hidden; color: var(--text); font-size: 0.8125rem; font-weight: 650; text-overflow: ellipsis; white-space: nowrap; }
.chat-pins-item-text {
  display: -webkit-box;
  overflow: hidden;
  color: var(--text-muted);
  font-size: 0.85rem;
  line-height: 1.4;
  overflow-wrap: anywhere;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
}
.chat-pins-item-by { display: inline-flex; align-items: center; gap: 0.25rem; color: var(--text-subtle); font-size: 0.72rem; }
.chat-pins-thumb {
  display: grid;
  flex: none;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  overflow: hidden;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--text-muted);
}
.chat-pins-thumb img { max-width: 100%; max-height: 100%; object-fit: scale-down; }
.chat-pins-thumb.is-cover img { width: 100%; height: 100%; object-fit: cover; }
.chat-pins-item-actions { display: flex; flex: none; flex-direction: column; align-items: flex-end; gap: 0.35rem; margin-left: auto; padding: 0.55rem 0.55rem 0.4rem 0.2rem; }
.chat-pins-item-actions .chat-link { font-size: 0.78rem; }
.chat-pins-unpin { color: var(--text-muted); }
.chat-pins-unpin:hover { color: var(--danger-text); }

/* --------------------------------------------------------------------------
   Enlaces internos: tarjetas de vista previa (mensaje, item, sala)
   -------------------------------------------------------------------------- */
.msg.has-links .msg-bubble { min-width: min(17rem, 100%); }
.link-cards { display: flex; flex-direction: column; gap: 0.35rem; margin: 0.4rem 0 0.1rem; }
.link-card {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  min-height: 3.35rem;
  padding: 0.45rem 0.6rem 0.45rem 0.55rem;
  border: 1px solid color-mix(in srgb, var(--border) 80%, transparent);
  border-left: 3px solid color-mix(in srgb, var(--accent) 70%, var(--border));
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--text);
  text-decoration: none;
  transition: background-color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.link-card:hover { background: var(--surface-3); }
.link-card:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.msg.is-own .link-card { border-color: transparent; border-left-color: color-mix(in srgb, var(--accent) 70%, transparent); background: var(--bubble-own-inset); }
.msg.is-own .link-card:hover { background: color-mix(in srgb, var(--bubble-own-inset) 70%, var(--surface)); }
.link-card.is-denied { border-left-color: var(--border-strong); color: var(--text-muted); }
.link-card-body { display: flex; flex: 1; flex-direction: column; gap: 0.1rem; min-width: 0; line-height: 1.35; }
.link-card-head { display: flex; align-items: baseline; gap: 0.45rem; min-width: 0; }
.link-card-title { overflow: hidden; font-size: 0.8125rem; font-weight: 650; text-overflow: ellipsis; white-space: nowrap; }
.link-card-time { flex: none; margin-left: auto; color: var(--text-subtle); font-size: 0.72rem; }
.msg.is-own .link-card-time { color: var(--bubble-own-meta); }
.link-card-text {
  display: -webkit-box;
  overflow: hidden;
  color: var(--text-muted);
  font-size: 0.8125rem;
  overflow-wrap: anywhere;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
}
.link-card-text.is-deleted { font-style: italic; }
.msg.is-own .link-card-text, .msg.is-own .link-card-meta { color: var(--bubble-own-meta); }
.link-card-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.15rem 0.5rem;
  min-width: 0;
  color: var(--text-muted);
  font-size: 0.75rem;
}
.link-card-meta-item { display: inline-flex; align-items: center; gap: 0.25rem; min-width: 0; overflow: hidden; color: inherit; font-size: 0.75rem; text-overflow: ellipsis; white-space: nowrap; }
.link-card-head .link-card-meta-item { color: var(--text-subtle); }
.msg.is-own .link-card-head .link-card-meta-item { color: var(--bubble-own-meta); }
.link-card-tag { padding: 0 0.4rem; border-radius: var(--radius-full); background: var(--surface-3); color: var(--text-muted); font-size: 0.7rem; }
.msg.is-own .link-card-tag { background: color-mix(in srgb, var(--bubble-own-text) 8%, transparent); color: var(--bubble-own-text); }
.link-card-icon {
  display: grid;
  flex: none;
  place-items: center;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: var(--radius-sm);
  background: var(--accent-soft);
  color: var(--accent-text);
}
.link-card.is-denied .link-card-icon { background: var(--surface-3); color: var(--text-muted); }
.link-card-avatar, .link-card-glyph { flex: none; }
.link-card-thumb {
  display: grid;
  flex: none;
  place-items: center;
  width: 2.6rem;
  height: 2.6rem;
  overflow: hidden;
  border-radius: var(--radius-sm);
  background: var(--surface-3);
  color: var(--text-muted);
}
.link-card-thumb img { max-width: 100%; max-height: 100%; object-fit: scale-down; }
.link-card-thumb.is-cover img { width: 100%; height: 100%; object-fit: cover; }
.link-card-line { display: block; width: 70%; height: 0.7rem; border-radius: var(--radius-full); }
.link-card-line.is-short { width: 45%; margin-top: 0.3rem; }
.link-cards.is-compact .link-card { min-height: 2.9rem; padding-top: 0.35rem; padding-bottom: 0.35rem; }
.link-cards.is-compact .link-card-text { -webkit-line-clamp: 1; }
/* En el composer: tarjetas compactas encima del campo, antes de enviar */
.composer-links { padding: 0.45rem 0.55rem 0; }
.composer-links[hidden] { display: none; }
.link-cards.in-composer { margin: 0; }

/* --------------------------------------------------------------------------
   Comentarios clavados en la imagen (hilos)
   -------------------------------------------------------------------------- */
.msg-anchor-row { display: flex; align-items: center; gap: 0.55rem; margin: 0.1rem 0 0.35rem; }
.msg-anchor {
  display: inline-flex;
  align-items: center;
  gap: 0.2rem;
  height: 1.45rem;
  padding: 0 0.5rem 0 0.35rem;
  border: 0;
  border-radius: var(--radius-full);
  background: color-mix(in srgb, var(--user-color) 15%, transparent);
  color: color-mix(in srgb, var(--user-color) var(--name-mix, 50%), var(--text));
  font: inherit;
  font-size: 0.75rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
}
.msg-anchor:hover { background: color-mix(in srgb, var(--user-color) 24%, transparent); }
.msg-anchor:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.msg-anchor.is-resolved { background: var(--surface-3); color: var(--text-muted); }
.msg.is-own .msg-anchor.is-resolved { background: var(--bubble-own-inset); color: var(--bubble-own-meta); }
.msg-anchor-state { margin-left: 0.15rem; font-weight: 600; }
.msg-anchor-crop {
  position: relative;
  flex: none;
  width: 4.5rem;
  height: 4.5rem;
  padding: 0;
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  cursor: zoom-in;
}
/* La miniatura a su tamaño natural (nunca ampliada), con el punto en el centro del recorte. */
.msg-anchor-crop img {
  position: absolute;
  top: 50%;
  left: 50%;
  width: auto;
  max-width: none;
  height: auto;
  max-height: none;
  transform: translate(calc(-1 * var(--ax, 50%)), calc(-1 * var(--ay, 50%)));
}
/* Ya medida (JS): recorte dentro de la imagen y el marcador en el punto real */
.msg-anchor-crop.is-placed img { top: var(--img-top); left: var(--img-left); transform: none; }
.msg-anchor-crop.is-placed .msg-anchor-dot { top: var(--dot-top); left: var(--dot-left); }
.msg-anchor-crop.is-resolved img { opacity: 0.6; filter: grayscale(0.5); }
.msg-anchor-crop:focus-visible { outline: none; box-shadow: var(--focus-ring); }
/* Marcador sobre la foto: círculo del color del autor con anillo blanco (igual en ambos temas). */
.msg-anchor-dot {
  position: absolute;
  top: 50%;
  left: 50%;
  display: grid;
  place-items: center;
  min-width: 1.3rem;
  height: 1.3rem;
  padding: 0 0.2rem;
  border: 2px solid #fff;
  border-radius: var(--radius-full);
  background: var(--user-color);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.35);
  color: #fff;
  font-size: 0.68rem;
  font-weight: 800;
  line-height: 1;
  text-shadow: 0 0 2px rgba(0, 0, 0, 0.6);
  transform: translate(-50%, -50%);
}
.msg-anchor-crop.is-resolved .msg-anchor-dot { background: var(--text-subtle); }

/* Barra «Punto N · Este punto | Todos» (filtro de la conversación de un punto) */
.chat-anchor-bar {
  display: flex;
  flex: none;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.35rem 0.75rem;
  padding: 0.35rem var(--chat-pad-x);
  border-bottom: 1px solid var(--border);
  background: color-mix(in srgb, var(--accent-soft) 60%, var(--bg));
  font-size: 0.8125rem;
}
.chat-anchor-bar[hidden] { display: none; }
.chat-comments .chat-anchor-bar { margin-bottom: 0.25rem; padding: 0.3rem 0.5rem; border: 0; border-radius: var(--radius); }
.chat-anchor-label { display: inline-flex; align-items: center; gap: 0.3rem; color: var(--accent-text); }
.chat-anchor-label.is-resolved { color: var(--text-muted); }
.chat-anchor-count { color: var(--text-muted); }
.chat-anchor-choices { display: inline-flex; padding: 0.15rem; border-radius: var(--radius-full); background: var(--surface); box-shadow: inset 0 0 0 1px var(--border); }
.chat-anchor-choice {
  padding: 0.15rem 0.65rem;
  border: 0;
  border-radius: var(--radius-full);
  background: none;
  color: var(--text-muted);
  font: inherit;
  font-size: 0.78rem;
  font-weight: 600;
  cursor: pointer;
}
.chat-anchor-choice[aria-pressed="true"] { background: var(--accent); color: var(--accent-contrast); }
.chat-anchor-choice:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* --------------------------------------------------------------------------
   Composer: un solo «+» con Archivos, Emoji y Votación (SPEC §36)
   -------------------------------------------------------------------------- */
.menu.composer-plus-menu { min-width: 12rem; }

@media (prefers-reduced-motion: reduce) {
  .poll-bar > i { transition: none; }
}

/* ---------------------------------------------------------------------------
   Comentarios de los archivos catalogados (SPEC §15.5 y §15.6; chat/file-comments.js)
   --------------------------------------------------------------------------- */
/* Insignia «💬 N»: abajo a la izquierda de la imagen (arriba a la derecha sale la barra del mensaje), junto
   a «Ver en grande» en el vídeo y en la línea de la tarjeta de archivo o del audio. */
.att-comments {
  position: absolute;
  bottom: 0.4rem;
  left: 0.4rem;
  z-index: 3;
  display: inline-flex;
  align-items: center;
  gap: 0.2rem;
  height: 1.5rem;
  padding: 0 0.45rem;
  border: 0;
  border-radius: 999px;
  background: var(--media-scrim);
  color: #fff;
  font: inherit;
  font-size: 0.75rem;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  cursor: pointer;
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
  transition: background var(--dur) var(--ease);
}
.att-video > .att-comments { top: 0.35rem; bottom: auto; left: 2.45rem; }
.att-comments:hover { background: color-mix(in srgb, var(--accent) 78%, #000); }
.att-comments:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.att-comments.has-unread::after {
  content: "";
  width: 0.45rem;
  height: 0.45rem;
  margin-left: 0.1rem;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 1.5px #fff;
}
.att-file > .att-comments,
.att-audio > .att-comments {
  position: static;
  flex: none;
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  color: var(--accent-text);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
.att-file > .att-comments:hover,
.att-audio > .att-comments:hover { background: color-mix(in srgb, var(--accent) 24%, transparent); }
.att-file > .att-comments.has-unread::after,
.att-audio > .att-comments.has-unread::after { box-shadow: none; }
.att-audio:has(> .att-comments) { display: flex; align-items: center; gap: 0.35rem; }
.att-audio:has(> .att-comments) > .audio-player { flex: 1; }

/* Puntos comentados sobre la imagen del chat: los de la ficha, en pequeño (la capa es .lib-pins). */
.att-pins .lib-pin { --pin-size: 1.3rem; border-width: 1.5px; font-size: 0.6875rem; }
.chat-comments .att-pins .lib-pin { --pin-size: 1.15rem; font-size: 0.625rem; }
/* Globos de esos puntos: por encima de la lista (que recorta), sin capturar el ratón. */
.att-pins-float { position: fixed; inset: 0; z-index: 60; pointer-events: none; }

/* Archivo de Chatper (tarjeta de una pestaña de archivos, adjunto de otro mensaje) arrastrado sobre el chat:
   la caja de texto se ilumina, que es donde quedará adjunto hasta enviar (SPEC §16.12). */
.chat.is-file-drop-target .composer-box { box-shadow: 0 0 0 1.5px color-mix(in srgb, var(--accent) 45%, transparent); }
.chat.is-file-drop-over .composer-box { box-shadow: 0 0 0 2px var(--accent), 0 0 0 6px var(--accent-soft); }

/* SPEC §17.3: el cursor de escritura, del color de acento */
.composer textarea, .chat textarea { caret-color: var(--accent); }

/* SPEC §44: comentarios de los archivos en el chat de la sala (una tarjeta por archivo, en su último comentario) */
.chat-file-activity {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  width: min(100%, 34rem);
  margin: 0.4rem auto;
  padding: 0.5rem 0.6rem 0.5rem 0.55rem;
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: background-color var(--dur) var(--ease);
}
.chat-file-activity:hover { background: var(--surface-2); }
.chat-file-activity:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.chat-file-activity-thumb {
  display: grid;
  flex: none;
  place-items: center;
  width: 2.5rem;
  height: 2.5rem;
  overflow: hidden;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--text-muted);
}
.chat-file-activity-thumb img { width: 100%; height: 100%; object-fit: cover; }
.chat-file-activity-body { display: flex; flex: 1; flex-direction: column; gap: 0.1rem; min-width: 0; }
.chat-file-activity-head { display: flex; align-items: center; gap: 0.35rem; min-width: 0; font-size: 0.8125rem; }
.chat-file-activity-head svg { flex: none; color: var(--accent-text); }
.chat-file-activity-title { min-width: 0; overflow: hidden; color: var(--text); font-weight: 600; text-overflow: ellipsis; white-space: nowrap; }
.chat-file-activity-new { flex: none; padding: 0 0.4rem; border-radius: var(--radius-full); background: var(--accent); color: var(--accent-contrast); font-size: 0.7rem; font-weight: 700; line-height: 1.35rem; }
.chat-file-activity-last { overflow: hidden; color: var(--text-muted); font-size: 0.875rem; text-overflow: ellipsis; white-space: nowrap; }
.chat-file-activity.is-unread .chat-file-activity-last { color: var(--text); }
.chat-file-activity-side { display: flex; flex: none; flex-direction: column; align-items: flex-end; gap: 0.25rem; color: var(--text-subtle); font-size: 0.75rem; }
.chat-file-activity-open {
  padding: 0.1rem 0.6rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-full);
  background: var(--surface-2);
  color: var(--text);
  font-weight: 600;
}
