/* SuperLawyer Terminal — hoja de estilo única.
   Papel de imprenta, verde de sumario y oro de subrayado: la misma paleta que la
   landing, para que el terminal y la web se lean como el mismo producto. El oro
   marca siempre lo mismo, una cita a la ley. Sin dependencias externas: la única
   tipografía de marca (Spectral, la del rótulo de la landing) va servida desde
   /static, así que sigue sin haber petición a terceros que declarar —la política
   de privacidad lo afirma por escrito. */

/* Spectral 600, subconjunto latino, copiado de Google Fonts a mano para NO
   cargarlo desde fonts.gstatic.com. Licencia SIL OFL 1.1 en fonts/. Es la misma
   fuente y el mismo peso con que la landing compone «SuperLawyer.»: el rótulo
   tiene que ser el mismo objeto en las dos superficies. */
@font-face {
  font-family: 'Spectral';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/static/fonts/spectral-600-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193,
                 U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  /* Misma paleta que la landing: papel de imprenta, verde de sumario y oro de
     subrayado. El oro marca siempre lo mismo, una cita a la ley. */
  --paper:      #f4efe4;
  --surface:    #fbf8f1;
  --surface-2:  #ece5d6;
  --ink:        #171712;
  --ink-2:      #46433b;
  --muted:      #827d6e;
  --line:       #ded6c4;
  --line-2:     #cbc2ac;
  --accent:     #164633;
  --accent-2:   #0f3325;
  --accent-ink: #f4efe4;
  --cite:       #8a6420;
  --cite-bg:    #f3e6c9;
  --cite-bg-2:  #e9d5a8;
  --ok:         #1f6b45;
  --warn:       #8e6414;
  --danger:     #8e2a2a;

  --radius:     10px;
  --radius-lg:  14px;
  --shadow:     0 1px 2px rgba(27,26,23,.05), 0 8px 24px -12px rgba(27,26,23,.18);
  --shadow-lg:  0 24px 60px -24px rgba(27,26,23,.34);

  /* La de la landing, solo para el rótulo de marca. */
  --display: 'Spectral', Georgia, serif;
  --sans: ui-sans-serif, -apple-system, "Segoe UI", Inter, Roboto, "Helvetica Neue", Arial, sans-serif;
  --serif: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, "Times New Roman", serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  --sidebar-w: 292px;
  --source-w:  440px;
}

[data-theme="dark"] {
  --paper:      #14150f;
  --surface:    #1b1c16;
  --surface-2:  #22241c;
  --ink:        #ece9df;
  --ink-2:      #c4bfb2;
  --muted:      #8d887b;
  --line:       #2c2e25;
  --line-2:     #3a3d31;
  --accent:     #86bda1;
  --accent-2:   #a4d0b6;
  --accent-ink: #0e1712;
  --cite:       #e8b464;
  --cite-bg:    #35291427;
  --cite-bg-2:  #4a381a;
  --ok:         #7dc79a;
  --warn:       #dbab5f;
  --danger:     #e08484;
  --shadow:     0 1px 2px rgba(0,0,0,.4), 0 10px 30px -14px rgba(0,0,0,.7);
  --shadow-lg:  0 24px 60px -20px rgba(0,0,0,.7);
}

* { box-sizing: border-box; }
/* La página NO scrollea: scrollea cada columna por su cuenta. */
html, body { height: 100%; overflow: hidden; }
body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overscroll-behavior: none;
}
svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.7;
      stroke-linecap: round; stroke-linejoin: round; flex: none; }
/* Esta regla es para los iconos de línea, pero alcanza a TODO `svg`, y el CSS le
   gana a los atributos `width="100%"`: la capa del botón líquido quedaba como un
   cuadrado de 18 px en la esquina —con el fondo del botón ya en transparente, así
   que el botón se veía hueco y con un lunar verde— y sus rectángulos heredaban de
   paso un filete de 1,7 px del color del texto. Se excluye por completo. */
svg[data-liquid-capa] { width: 100%; height: 100%; fill: initial; stroke: none;
                        stroke-width: 0; }
button { font: inherit; color: inherit; }
::selection { background: var(--cite-bg-2); }

/* Barras de desplazamiento de la casa: finas, del color de la línea y sin
   pista. El scrollbar del sistema era lo único que seguía cantando sobre el
   papel. Las dos sintaxis: la estándar manda donde existe y la -webkit- cubre
   los Safari que aún no la tienen. */
* { scrollbar-width: thin; scrollbar-color: var(--line-2) transparent; }
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb { background-color: var(--line-2); border-radius: 8px;
                             border: 3px solid transparent; background-clip: content-box; }
*::-webkit-scrollbar-thumb:hover { background-color: var(--muted); }

/* Grano de papel: un velo de ruido FIJO sobre todo, casi invisible, que da
   materia a la metáfora de imprenta. Estático, en data URI y sin eventos:
   cero peticiones, cero movimiento, cero estorbo al puntero. */
body::after {
  content: ''; position: fixed; inset: 0; z-index: 200; pointer-events: none;
  opacity: .038; mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23g)'/%3E%3C/svg%3E");
  background-size: 240px 240px;
}
[data-theme="dark"] body::after { opacity: .05; mix-blend-mode: screen; }

/* ── Estructura ───────────────────────────────────────────────────────── */
.app {
  display: grid;
  grid-template-columns: var(--sidebar-w) minmax(0, 1fr) 0;
  /* 100% sobre la cadena html/body (ambos height:100%), NO 100dvh: con zoom de
     página, Chrome computa dvh contra el viewport sin zoom y la app se quedaba
     corta, con una franja de fondo vacía debajo. El 100% es a prueba de zoom. */
  height: 100%;
  transition: grid-template-columns .28s cubic-bezier(.22,.8,.3,1);
}
/* Y las tres celdas tienen que poder encoger. Una celda de grid tiene
   `min-height: auto`, así que crece con su contenido y estira la fila por encima
   de 100dvh: la columna nunca llega a scrollear y, con el body recortado, no
   scrollea NADA. Esto es lo que faltaba. */
.app > * { min-height: 0; overflow: hidden; }
.app.source-open { grid-template-columns: var(--sidebar-w) minmax(0, 1fr) var(--source-w); }
.app.sidebar-hidden { grid-template-columns: 0 minmax(0, 1fr) 0; }
.app.sidebar-hidden.source-open { grid-template-columns: 0 minmax(0, 1fr) var(--source-w); }

/* ── Barra lateral ────────────────────────────────────────────────────── */
.sidebar {
  display: flex; flex-direction: column; gap: 12px;
  padding: 14px 12px;
  background: var(--surface-2);
  border-right: 1px solid var(--line);
  overflow: hidden;
  min-width: 0;
}
.app.sidebar-hidden .sidebar { padding: 0; border: 0; }
.sidebar__head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.brand { display: flex; align-items: center; gap: 9px; min-width: 0; }
/* El icono ya no es un trazo SVG sino el PNG de la pestaña: ni stroke ni color. */
.brand__mark { width: 22px; height: 22px; border-radius: 5px; flex: none;
               display: block; }
/* Mismo rótulo que la mancheta de la landing: Spectral 600, «Lawyer.» en verde
   y el punto incluido. Solo cambia el cuerpo, que aquí es de barra lateral. */
.brand__name { font-family: var(--display); font-weight: 600; font-size: 20px;
               letter-spacing: -.03em; line-height: 1; white-space: nowrap; }
.brand__name .dot { color: var(--accent); }
.brand__tag { font-family: var(--mono); font-size: 9px; letter-spacing: .14em;
              text-transform: uppercase; color: var(--muted); border: 1px solid var(--line-2);
              border-radius: 4px; padding: 2px 5px; white-space: nowrap; }

.sidebar__scroll { flex: 1; min-height: 0; overflow-y: auto; margin: 0 -4px; padding: 0 4px;
                   overscroll-behavior: contain; }
.sidebar__foot {
  border-top: 1px solid var(--line);
  padding-top: 9px; font-size: 11px; color: var(--muted); line-height: 1.45;
}
/* Las cifras del corpus SUBEN rodando al cargar, como el cuentakilómetros del
   grafo: dice «esto está vivo» sin ocupar un píxel más. */
.sidebar__foot .cifra { display: inline-flex; vertical-align: -2px;
                        font-variant-numeric: tabular-nums; }

/* Sin cuenta no hay clientes ni historial que enseñar, así que no se enseñan
   los rótulos: dos encabezados sobre el vacío parecen una función rota, y sus
   botones solo sabían pedir el correo. Queda la barra con lo que sí funciona
   —preguntar, buscar en el corpus— y el tamaño del corpus abajo. */
.app.es-anonimo .sidebar__scroll .group,
.app.es-anonimo #assignFolder { display: none; }

.group { margin-bottom: 18px; }
.group__head {
  display: flex; align-items: center; justify-content: space-between;
  font-family: var(--mono); font-size: 9.5px; font-weight: 700; letter-spacing: .14em;
  text-transform: uppercase; color: var(--muted); padding: 4px 6px; margin-bottom: 6px;
}

/* ── Botones y controles ──────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  border: 1px solid var(--line-2); background: var(--surface); color: var(--ink);
  border-radius: var(--radius); padding: 9px 13px; cursor: pointer;
  font-weight: 560; font-size: 14px; transition: background .15s, border-color .15s, transform .06s;
}
.btn:hover { background: var(--surface-2); border-color: var(--muted); }
.btn:active { transform: translateY(1px); }
.btn--primary { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.btn--primary:hover { background: var(--accent-2); border-color: var(--accent-2); }
.btn--block { width: 100%; }

/* Botón líquido (`/static/liquid.js`). El blob es el MISMO verde al que el botón
   ya viraba al pasar por encima: el efecto sustituye un cambio de color plano por
   uno líquido, sin meter un color nuevo en la paleta. El oro queda fuera a
   propósito — aquí el oro significa una cita a la ley y no puede significar
   además «botón bonito». */
[data-liquid] { --liquid-blob: var(--accent-2); }
/* El `outline` se pinta el último de todos, por encima del SVG del efecto, pero
   se declara en vez de fiarlo al del navegador: este es el botón principal de la
   aplicación y sin ratón no hay otra forma de saber dónde está el foco. */
[data-liquid]:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.btn--send { width: 38px; height: 38px; padding: 0; border-radius: 9px; }
.btn:disabled { opacity: .5; cursor: not-allowed; }

.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; border: 0; background: transparent; color: var(--muted);
  border-radius: 8px; cursor: pointer; transition: background .15s, color .15s;
}
.icon-btn:hover { background: var(--line); color: var(--ink); }
.icon-btn--sm { width: 24px; height: 24px; }
.icon-btn--sm svg { width: 14px; height: 14px; }

/* El buscador de la barra ES la puerta del paladar: la gente va ahí a buscar, así
   que abrir ⌘K desde ahí anuncia el atajo solo, en vez de dejarlo escondido. */
.search__lanzador {
  display: flex; align-items: center; gap: 8px; width: 100%;
  border: 1px solid var(--line-2); background: var(--surface); color: var(--muted);
  border-radius: var(--radius); padding: 8px 10px 8px 32px; font-size: 13.5px;
  cursor: pointer; text-align: left; transition: border-color .15s, color .15s;
}
.search__lanzador span { flex: 1; min-width: 0; overflow: hidden;
                         text-overflow: ellipsis; white-space: nowrap; }
.search__lanzador:hover { border-color: var(--muted); color: var(--ink-2); }
.search__lanzador kbd { flex: none; }

.search { position: relative; }
.search svg { position: absolute; left: 10px; top: 50%; transform: translateY(-50%);
              color: var(--muted); width: 15px; height: 15px; }
.search input, .select, .composer textarea {
  width: 100%; border: 1px solid var(--line-2); background: var(--surface); color: var(--ink);
  border-radius: var(--radius); font: inherit; outline: none;
}
.search input { padding: 8px 10px 8px 32px; font-size: 13.5px; }
.search input:focus, .select:focus, .composer textarea:focus {
  border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 14%, transparent);
}
.select { width: auto; max-width: 15rem; padding: 5px 26px 5px 9px; font-size: 12.5px;
           border-radius: 8px; cursor: pointer;
           /* el ancho lo pone el contenido: con width:100% heredado del grupo de
              controles, el desplegable rompía la fila de filtros a dos líneas */
           appearance: none;
           background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%),
                             linear-gradient(135deg, var(--muted) 50%, transparent 50%);
           background-position: calc(100% - 14px) 12px, calc(100% - 9px) 12px;
           background-size: 5px 5px, 5px 5px; background-repeat: no-repeat; }

/* ── Árbol de clientes ────────────────────────────────────────────────── */
.tree__item {
  display: flex; align-items: center; gap: 7px;
  padding: 6px 8px; border-radius: 8px; cursor: pointer; font-size: 13.5px;
  color: var(--ink-2); user-select: none;
}
.tree__item:hover { background: var(--line); color: var(--ink); }
.tree__item.is-active { background: var(--surface); color: var(--ink); font-weight: 580;
                        box-shadow: inset 0 0 0 1px var(--line-2); }
.tree__item svg { width: 15px; height: 15px; color: var(--muted); }
.tree__item .tree__name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis;
                          white-space: nowrap; }
.tree__count { font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums; }
.tree__children { margin-left: 14px; padding-left: 8px; border-left: 1px solid var(--line); }
.tree__empty { font-size: 12.5px; color: var(--muted); padding: 4px 8px 8px; }

/* ── Lista de consultas ───────────────────────────────────────────────── */
.conv {
  position: relative; display: block; width: 100%; text-align: left; border: 0;
  background: transparent; padding: 7px 26px 7px 8px; border-radius: 8px;
  cursor: pointer; margin-bottom: 1px;
}
/* Eliminar a un clic, no escondido en un menú contextual. */
.conv__borrar {
  position: absolute; top: 50%; right: 4px; transform: translateY(-50%);
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: 6px; color: var(--muted);
  opacity: 0; transition: opacity .15s, background .15s, color .15s;
}
.conv__borrar svg { width: 13px; height: 13px; }
.conv:hover .conv__borrar { opacity: 1; }
.conv__borrar:hover { background: color-mix(in srgb, var(--danger) 14%, transparent);
                      color: var(--danger); }
@media (hover: none) { .conv__borrar { opacity: .6; } }
.conv:hover { background: var(--line); }
.conv.is-active { background: var(--surface); box-shadow: inset 0 0 0 1px var(--line-2); }
.conv.is-dragging { opacity: .4; cursor: grabbing; }
.tree__item.is-drop { background: var(--cite-bg); color: var(--cite);
                      box-shadow: inset 0 0 0 1px var(--cite); }
.tree__item.is-drop svg { color: var(--cite); }
.conv__title { font-size: 13.5px; font-weight: 540; overflow: hidden; text-overflow: ellipsis;
               white-space: nowrap; }
.conv__meta { font-size: 11px; color: var(--muted); display: flex; gap: 6px; margin-top: 1px; }
/* Está respondiendo: donde iba la hora va un punto que late. El punto es el
   mismo de la tira de la esquina —misma señal, mismo significado— y el título
   sube de peso lo justo para que la fila cante entre las de al lado. */
.conv__curso { display: inline-flex; align-items: center; gap: 5px; color: var(--cite); }
.conv__curso[hidden] { display: none; }   /* el display de arriba gana al del navegador */
.conv__pulso {
  width: 6px; height: 6px; border-radius: 50%; background: currentColor;
  flex: none; animation: envueloLate 1.4s ease-in-out infinite;
}
.conv.is-corriendo .conv__title { color: var(--ink); font-weight: 600; }

/* ── Cabecera ─────────────────────────────────────────────────────────── */
.main { display: flex; flex-direction: column; min-width: 0; background: var(--paper); }
.topbar {
  display: flex; align-items: center; gap: 10px; flex: none;
  padding: 10px 18px; border-bottom: 1px solid var(--line);
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  backdrop-filter: saturate(1.4) blur(8px);
  position: sticky; top: 0; z-index: 6;
}
#showSidebar { display: none; }
.app.sidebar-hidden #showSidebar { display: inline-flex; }
.topbar__title { flex: 1; min-width: 0; }
.topbar__title h1 { margin: 0; font-size: 15px; font-weight: 620; letter-spacing: -.01em;
                    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.topbar__folder { font-size: 11.5px; color: var(--muted); }
.topbar__actions { display: flex; gap: 2px; }

/* ── Hilo ─────────────────────────────────────────────────────────────── */
/* `min-height: 0` es lo que hace que esto scrolle de verdad: un hijo flexible
   con `flex: 1` no baja de la altura de su contenido, así que sin esa línea la
   columna crecía y arrastraba a la página entera —el hilo, la barra lateral y el
   panel de la fuente scrolleaban todos juntos—. */
.thread { flex: 1; min-height: 0; overflow-y: auto; padding: 26px 18px 8px;
          scroll-behavior: smooth; overscroll-behavior: contain;
          /* Los mensajes se FUNDEN en los bordes en vez de cortarse a cuchillo
             contra la cabecera y el cajón de escribir. */
          -webkit-mask-image: linear-gradient(to bottom,
            transparent, #000 18px, #000 calc(100% - 22px), transparent);
          mask-image: linear-gradient(to bottom,
            transparent, #000 18px, #000 calc(100% - 22px), transparent); }
.thread > * { max-width: 780px; margin-inline: auto; }

.welcome { padding: 8vh 0 0; text-align: left; position: relative; }
/* La cara de renglones tachados, a la derecha del saludo. Absoluta a propósito:
   no añade ni un píxel al alto del recibimiento, que ya va justo en portátil.
   Como máscara y no como <img>, para que tome el color de tinta de cada tema. */
.welcome__cara { position: absolute; top: 8vh; right: 0; width: 90px; height: 124px;
                 background: var(--ink); opacity: .82; pointer-events: none;
                 -webkit-mask: url(logo-cara.png) center/contain no-repeat;
                 mask: url(logo-cara.png) center/contain no-repeat; }
@media (max-width: 760px) { .welcome__cara { display: none; } }
/* En un portátil (723 px de alto útil) el recibimiento medía 499 y la última
   consulta quedaba cortada por el cuadro de escribir: se podía leer bajando,
   pero una pantalla de bienvenida que hay que scrollear ya ha fallado. El aire
   de arriba es lo primero que sobra cuando no hay alto. */
@media (max-height: 860px) {
  .welcome { padding-top: 20px; }
  .welcome p { margin-bottom: 18px; }
  .welcome__cara { top: 20px; }   /* la cara sigue al saludo cuando pierde el aire */
}
.welcome h2 { font-family: var(--serif); font-size: 30px; font-weight: 600; margin: 0 0 10px;
              letter-spacing: -.02em; }
.welcome p { color: var(--ink-2); margin: 0 0 26px; max-width: 56ch; }
/* Las consultas guardadas, como el índice de un tomo: una fila cada una y la
   materia a la derecha en versalitas. Antes eran once rótulos de materia y
   veinte pastillas sueltas —una pared de casi seiscientos píxeles que se metía
   por debajo del cuadro de escribir y quedaba cortada—. Ahora se ven seis, una
   por materia, y las veinte están a un clic. Quien no las quiera, las oculta. */
/* Sin `display` propio: el bloque se oculta con el atributo `hidden` y cualquier
   `display` aquí le gana al del navegador —lo pusimos, y «Ocultar» dejaba la
   cabecera a la vista sobre una lista vacía—. */
.ejemplos[hidden] { display: none; }
.ejemplos__barra { display: flex; align-items: baseline; justify-content: space-between;
                   gap: 14px; padding-bottom: 6px; border-bottom: 1px solid var(--line-2); }
.ejemplos__rotulo, .ejemplos__accion, .ejemplo__area, .ejemplos__mostrar {
  font-family: var(--mono); font-size: 9px; font-weight: 700; letter-spacing: .14em;
  text-transform: uppercase; color: var(--muted);
}
.ejemplos__acciones { display: flex; gap: 16px; flex: none; }
.ejemplos__accion { background: none; border: 0; padding: 0; cursor: pointer;
                    transition: color .15s; }
.ejemplos__accion:hover { color: var(--accent); }

.ejemplos__lista { list-style: none; margin: 0; padding: 0; }
.ejemplos__lista li + li { border-top: 1px solid var(--line); }
.ejemplo {
  display: flex; align-items: baseline; justify-content: space-between; gap: 16px;
  width: 100%; background: none; border: 0; border-radius: 7px; cursor: pointer;
  padding: 10px 9px; margin-inline: -9px; width: calc(100% + 18px);
  text-align: left; color: var(--ink-2); font-size: 14.5px;
  transition: color .15s, background .15s;
}
.ejemplo__q { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ejemplo__area { flex: none; transition: color .15s; }
.ejemplo:hover { color: var(--ink); background: color-mix(in srgb, var(--accent) 6%, transparent); }
.ejemplo:hover .ejemplo__area { color: var(--accent); }

/* Ocultas, queda una línea para volver a verlas: una preferencia que no se
   puede deshacer no es una preferencia, es una pérdida. */
.ejemplos__mostrar { background: none; border: 0; padding: 4px 0; cursor: pointer;
                     transition: color .15s; }
.ejemplos__mostrar:hover { color: var(--accent); }

@media (max-width: 620px) { .ejemplo__area { display: none; } }
/* Va DESPUÉS de `.ejemplo` a propósito: escrita arriba, junto al resto del
   ajuste por alto, perdía contra la regla base por orden de aparición. */
@media (max-height: 860px) { .ejemplo { padding-top: 7px; padding-bottom: 7px; } }

/* El botón de repetir vive dentro de un aviso, así que va más pequeño. */
.btn--xs { font-size: 12px; padding: 4px 11px; margin-left: auto; flex: none; }

.msg { margin-bottom: 26px; }
.msg--user .msg__body {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-lg);
  padding: 12px 16px; font-size: 15px; white-space: pre-wrap; word-break: break-word;
}
.msg--assistant .msg__body { font-size: 15.5px; }
/* El dictamen se lee en la MISMA serifa que el articulado del panel: pregunta en
   sans (tarjeta), respuesta en serifa (papel). Solo el texto corrido — los
   avisos, las fuentes y los botones son interfaz y siguen en la sans. */
.msg--assistant .msg__body > p, .msg--assistant .msg__body > ul,
.msg--assistant .msg__body > ol, .msg--assistant .msg__body > blockquote {
  font-family: var(--serif); font-size: 16px; line-height: 1.72;
}
.msg__body > *:first-child { margin-top: 0; }
.msg__body > *:last-child  { margin-bottom: 0; }
.msg__body p { margin: 0 0 .85em; }
.msg__body ul, .msg__body ol { margin: 0 0 .9em; padding-left: 1.35em; }
.msg__body li { margin-bottom: .3em; }
.msg__body h3 { font-family: var(--sans); font-size: 15px; font-weight: 660;
                margin: 1.4em 0 .5em; }
.msg__body strong { font-weight: 650; }
.msg__body code { font-family: var(--mono); font-size: .88em; background: var(--surface-2);
                  padding: 1px 5px; border-radius: 5px; }
.msg__body blockquote { margin: 0 0 .9em; padding-left: 14px; border-left: 3px solid var(--line-2);
                        color: var(--ink-2); }

/* Cita: el subrayado ámbar es siempre una referencia a la ley */
.cite {
  border: 0; padding: 0 3px; margin: 0; cursor: pointer;
  background: var(--cite-bg); color: var(--cite);
  border-radius: 5px; font: inherit; font-weight: 560;
  box-shadow: inset 0 -1px 0 color-mix(in srgb, var(--cite) 40%, transparent);
  transition: background .14s, box-shadow .14s;
}
.cite:hover, .cite.is-open { background: var(--cite-bg-2);
  box-shadow: inset 0 -2px 0 var(--cite); }
/* Cita aún sin verificar: mismo sitio, sin invitar a pulsarla. */
.cite--pendiente { cursor: default; opacity: .72; box-shadow: none; }

/* Traza del agente */
.trace { border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface);
         margin-bottom: 14px; overflow: hidden; }
.trace__head { display: flex; align-items: center; gap: 9px; padding: 9px 13px; cursor: pointer;
               font-size: 13px; color: var(--ink-2); user-select: none; }
.trace__head:hover { background: var(--surface-2); }
.trace__caret { transition: transform .18s; color: var(--muted); }
.trace.is-open .trace__caret { transform: rotate(90deg); }
.trace__steps { display: none; padding: 2px 13px 11px; }
.trace.is-open .trace__steps { display: block; }
.trace__step { display: flex; gap: 9px; align-items: baseline; font-size: 12.5px;
               color: var(--muted); padding: 3px 0; }
.trace__step b { color: var(--ink-2); font-weight: 560; }
.trace__reloj { margin-left: auto; font-family: var(--mono); font-size: 11px;
                color: var(--muted); font-variant-numeric: tabular-nums; flex: none; }

/* El paso en curso lleva un anillo girando; los ya hechos, un visto. Se
   distingue de un tirón qué se ha terminado y en qué está el sistema ahora. */
.step__mark { width: 11px; height: 11px; flex: none; align-self: center;
              position: relative; display: inline-flex; }
.trace__step.is-curso .step__mark::after {
  content: ''; position: absolute; inset: 0; border-radius: 50%;
  border: 1.5px solid var(--line-2); border-top-color: var(--accent);
  animation: giro .75s linear infinite;
}
.trace__step.is-hecho .step__mark svg { width: 11px; height: 11px; color: var(--ok);
                                        opacity: .8; stroke-width: 2.6; }
/* El visto se DIBUJA (trazo de izquierda a derecha), no aparece: un check
   dibujado se lee como «comprobado»; uno que brota, como un icono más. El
   pathLength=24 lo pone el propio marcado en app.js. */
.trace__step.is-hecho .step__mark svg path {
  stroke-dasharray: 24; stroke-dashoffset: 24;
  animation: dibujarVisto .4s cubic-bezier(.55,0,.35,1) forwards;
}
@keyframes dibujarVisto { to { stroke-dashoffset: 0; } }
@keyframes giro { to { transform: rotate(360deg); } }

/* Rejilla de trabajo: nueve teselas y un destello que las recorre en diagonal.
   Sustituye al punto que parpadeaba — el parpadeo pide atención cada segundo y
   a los treinta cansa; esto se mueve sin llamar. */
.churn { display: grid; grid-template-columns: repeat(3, 3px); gap: 2px;
         flex: none; align-self: center; }
.churn i { width: 3px; height: 3px; border-radius: 1px; background: var(--accent);
           opacity: .16; animation: churn 1.6s ease-in-out infinite; }
.churn i:nth-child(1) { animation-delay: 0ms; }
.churn i:nth-child(2), .churn i:nth-child(4) { animation-delay: 110ms; }
.churn i:nth-child(3), .churn i:nth-child(5), .churn i:nth-child(7) { animation-delay: 220ms; }
.churn i:nth-child(6), .churn i:nth-child(8) { animation-delay: 330ms; }
.churn i:nth-child(9) { animation-delay: 440ms; }
@keyframes churn { 0%, 62%, 100% { opacity: .16; } 22% { opacity: 1; } }
.churn--sm { grid-template-columns: repeat(3, 2.5px); gap: 1.5px; }
.churn--sm i { width: 2.5px; height: 2.5px; }
.churn__ok { width: 13px; height: 13px; flex: none; align-self: center; color: var(--ok);
             stroke-width: 2.4; }
.churn__ok path { stroke-dasharray: 24; stroke-dashoffset: 24;
                  animation: dibujarVisto .45s cubic-bezier(.55,0,.35,1) .06s forwards; }
.churn__ok--sm { width: 11px; height: 11px; }
.trace__done { color: var(--ok); }
.trace__aviso { color: var(--warn); }
.trace__thinking { font-size: 12px; color: var(--muted); line-height: 1.5; margin-top: 6px;
                   padding-top: 7px; border-top: 1px dashed var(--line); }
.thinking__head { display: flex; align-items: center; gap: 5px; font: inherit;
                  color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
.thinking__head:hover { color: var(--ink-2); }
.thinking__caret { width: 11px; height: 11px; flex: none; fill: none; stroke: currentColor;
                   stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round;
                   transition: transform .16s; }
.trace__thinking.is-open .thinking__caret { transform: rotate(90deg); }
.thinking__txt { display: none; margin-top: 5px; font-style: italic;
                 max-height: 9em; overflow: auto; }
.trace__thinking.is-open .thinking__txt { display: block; }

/* Grafo de exploración: se dibuja mientras se busca y se recoge al responder */
/* El contenedor NO se recorta: se recoge el lienzo. Recortando el contenedor, el
   pie quedaba fuera del corte y solo se veía una caja blanca vacía. */
.grafo {
  border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface);
  margin: -6px 0 14px; animation: fade .3s ease both;
}
/* `overflow-y: auto` y no `hidden`: el paso entre filas se aprieta hasta
   `FILA_MIN` para que quepan todas (ver `disponer` en app.js), pero con más de
   veintitantas vías ni apretando cabe, y entonces lo que toca es poder bajar —no
   quedarse sin saber que hay tres nodos ahí abajo—. En horizontal sigue sin
   desbordar: el rótulo se recorta a la anchura de su columna. */
/* `--grafo-alto` es el tope, y lo lee también el JS (`altoUtil`) para saber
   hasta dónde puede apretar el paso entre filas. Va en una variable y no se lee
   `max-height` directamente porque `max-height` se anima al plegar el panel: a
   mitad de la transición vale 200 y pico, y el grafo se recolocaría contra un
   techo que dura un cuarto de segundo. */
.grafo__lienzo {
  --grafo-alto: 420px;
  padding: 10px 12px 4px; overflow: hidden auto; max-height: var(--grafo-alto);
  overscroll-behavior: contain;
  transition: max-height .5s cubic-bezier(.22,.8,.3,1), opacity .35s, padding .5s;
}
/* Al plegarse vuelve a `hidden`: con `auto`, la barra de desplazamiento
   parpadea durante la transición a max-height 0. */
.grafo.is-collapsed .grafo__lienzo {
  max-height: 0; opacity: 0; padding-top: 0; padding-bottom: 0; overflow: hidden;
}
.grafo__mapa { position: relative; }
/* Solo el lienzo, no cualquier svg del panel: con `.grafo svg` el visto del pie
   se comía la tarjeta entera (width:100% gana a la clase del icono). */
.grafo__mapa > svg { width: 100%; height: auto; display: block; overflow: visible; }
.grafo__pie {
  display: flex; align-items: center; gap: 8px; padding: 8px 13px;
  border-top: 1px solid var(--line); font-size: 12px; color: var(--muted);
  cursor: pointer; user-select: none; transition: border-color .3s;
}
.grafo.is-collapsed .grafo__pie { border-top-color: transparent; }
.grafo__contador { margin-left: auto; font-variant-numeric: tabular-nums;
                   font-size: 11.5px; color: var(--muted); }
/* El contador de razonamiento es un RODILLO por dígito, no un número que salta:
   mientras el modelo delibera, la cifra rueda hacia arriba como un
   cuentakilómetros. Flex en lugar de alinear por línea base, porque cada rueda
   lleva overflow:hidden y entonces su línea base es su borde inferior — encajarla
   con el rótulo exigía un `vertical-align` a ojo. --cifra-cel debe coincidir con
   CIFRA_CEL en app.js: es el paso del rodillo. */
.grafo__contador { --cifra-cel: 14px; display: flex; align-items: center; gap: .36em; }
/* El rodillo ya no es solo del grafo: cualquier cifra con esta clase rueda
   (el pie del corpus lo reutiliza). El paso por defecto sigue siendo el de
   CIFRA_CEL en app.js. */
.cifra { display: flex; height: var(--cifra-cel, 14px); overflow: hidden;
         transition: color .35s; }
.grafo__contador.is-vivo .cifra { color: var(--cite); }
.cifra__col { display: block; height: var(--cifra-cel, 14px); overflow: hidden; }
.cifra__tira { display: block; will-change: transform; }
.cifra__d,
.cifra__sep { display: block; height: var(--cifra-cel, 14px);
              line-height: var(--cifra-cel, 14px); text-align: center; }
.grafo__pie:hover { color: var(--ink-2); }
/* La misma flecha que la traza: las dos tarjetas se despliegan igual, así que
   deben decirlo igual. Apunta abajo cuando está abierta. */
.grafo__caret { width: 18px; height: 18px; flex: none; color: var(--muted);
                transform: rotate(90deg); transition: transform .18s; }
.grafo.is-collapsed .grafo__caret { transform: none; }

/* Los rótulos son HTML por encima del lienzo, no <text> dentro del SVG: un
   texto escalado se sale del retículo de píxeles y se ve engordado y sucio.
   Llevan el fondo del panel para tapar la línea que les pasa por detrás: sin
   eso, el trazo cruza las letras y parece que estén tachadas. */
.grafo__rotulos { position: absolute; inset: 0; pointer-events: none; }
.grafo__rot {
  position: absolute; transform: translateY(-50%);
  background: var(--surface); padding: 1px 4px; border-radius: 4px;
  font-size: 11.5px; line-height: 1.3; color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  pointer-events: auto; animation: fade .5s ease both;
  transition: color .25s;
}
.grafo__rot.es-consulta { color: var(--ink); font-weight: 560; }
.grafo__rot.es-norma { color: var(--ink-2); }
.grafo__rot.is-activo { color: var(--ink); }
/* Exploradas todas, útiles unas pocas. La Ley de cinematografía de 1960 se
   exploró de verdad en una consulta de despido —el grafo no miente— pero
   dibujarla igual que al Estatuto de los Trabajadores la convertía en un
   hallazgo. Se quedan, atenuadas; las que sostienen la respuesta, en tinta. */
.grafo__rot.es-util { color: var(--ink); font-weight: 560; }
.grafo__rot.es-descartada { color: var(--muted); opacity: .5; }
.grafo__nodo.es-descartada { opacity: .38; }

/* `stroke: none` no es un detalle: la regla global `svg { stroke: currentColor;
   stroke-width: 1.7 }` está pensada para los iconos de línea, y un `<circle>` la
   HEREDA. Cada punto del grafo salía con un anillo de 1,7 px del color del texto
   —blanco en oscuro— alrededor de su color. Nadie lo dibujó: se coló solo. */
.grafo__punto { animation: brotar .45s cubic-bezier(.34,1.56,.64,1) both;
                animation-delay: var(--d, 0ms); opacity: .88; stroke: none; }
/* El grosor del trazo va en píxeles (`non-scaling-stroke` en el propio nodo):
   en unidades del viewBox lo multiplicaba la escala del lienzo y un trazo
   pensado como pelo salía como una raya. */
.grafo__arista { fill: none; stroke-width: 1; opacity: .2; stroke-linecap: round;
                 stroke-dasharray: 320; stroke-dashoffset: 320;
                 animation: trazar .6s cubic-bezier(.22,.8,.3,1) both;
                 animation-delay: var(--d, 0ms); }
/* Una remisión se dibuja de puntos, pero durante el trazado la línea tiene que
   ir entera: el patrón se cambia en el último fotograma. */
.grafo__arista--punteada { animation-name: trazarPunteado; }
@keyframes trazarPunteado {
  0%   { stroke-dasharray: 320; stroke-dashoffset: 320; }
  99%  { stroke-dasharray: 320; stroke-dashoffset: 0; }
  100% { stroke-dasharray: 2.5 3.5; stroke-dashoffset: 0; }
}

/* El nodo de la vía que está buscando ahora mismo respira, y su arista brilla:
   se ve por dónde va el sistema, no solo lo que ya ha encontrado. */
.grafo__nodo.is-activo .grafo__punto { animation: brotar .45s cubic-bezier(.34,1.56,.64,1) both,
                                                  latir 1.4s ease-in-out .45s infinite; }
.grafo__nodo.is-activo .grafo__halo { animation: halo 1.6s ease-out infinite; }
.grafo__halo { fill: none; stroke-width: 1; opacity: 0; }
.grafo__arista.is-activa { opacity: .5; stroke-width: 1.1; }
/* Un punto de luz recorre la arista de la vía activa hacia el nodo: se VE la
   búsqueda fluir, no solo dónde está. Es un único path superpuesto que copia el
   trazado de la arista realzada (pulsoArista en app.js); pathLength=100
   normaliza el patrón, así que el mismo dash sirve para cualquier longitud. */
.grafo__pulso { fill: none; stroke-width: 2; stroke-linecap: round; opacity: .85;
                stroke-dasharray: 10 100; animation: viajar 1.25s linear infinite; }
@keyframes viajar { from { stroke-dashoffset: 110; } to { stroke-dashoffset: 0; } }
@media (prefers-reduced-motion: reduce) { .grafo__pulso { display: none; } }
@keyframes latir { 0%,100% { transform: scale(1); } 50% { transform: scale(1.35); } }
@keyframes halo  { 0% { r: 5; opacity: .5; } 100% { r: 15; opacity: 0; } }
@keyframes brotar { from { transform: scale(0); opacity: 0; } to { transform: scale(1); opacity: 1; } }
@keyframes trazar { to { stroke-dashoffset: 0; } }
.grafo__nodo { transform-box: fill-box; transform-origin: center; }
.grafo__nodo .grafo__punto { transform-box: fill-box; transform-origin: center; }

@media (max-width: 720px) {
  .grafo__lienzo { --grafo-alto: 300px; }
  .grafo__rot { font-size: 10.5px; }
}

/* Fuentes usadas — bibliografía, no nube de etiquetas.
   Diecisiete píldoras de anchura libre repetían el nombre de la ley una vez por
   artículo y no formaban retícula ninguna; peor, pesaban todas igual, así que
   las tres que sostenían la respuesta no se distinguían de las catorce que solo
   se miraron. Ahora son dos bandas ROTULADAS —lo citado y lo consultado— y una
   fila por norma. El rótulo es lo que hace el trabajo: el color solo acompaña,
   porque puesto a explicarse solo se entendía justo del revés. */
.sources { margin-top: 16px; padding-top: 13px; border-top: 1px solid var(--line); }
.sources__title { font-family: var(--mono); font-size: 9.5px; font-weight: 700;
                  letter-spacing: .14em; text-transform: uppercase;
                  color: var(--muted); margin-bottom: 10px; }
.sources__title b { color: var(--cite); font-weight: 700; }

/* ── Banda alta: lo que la respuesta cita ─────────────────────────────────── */
.src-cit { display: grid; grid-template-columns: 190px auto 1fr; gap: 0 14px;
           align-items: baseline; padding: 6px 0;
           border-bottom: 1px solid color-mix(in srgb, var(--line) 60%, transparent); }
.src-cit:last-of-type { border-bottom: 0; }
.src-cit__n { font-size: 13px; font-weight: 620; color: var(--ink); text-align: right; }
.src-cit__r { font-size: 12.5px; color: var(--muted);
              overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.src-pill { font-size: 12px; font-variant-numeric: tabular-nums; font-family: inherit;
            background: var(--cite-bg); color: var(--cite); font-weight: 620;
            border: 0; border-radius: 6px; padding: 2.5px 9px; cursor: pointer;
            display: inline-flex; align-items: center; gap: 6px; white-space: nowrap;
            box-shadow: inset 0 -2px 0 color-mix(in srgb, var(--cite) 45%, transparent);
            transition: background .14s; }
.src-pill:hover { background: var(--cite-bg-2); }
.src-pill em { font-style: normal; font-family: var(--mono); font-size: 9.5px;
               font-weight: 700; opacity: .7; flex: none; }
.src-pill span { overflow: hidden; text-overflow: ellipsis; }
.src-pill { max-width: 300px; }
/* Una comprobación no es una fuente: es aritmética sobre los cuadros de la ley.
   Va en el verde del sumario para que no se confunda con un artículo citado. */
.src-pill--calculo { background: color-mix(in srgb, var(--accent) 10%, transparent);
                     color: var(--accent);
                     box-shadow: inset 0 -2px 0 color-mix(in srgb, var(--accent) 45%, transparent); }
.src-pill--calculo:hover { background: color-mix(in srgb, var(--accent) 17%, transparent); }

/* ── Banda baja: lo consultado y no citado ────────────────────────────────── */
/* Se hunde en el papel en vez de seguir apilada encima: la jerarquía la da el
   plano, no otro gris más. El rótulo va montado sobre la regla. */
.src-rule { position: relative; margin-top: 20px; border-top: 1px solid var(--line); }
.src-rule__l { position: absolute; top: -7px; left: 0; background: var(--surface);
               padding-right: 9px; font-family: var(--mono); font-size: 9px;
               font-weight: 700; letter-spacing: .14em; text-transform: uppercase;
               color: var(--muted); }
.src-inset { background: var(--paper); border-radius: 11px; padding: 13px 16px 11px;
             margin-top: 16px; box-shadow: inset 0 1px 2px rgba(27,26,23,.045); }
.src-rows { display: grid; grid-template-columns: 174px 1fr; gap: 1px 16px;
            align-items: baseline; }
.src-rows__n { font-size: 12.5px; color: var(--muted); text-align: right;
               padding: 4px 0; line-height: 1.35; }
.src-rows__a { display: flex; flex-wrap: wrap; gap: 5px; padding: 2px 0; }
/* Píldora de contorno, no maciza: secundaria a la vista, pulsable a la mano. */
.src-ghost { display: inline-flex; align-items: center; font-size: 11.5px;
             font-variant-numeric: tabular-nums; font-family: inherit;
             color: var(--ink-2); background: transparent; border: 1px solid var(--line-2);
             border-radius: 6px; padding: 1.5px 8px; line-height: 1.35; cursor: pointer;
             max-width: 100%; white-space: nowrap;
             transition: border-color .14s, color .14s; }
.src-ghost span { overflow: hidden; text-overflow: ellipsis; }
.src-ghost:hover { border-color: var(--accent); color: var(--ink); }
/* Lo que el BOE ya no publica. Es el único «motivo de descarte» que consta de
   verdad, así que es el único que se dibuja. */
.src-ghost--off { border-style: dashed; color: var(--muted); }
.src-ghost--txt { font-variant-numeric: normal; max-width: 330px; }

/* Cinta de plegado, para cuando lo consultado es un muro. */
.src-fold { display: flex; align-items: center; gap: 10px; flex-wrap: nowrap; width: 100%;
            margin-top: 16px; padding: 8px 15px; border: 0; border-radius: 999px;
            background: var(--paper); cursor: pointer; text-align: left;
            box-shadow: inset 0 1px 2px rgba(27,26,23,.045); font-family: inherit; }
.src-fold__c { font-family: var(--mono); font-size: 10px; font-weight: 700;
               letter-spacing: .1em; text-transform: uppercase; color: var(--ink-2);
               display: inline-flex; align-items: center; gap: 6px; flex: none; }
.src-fold__c svg { width: 10px; height: 10px; fill: none; stroke: currentColor;
                   stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round;
                   transition: transform .18s; }
.src-fold[aria-expanded="true"] .src-fold__c svg { transform: rotate(90deg); }
.src-fold__s { font-size: 12px; color: var(--muted); overflow: hidden;
               text-overflow: ellipsis; white-space: nowrap; }

/* ── Ficha: qué es y cómo llegó ───────────────────────────────────────────── */
/* El tooltip de dos líneas no da para esto y no debe: aquí se enseña el texto de
   la ley, y el texto de la ley se lee en serifa. Dice CÓMO entró —que consta— y
   nunca por qué no se citó, que no consta en ninguna parte. */
.ficha { position: fixed; z-index: 60; width: 352px; max-width: calc(100vw - 24px);
         background: var(--surface); border: 1px solid var(--line-2);
         border-radius: 12px; box-shadow: var(--shadow-lg); padding: 13px 15px 11px;
         opacity: 0; transform: translateY(3px); pointer-events: none;
         transition: opacity .13s ease, transform .13s ease; }
.ficha.is-open { opacity: 1; transform: none; }
.ficha__t { font-size: 13.5px; font-weight: 650; color: var(--ink); line-height: 1.3; }
.ficha__r { font-size: 12.5px; color: var(--ink-2); margin-top: 2px; line-height: 1.35; }
.ficha__b { font-family: var(--mono); font-size: 9px; letter-spacing: .1em;
            text-transform: uppercase; color: var(--muted); margin-top: 6px; }
.ficha__x { margin: 10px 0; padding: 9px 0;
            border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
/* El recorte va en un elemento SIN padding ni borde: compartiendo caja con
   ellos, WebKit cuenta mal y deja asomar media cuarta línea. */
.ficha__x span { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
                 overflow: hidden; font-family: var(--serif); font-size: 13px;
                 line-height: 1.5; color: var(--ink-2); }
.ficha__f { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.ficha__via { font-family: var(--mono); font-size: 9.5px; font-weight: 700;
              letter-spacing: .05em; text-transform: uppercase; border-radius: 5px;
              padding: 2px 7px; background: var(--surface-2); color: var(--ink-2); }
/* Vía floja —vecindad o remisión—: contorno, no macizo. Lo dice el peso que le
   da el reordenador, no una opinión de la interfaz. */
.ficha__via--w { background: transparent; border: 1px dashed var(--line-2); color: var(--muted); }
.ficha__est { margin-left: auto; font-size: 10.5px; font-weight: 600; color: var(--ok); }
.ficha__est--off { color: var(--danger); }
.ficha__why { font-size: 11.5px; color: var(--muted); line-height: 1.45; margin-top: 8px;
              padding-top: 8px; border-top: 1px solid var(--line); }
.ficha__why b { color: var(--ink-2); font-weight: 600; }
/* La ficha se puede tocar: aquí vive la acción de rehacer. Por eso el puntero
   tiene que poder entrar en ella, y por eso el cierre es indulgente. */
.ficha { pointer-events: auto; }
.ficha__fijar { display: flex; align-items: center; gap: 7px; width: 100%; margin-top: 10px;
                padding: 7px 10px; border: 1px solid var(--line-2); border-radius: 8px;
                background: var(--paper); color: var(--ink-2); cursor: pointer;
                font-family: inherit; font-size: 11.5px; font-weight: 560;
                transition: border-color .14s, color .14s, background .14s; }
.ficha__fijar:hover { border-color: var(--accent); color: var(--accent);
                      background: color-mix(in srgb, var(--accent) 7%, var(--paper)); }
.ficha__fijar svg { width: 12px; height: 12px; flex: none; fill: none; stroke: currentColor;
                    stroke-width: 2.2; stroke-linecap: round; }

/* La misma pregunta repetida no es un descuido: es la misma pregunta con más
   evidencia dentro, y hay que decirlo debajo de ella. */
.msg__nota { font-size: 11.5px; color: var(--muted); margin-top: 5px; text-align: right; }

.msg__foot { display: flex; align-items: center; gap: 4px; margin-top: 10px; }
.msg__foot .icon-btn { width: 28px; height: 28px; }
/* Alineación óptica: el icono va centrado en su botón, así que sin este retranqueo
   el dibujo queda cinco píxeles dentro de la columna del texto y de los chips. */
.msg__foot .icon-btn:first-child { margin-left: -5px; }
.msg__stat { font-size: 11.5px; color: var(--muted); margin-left: auto;
             font-variant-numeric: tabular-nums; }

.notice { border-radius: var(--radius); padding: 10px 13px; font-size: 13.5px; margin-bottom: 14px;
          border: 1px solid; display: flex; gap: 9px; align-items: flex-start; }
.notice--warn { border-color: color-mix(in srgb, var(--warn) 40%, var(--line));
                background: color-mix(in srgb, var(--warn) 8%, transparent); color: var(--ink-2); }
.notice--error { border-color: color-mix(in srgb, var(--danger) 45%, var(--line));
                 background: color-mix(in srgb, var(--danger) 8%, transparent); color: var(--ink-2); }

.caret { display: inline-block; width: 8px; height: 1.05em; background: var(--accent);
         vertical-align: -2px; margin-left: 2px; animation: blink 1s steps(2) infinite; }
@keyframes blink { 50% { opacity: 0; } }

/* La cola de texto recién llegada del stream no aparece: respira. Cada trozo
   entra con un fundido corto; como los fundidos se solapan, la escritura se lee
   continua en vez de a golpes. Lo envuelve pintarStream() en app.js. */
.stream-brote { animation: fade .32s ease both; }

/* ── Redactor ─────────────────────────────────────────────────────────── */
/* `flex: none` a lo que no debe encoger: un hijo flexible encoge por defecto, y
   con la columna recortada lo que se pierde es justo lo de abajo —el aviso y el
   pie legal— en cuanto la ventana es baja. Lo que cede es el hilo, que scrollea. */
.composer-wrap { padding: 4px 18px 14px; flex: none; }
.composer-wrap > * { max-width: 780px; margin-inline: auto; }
.composer {
  border: 1px solid var(--line-2); background: var(--surface); border-radius: var(--radius-lg);
  padding: 10px 12px 9px; box-shadow: var(--shadow);
  transition: border-color .15s, box-shadow .15s;
}
.composer:focus-within { border-color: var(--accent);
  box-shadow: var(--shadow), 0 0 0 3px color-mix(in srgb, var(--accent) 12%, transparent); }
.composer textarea { border: 0; padding: 4px 2px; resize: none; max-height: 220px;
                     font-size: 15px; background: transparent; }
.composer textarea:focus { box-shadow: none; }
.composer__bar { display: flex; align-items: center; justify-content: space-between; gap: 10px;
                 margin-top: 6px; }
.composer__filters { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; min-width: 0; }
.chip-toggle { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px;
               color: var(--muted); cursor: pointer; user-select: none; }
.chip-toggle input { accent-color: var(--accent); margin: 0; width: 14px; height: 14px;
                     border-radius: 4px; cursor: pointer; }
/* El selector de fecha del navegador viene con su propio marco y su propia
   tipografía: se le pone la de la casa para que no parezca pegado de otra web. */
input[type="date"] {
  font: inherit; font-size: 13.5px; color: var(--ink); background: var(--surface);
  border: 1px solid var(--line-2); border-radius: 8px; padding: 7px 9px;
  font-variant-numeric: tabular-nums;
}
input[type="date"]:focus { outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 14%, transparent); }
input[type="date"]::-webkit-calendar-picker-indicator { cursor: pointer; opacity: .55; }
input[type="date"]::-webkit-calendar-picker-indicator:hover { opacity: 1; }

/* Selector de fecha de los hechos: apagado no llama la atención; encendido se ve
   de lejos, porque cambia por completo qué derecho se está consultando. */
.chip-fecha {
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
  border: 1px solid var(--line-2); background: var(--surface); color: var(--muted);
  border-radius: 999px; padding: 4px 11px; font-size: 12.5px; font-weight: 520;
  transition: border-color .15s, color .15s, background .15s;
}
.chip-fecha svg { width: 13px; height: 13px; }
.chip-fecha:hover { border-color: var(--muted); color: var(--ink-2); }
.chip-fecha.is-on { border-color: var(--accent); color: var(--accent);
                    background: color-mix(in srgb, var(--accent) 8%, transparent); }
.chip-fecha.is-on.is-auto { border-style: dashed; }

.pop__atajos { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 12px; }
.btn--chip { padding: 5px 10px; font-size: 12.5px; border-radius: 999px; font-weight: 520; }
.btn--chip.is-on { border-color: var(--accent); color: var(--accent);
                   background: color-mix(in srgb, var(--accent) 10%, transparent); }
.pop__campo { display: block; font-size: 12px; color: var(--muted); margin-bottom: 10px; }
.pop__campo input { margin-top: 5px; font-variant-numeric: tabular-nums; }
/* El `auto` de los márgenes laterales es lo que centra: con `margin: 8px 0 0` se
   pisaba el `margin-inline: auto` de `.composer-wrap > *` y el texto quedaba
   centrado sobre un eje distinto al del cajón de escribir. */
.composer__note { font-size: 11.5px; color: var(--muted); text-align: center;
                  margin: 8px auto 0; line-height: 1.45; }
.composer__note strong { color: var(--ink-2); font-weight: 600; }
.legal {
  display: flex; justify-content: center; align-items: center; gap: 5px 12px;
  flex-wrap: wrap; margin: 6px auto 0; font-size: 11px; color: var(--muted);
}
.legal a { color: var(--muted); text-decoration: none; border-bottom: 1px solid transparent; }
.legal a:hover { color: var(--ink-2); border-bottom-color: var(--line-2); }

/* ── Panel de fuente ──────────────────────────────────────────────────── */
.source {
  background: var(--surface); border-left: 1px solid var(--line);
  display: flex; flex-direction: column; overflow: hidden; min-width: 0;
}
/* El asa de la lámina móvil: solo existe en teléfono (ver el media query del
   final). `touch-action: none` es lo que permite seguir al dedo sin que el
   navegador se quede el gesto para scrollear. */
.source__asa { display: none; justify-content: center; padding: 9px 0 3px;
               cursor: grab; touch-action: none; flex: none; }
.source__asa:active { cursor: grabbing; }
.source__asa i { width: 42px; height: 4px; border-radius: 999px;
                 background: var(--line-2); }
.source__head { display: flex; align-items: flex-start; gap: 10px; padding: 15px 18px 12px; flex: none;
                border-bottom: 1px solid var(--line); }
.source__head > div { flex: 1; min-width: 0; }
.source__eyebrow { font-family: var(--mono); font-size: 9.5px; font-weight: 700; letter-spacing: .14em;
                   text-transform: uppercase; color: var(--cite); }
.source__head h2 { margin: 2px 0 0; font-size: 15.5px; font-weight: 620; letter-spacing: -.01em;
                   line-height: 1.35; }
.source__body { flex: 1; min-height: 0; overflow-y: auto; padding: 16px 18px 40px;
                overscroll-behavior: contain;
                /* El mismo fundido del hilo: el articulado no se corta en seco. */
                -webkit-mask-image: linear-gradient(to bottom,
                  transparent, #000 14px, #000 calc(100% - 24px), transparent);
                mask-image: linear-gradient(to bottom,
                  transparent, #000 14px, #000 calc(100% - 24px), transparent); }

/* ── Vida de la norma ────────────────────────────────────────────────────────
   Cronología, no lista: publicación, una marca por reforma y el final. Es la
   forma en que un jurista lee el estado de una norma —lo que hacen KeyCite o
   vLex con sus banderas— y de paso cada marca es una puerta al texto de
   entonces. */
.vida { padding: 4px 2px 0; }
.vida__linea {
  position: relative; height: 3px; border-radius: 2px; margin: 14px 3px 9px;
  background: linear-gradient(90deg,
    color-mix(in srgb, var(--ok) 45%, var(--line)) 0%,
    color-mix(in srgb, var(--ok) 22%, var(--line)) 100%);
}
.vida.is-derogada .vida__linea {
  background: linear-gradient(90deg,
    color-mix(in srgb, var(--muted) 40%, var(--line)) 0%,
    color-mix(in srgb, var(--danger) 55%, var(--line)) 100%);
}
.vida__linea::before, .vida__linea::after {
  content: ''; position: absolute; top: 50%; width: 7px; height: 7px; border-radius: 50%;
  transform: translate(-50%, -50%); background: var(--ok);
}
.vida__linea::before { left: 0; background: var(--muted); }
.vida__linea::after { left: 100%; }
.vida.is-derogada .vida__linea::after { background: var(--danger); }
/* Una reforma. Rombo, no círculo: se distingue de los extremos de un vistazo. */
.vida__marca {
  position: absolute; top: 50%; width: 8px; height: 8px; padding: 0;
  transform: translate(-50%, -50%) rotate(45deg);
  border: 1px solid var(--surface); background: var(--accent);
  cursor: pointer; transition: transform .14s, background .14s;
}
.vida__marca:hover { transform: translate(-50%, -50%) rotate(45deg) scale(1.45);
                     background: var(--cite); }
.vida__extremos { display: flex; justify-content: space-between; align-items: baseline;
                  font-size: 11.5px; color: var(--muted); gap: 8px; }
.vida__extremos b { display: block; color: var(--ink-2); font-weight: 560; }
.vida__extremos i { font-style: normal; font-size: 10.5px; }
.vida__fin { text-align: right; }
.vida__reformas { font-family: var(--mono); font-size: 10px; letter-spacing: .08em;
                  text-transform: uppercase; }
.vida__quien { margin-top: 9px; font-size: 12.5px; color: var(--ink-2); }

/* Relaciones agrupadas: el verbo con su flecha, y debajo las normas. */
.rel-grupo { margin-bottom: 11px; }
.rel-grupo__verbo { display: flex; align-items: center; gap: 6px; font-size: 12px;
                    color: var(--muted); margin-bottom: 5px; }
.rel-grupo__flecha { font-family: var(--mono); color: var(--line-2); font-size: 13px; }
.rel-grupo.is-fuerte .rel-grupo__verbo { color: var(--danger); font-weight: 560; }
.rel-grupo.is-fuerte .rel-grupo__flecha { color: var(--danger); }
.rel-grupo__n { font-family: var(--mono); font-size: 10px; color: var(--muted);
                background: var(--surface-2); border-radius: 999px; padding: 1px 6px; }
.rel-grupo__normas { display: flex; flex-wrap: wrap; gap: 5px; }
.rel-grupo__normas .src-rel__norm {
  border: 1px solid var(--line-2); background: var(--surface); border-radius: 999px;
  padding: 3px 10px; font-size: 12.5px; color: var(--ink-2); cursor: pointer;
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  transition: border-color .15s, color .15s;
}
.rel-grupo__normas .src-rel__norm:hover { border-color: var(--accent); color: var(--ink); }
.rel-grupo__normas .src-rel__norm i { font-style: normal; color: var(--danger);
                                      font-size: 11px; }

/* ── La norma entera ─────────────────────────────────────────────────────────
   El sumario de una norma es lo que un jurista mira para orientarse, así que se
   lee como un índice: la jerarquía sangrada, el artículo en negrita y su rúbrica
   al lado, y un filtro que esconde lo que no toca sin recargar nada. */
.norma__buscar { position: relative; margin: 6px 0 12px; }
.norma__buscar svg { position: absolute; left: 10px; top: 50%; transform: translateY(-50%);
                     width: 15px; height: 15px; color: var(--muted); }
.norma__buscar input {
  width: 100%; border: 1px solid var(--line-2); background: var(--surface);
  color: var(--ink); border-radius: var(--radius); font: inherit; font-size: 13.5px;
  padding: 8px 10px 8px 32px; outline: none;
}
.norma__buscar input:focus { border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 14%, transparent); }
.norma__aviso { font-size: 11.5px; color: var(--muted); margin: -6px 0 8px;
                min-height: 1.2em; }
.norma__indice { display: flex; flex-direction: column; gap: 2px; }
.norma__grupo[hidden] { display: none; }
.norma__division {
  display: flex; flex-direction: column; gap: 1px;
  margin: 14px 0 5px; padding-left: calc(var(--nivel, 0) * 10px);
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--muted);
}
.norma__division b { color: var(--ink-2); font-weight: 700; }
.norma__division span { font-family: var(--sans); font-size: 11.5px; letter-spacing: 0;
                        text-transform: none; color: var(--muted); }
.norma__unidad {
  display: flex; align-items: baseline; gap: 8px; width: 100%; text-align: left;
  border: 0; background: transparent; border-left: 2px solid transparent;
  padding: 6px 8px; border-radius: 7px; cursor: pointer; color: var(--ink-2);
  font-size: 13px; transition: background .12s, border-color .12s;
}
.norma__unidad:hover { background: var(--surface-2); border-left-color: var(--line-2); }
.norma__unidad.is-foco { background: var(--cite-bg); border-left-color: var(--cite); }
.norma__unidad[hidden] { display: none; }
.norma__label { font-weight: 620; color: var(--ink); white-space: nowrap; }
.norma__rubrica { min-width: 0; overflow: hidden; text-overflow: ellipsis;
                  white-space: nowrap; color: var(--muted); }

/* Un dato de la ficha que además lleva a alguna parte. */
.src-enlace { border: 0; background: transparent; padding: 0; cursor: pointer;
              color: var(--accent); font: inherit;
              border-bottom: 1px solid color-mix(in srgb, var(--accent) 35%, transparent); }
.src-enlace:hover { color: var(--accent-2); border-bottom-color: var(--accent-2); }
.src-nota { font-size: 11.5px; color: var(--muted); margin: -4px 0 10px; }
.vida.is-senalada { animation: senalar 1.6s ease-out both; }
@keyframes senalar {
  0%, 60% { background: color-mix(in srgb, var(--cite) 14%, transparent); }
  100% { background: transparent; }
}

/* El apartado citado, subrayado dentro del artículo: se cita «30.2.5.ª» y hay que
   poder distinguir ese apartado en el cuerpo del 30 sin releerlo entero.
   El oro no aparece: SE PINTA, de izquierda a derecha, como una pasada de
   marcador — que es literalmente lo que la paleta dice que es este color. */
.src-text .is-apartado {
  border-left: 2px solid var(--cite);
  margin-left: -10px; padding: 2px 8px; border-radius: 0 5px 5px 0;
  background-image: linear-gradient(var(--cite-bg), var(--cite-bg));
  background-repeat: no-repeat; background-size: 100% 100%;
  animation: subrayar .6s cubic-bezier(.25,.6,.35,1) both;
}
@keyframes subrayar {
  from { background-size: 0% 100%; }
  to   { background-size: 100% 100%; }
}

.src-meta { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 14px; }
.tag { font-size: 11px; padding: 2px 8px; border-radius: 999px; border: 1px solid var(--line-2);
       color: var(--muted); background: var(--surface-2); }
.tag--ok { color: var(--ok); border-color: color-mix(in srgb, var(--ok) 35%, var(--line-2)); }
.tag--danger { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 35%, var(--line-2)); }
.tag--warn { color: var(--warn); background: color-mix(in srgb, var(--warn) 9%, transparent);
             border-color: color-mix(in srgb, var(--warn) 35%, var(--line-2)); font-weight: 560; }
/* La doctrina se ve distinta de la ley: interpreta la norma, no la sustituye. */
.tag--fecha { color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, transparent);
               border-color: color-mix(in srgb, var(--accent) 35%, var(--line-2)); }
.tag--doctrina { color: var(--cite); background: var(--cite-bg);
                 border-color: color-mix(in srgb, var(--cite) 35%, var(--line-2)); }

/* Una comprobación tampoco es la ley: es aritmética sobre sus cuadros. Se marca
   con el acento y en monoespaciada, que es como se lee un cálculo. */
.tag--calculo { color: var(--accent); background: color-mix(in srgb, var(--accent) 10%, transparent);
                border-color: color-mix(in srgb, var(--accent) 40%, var(--line-2)); font-weight: 560; }
.src-calc { font-family: var(--mono);
            font-size: 13px; line-height: 1.65; color: var(--ink); margin: 0;
            white-space: pre-wrap; word-break: break-word; }

.src-crumb { font-size: 12px; color: var(--muted); margin-bottom: 12px; line-height: 1.5; }
.src-article { margin-bottom: 20px; }
.src-article__label { font-size: 13px; font-weight: 660; color: var(--accent); margin-bottom: 2px; }
.src-article__rubric { font-family: var(--serif); font-size: 17px; font-weight: 600; margin: 0 0 10px;
                       line-height: 1.35; letter-spacing: -.01em; }
.src-text { font-family: var(--serif); font-size: 15.5px; line-height: 1.72; color: var(--ink);
            word-break: break-word; }
.src-text.is-context { font-size: 14px; color: var(--muted); }
/* Los títulos del documento (los `###` del markdown convertido de PDF). Sobrios
   y en la serif del cuerpo: son parte del texto, no de la interfaz. */
.legal-h { font-family: var(--serif); font-weight: 650; color: var(--ink);
           margin: 1.3em 0 .5em; line-height: 1.35; }
.legal-h:first-child { margin-top: 0; }
h3.legal-h { font-size: 1.08em; }
h4.legal-h { font-size: 1em; }
h5.legal-h, h6.legal-h { font-size: .94em; color: var(--ink-2);
                         font-family: var(--mono); font-weight: 700;
                         letter-spacing: .04em; text-transform: none; }

.src-text p { margin: 0 0 .85em; }
.src-text p:last-child { margin-bottom: 0; }
.src-text ul { margin: 0 0 .9em; padding-left: 1.3em; }
.src-text strong { font-weight: 650; }
.src-text small { font-size: .82em; }
.src-text code { font-family: var(--mono); font-size: .85em; background: var(--surface-2);
                 padding: 1px 5px; border-radius: 5px; }
.src-text a { color: var(--accent); text-decoration: underline;
              text-decoration-color: color-mix(in srgb, var(--accent) 40%, transparent);
              text-underline-offset: 3px; }

/* Redacción histórica: lo que regía el día de los hechos, que es lo que importa
   cuando se está defendiendo un caso. */
.src-historico { border: 1px solid color-mix(in srgb, var(--accent) 30%, var(--line));
                 border-radius: var(--radius); padding: 12px 14px; margin: 0 0 18px;
                 background: color-mix(in srgb, var(--accent) 4%, transparent); }
.src-historico__cab { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
                      font-family: var(--sans); font-size: 12px; font-weight: 620;
                      color: var(--accent); margin-bottom: 8px; }
.src-historico__ver { font-weight: 500; color: var(--muted); }
.src-historico__nota, .src-historico p { font-family: var(--sans); font-size: 12px;
                       color: var(--muted); margin: 9px 0 0; line-height: 1.5; }
.src-historico--igual, .src-historico--nada { background: var(--surface-2);
                       border-color: var(--line); }
.src-historico--igual .src-historico__cab { color: var(--ok); }
.src-historico--nada .src-historico__cab { color: var(--warn); }
.src-historico__dif { margin-top: 10px; }

/* ── La vigencia del ARTÍCULO ────────────────────────────────────────────────
   Lo primero que un jurista le pregunta al texto que tiene delante: ¿es la
   redacción original o me la tocó una reforma? Verde si es la original; el
   acento si cambió, con el «ver qué cambió» al lado. */
.vida-art { font-size: 12.5px; color: var(--muted); margin: -6px 0 12px;
            line-height: 1.5; }
.vida-art[hidden] { display: none; }
.vida-art b { color: var(--ok); font-weight: 620; }
.vida-art--cambiada b { color: var(--accent); }
.vida-art__espera { opacity: .7; font-style: italic; }

/* ── El diff de redacciones ──────────────────────────────────────────────────
   Tachado lo que decía entonces; marcado con el acento lo que dice hoy. El oro
   queda fuera a propósito: aquí significa cita, no cambio. */
.src-dif p { margin: 0 0 .85em; }
.src-dif del { color: var(--danger); text-decoration: line-through;
               text-decoration-thickness: 1px; opacity: .78; }
.src-dif ins { text-decoration: none; color: var(--ink); border-radius: 3px;
               padding: 0 1px;
               background: color-mix(in srgb, var(--accent) 13%, transparent);
               border-bottom: 1px solid color-mix(in srgb, var(--accent) 55%, transparent); }
.src-dif__leyenda { font-family: var(--sans); font-size: 11px; color: var(--muted);
                    margin: 0 0 10px; }
.src-dif__leyenda del, .src-dif__leyenda ins { font-size: inherit; }

/* ── Copiar la cita ──────────────────────────────────────────────────────────
   Al lado del texto, que es donde se decide usarla en el escrito. */
.src-copiar { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }

/* ── Quién aplica este artículo ──────────────────────────────────────────────
   Una fila por resolución, la más reciente primero: órgano en versalitas,
   fecha a la derecha y el título en dos líneas. */
.aplica { display: block; width: 100%; text-align: left; border: 1px solid var(--line);
          border-radius: var(--radius); background: transparent; padding: 8px 11px;
          margin-bottom: 7px; cursor: pointer; transition: border-color .15s; }
.aplica:hover { border-color: var(--accent); }
.aplica__cab { display: flex; align-items: baseline; justify-content: space-between;
               gap: 10px; min-width: 0; }
.aplica__org { font-family: var(--mono); font-size: 9.5px; font-weight: 700;
               letter-spacing: .08em; text-transform: uppercase; color: var(--accent);
               overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.aplica__fecha { flex: none; font-size: 11px; color: var(--muted);
                 font-variant-numeric: tabular-nums; }
.aplica__t { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
             overflow: hidden; font-size: 12.5px; color: var(--ink-2);
             line-height: 1.45; margin-top: 2px; }

/* ── Sección plegada («La norma frente a otras») ────────────────────────────
   El rótulo lleva la cuenta y hace de botón; la flecha dice el estado. */
.src-plegado { display: flex; align-items: center; gap: 7px; width: 100%;
               background: none; border: 0; padding: 0; cursor: pointer;
               text-align: left; }
.src-plegado svg { width: 13px; height: 13px; flex: none; color: var(--muted);
                   transition: transform .18s; }
.src-plegado[aria-expanded="true"] svg { transform: rotate(90deg); }
.src-plegado .src-section__title { margin-bottom: 0; }
.src-plegado:hover .src-section__title { color: var(--ink-2); }
.src-plegado__cuerpo { margin-top: 10px; }
.src-plegado__cuerpo[hidden] { display: none; }

/* Nota editorial del BOE: dice qué reforma o deroga el precepto. Es información
   de primera, no decoración, así que se marca en vez de esconderse. */
.nota-boe {
  font-family: var(--sans); font-size: 12.5px; line-height: 1.55; color: var(--ink-2);
  background: var(--surface-2); border-left: 2px solid var(--line-2);
  border-radius: 0 8px 8px 0; padding: 8px 11px; margin: 0 0 .8em;
}
.nota-boe small { font-size: 1em; }

/* Tablas del articulado (escalas del IRPF, tarifas): con scroll propio para que
   la página nunca se desplace en horizontal. */
.tabla-legal { overflow-x: auto; margin: 0 0 1em; border: 1px solid var(--line);
               border-radius: 8px; }
.tabla-legal table { border-collapse: collapse; width: 100%; font-family: var(--sans);
                     font-size: 12.5px; }
.tabla-legal th, .tabla-legal td { padding: 7px 10px; text-align: left; vertical-align: top;
                                   border-bottom: 1px solid var(--line); }
.tabla-legal th { background: var(--surface-2); font-weight: 620; white-space: nowrap;
                  position: sticky; top: 0; }
.tabla-legal tr:last-child td { border-bottom: 0; }
.tabla-legal td { font-variant-numeric: tabular-nums; }

/* Remisión a otra norma dentro del propio texto: navegable sin salir. */
.ref-norma {
  border: 0; background: var(--surface-2); color: var(--accent); cursor: pointer;
  font: inherit; font-family: var(--sans); font-size: .82em; padding: 1px 6px;
  border-radius: 5px; transition: background .14s, color .14s;
}
.ref-norma:hover { background: var(--cite-bg); color: var(--cite); }

.src-section { margin-top: 22px; padding-top: 16px; border-top: 1px solid var(--line); }
.src-section__title { font-family: var(--mono); font-size: 9.5px; font-weight: 700; letter-spacing: .14em;
                      text-transform: uppercase; color: var(--muted); margin-bottom: 10px; }
.src-neighbour { border: 1px solid var(--line); border-radius: var(--radius); padding: 10px 12px;
                 margin-bottom: 8px; cursor: pointer; transition: border-color .15s; }
.src-neighbour:hover { border-color: var(--accent); }
.src-neighbour__label { font-size: 12.5px; font-weight: 600; margin-bottom: 3px; }
.src-neighbour__preview { font-size: 12.5px; color: var(--muted); line-height: 1.5;
                          display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
                          overflow: hidden; }
.src-rel { font-size: 12.5px; color: var(--ink-2); padding: 4px 0; display: flex; gap: 7px; }
.src-rel__verb { color: var(--muted); flex: none; }
.src-rel__norm { cursor: pointer; text-decoration: underline; text-decoration-color: var(--line-2);
                 text-underline-offset: 3px; }
.src-rel__norm:hover { text-decoration-color: var(--accent); }

.src-links { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 6px; }
.src-links a { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px;
               color: var(--accent); text-decoration: none; border: 1px solid var(--line-2);
               border-radius: 999px; padding: 4px 11px; }
.src-links a:hover { border-color: var(--accent); background: var(--surface-2); }

.skeleton { background: linear-gradient(90deg, var(--surface-2) 25%, var(--line) 50%, var(--surface-2) 75%);
            background-size: 200% 100%; animation: shimmer 1.3s linear infinite;
            border-radius: 6px; height: 12px; margin-bottom: 9px; }
@keyframes shimmer { to { background-position: -200% 0; } }

/* ── Diálogo ligero ───────────────────────────────────────────────────── */
.backdrop { position: fixed; inset: 0; background: rgba(20,19,16,.42); opacity: 0;
            pointer-events: none; transition: opacity .2s; z-index: 40; }
.backdrop.is-open { opacity: 1; pointer-events: auto; }
.pop {
  position: fixed; z-index: 50; background: var(--surface); border: 1px solid var(--line-2);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); padding: 14px; width: 320px;
  max-width: calc(100vw - 32px);
}
.pop h3 { margin: 0 0 10px; font-size: 14px; font-weight: 640; }
.pop__texto { margin: -3px 0 12px; font-size: 13px; color: var(--ink-2); line-height: 1.5; }
.btn--peligro { background: var(--danger); border-color: var(--danger); color: #fff; }
.btn--peligro:hover { background: color-mix(in srgb, var(--danger) 85%, #000);
                      border-color: color-mix(in srgb, var(--danger) 85%, #000); }
.pop input, .pop select { width: 100%; padding: 8px 10px; border: 1px solid var(--line-2);
                          border-radius: 8px; background: var(--surface); color: var(--ink);
                          font: inherit; font-size: 14px; margin-bottom: 9px; outline: none; }
.pop input:focus { border-color: var(--accent); }
.pop__actions { display: flex; gap: 8px; justify-content: flex-end; }
.pop__list { max-height: 240px; overflow-y: auto; margin: -4px -4px 10px; padding: 4px; }
.pop__opt { padding: 7px 9px; border-radius: 8px; cursor: pointer; font-size: 13.5px; }
.pop__opt:hover { background: var(--surface-2); }

/* ── Paladar de comandos ─────────────────────────────────────────────────────
   Ocupa el sitio de un buscador de escritorio: centrado, por encima de todo y a
   una sola tecla. La fila seleccionada se marca con la banda de la izquierda,
   no con un fondo fuerte: se puede recorrer la lista sin que dé saltos. */
.paleta {
  position: fixed; inset: 0; z-index: 80; display: none;
  background: color-mix(in srgb, var(--ink) 26%, transparent);
  backdrop-filter: blur(3px); padding: 12vh 16px 16px;
}
.paleta.is-open { display: block; animation: fade .14s ease both; }
.paleta__caja {
  max-width: 640px; margin: 0 auto; background: var(--surface);
  border: 1px solid var(--line-2); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg); overflow: hidden;
  display: flex; flex-direction: column; max-height: 72vh;
  animation: surge .18s cubic-bezier(.22,.8,.3,1) both;
}
.paleta__barra { display: flex; align-items: center; gap: 10px; padding: 12px 12px 12px 15px;
                 border-bottom: 1px solid var(--line); }
.paleta__barra > svg { width: 17px; height: 17px; color: var(--muted); flex: none; }
.paleta__barra input { border: 0; background: transparent; font-size: 16px; flex: 1;
                       padding: 2px 0; min-width: 0; }
.paleta__barra input:focus { box-shadow: none; }
.paleta__barra .icon-btn { width: 26px; height: 26px; }
/* Al entrar en una norma, su nombre queda delante: se ve dónde se está buscando. */
.paleta__ambito {
  flex: none; max-width: 210px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  background: var(--surface-2); border-radius: 6px; padding: 3px 8px;
  font-size: 12.5px; color: var(--ink-2); font-weight: 560;
}
.paleta__lista { overflow-y: auto; padding: 6px; flex: 1; }
.paleta__grupo { font-size: 10.5px; font-weight: 660; letter-spacing: .07em; text-transform: uppercase;
                 color: var(--muted); padding: 10px 9px 5px; }
.paleta__fila {
  display: flex; align-items: center; gap: 11px; width: 100%; text-align: left;
  border: 0; background: transparent; border-left: 2px solid transparent;
  padding: 8px 10px; border-radius: 8px; cursor: pointer; color: var(--ink);
}
.paleta__fila > svg { width: 16px; height: 16px; color: var(--muted); flex: none; }
.paleta__fila.is-sel { background: var(--surface-2); border-left-color: var(--accent); }
.paleta__fila.is-sel > svg { color: var(--accent); }
.paleta__txt { min-width: 0; display: flex; flex-direction: column; gap: 1px; flex: 1; }
.paleta__txt b { font-weight: 560; font-size: 14px; overflow: hidden;
                 text-overflow: ellipsis; white-space: nowrap; }
.paleta__txt span { font-size: 12px; color: var(--muted); overflow: hidden;
                    text-overflow: ellipsis; white-space: nowrap; }
.paleta__marca { flex: none; font-size: 10.5px; font-weight: 660; letter-spacing: .04em;
                 text-transform: uppercase; color: var(--cite);
                 background: var(--cite-bg); border-radius: 999px; padding: 2px 8px; }
.paleta__vacio { padding: 22px 12px; text-align: center; font-size: 13px; color: var(--muted); }
/* El campo de la paleta es el único de la interfaz sin marco propio, así que el
   anillo azul del navegador cantaba sobre el papel. Se apaga y se sustituye por
   el foco de la casa, que va en el borde de la caja entera. */
.paleta__barra input:focus { outline: none; box-shadow: none; }
.paleta__caja:focus-within { border-color: var(--accent);
  box-shadow: var(--shadow-lg), 0 0 0 3px color-mix(in srgb, var(--accent) 14%, transparent); }
.paleta__pie { display: flex; align-items: center; gap: 14px; padding: 9px 14px;
               border-top: 1px solid var(--line); font-size: 11.5px; color: var(--muted); }
.paleta__pista { margin-left: auto; font-style: italic; overflow: hidden;
                 text-overflow: ellipsis; white-space: nowrap; }
kbd { font-family: var(--mono); font-size: 10.5px; color: var(--ink-2);
      background: var(--surface-2); border: 1px solid var(--line-2);
      border-bottom-width: 2px; border-radius: 5px; padding: 1px 5px; margin-right: 3px; }
.paleta__fila kbd { flex: none; margin: 0; }
.paleta__pista-fila { flex: none; font-size: 11px; color: var(--muted);
                      border: 1px solid var(--line); border-radius: 999px;
                      padding: 1px 8px; white-space: nowrap; }
.paleta__fila.is-sel .paleta__pista-fila { border-color: var(--line-2); color: var(--ink-2); }
@media (max-width: 720px) {
  .paleta { padding: 6vh 10px 10px; }
  .paleta__pista { display: none; }
}

.toast { position: fixed; bottom: 22px; left: 50%; transform: translateX(-50%) translateY(12px);
         background: var(--ink); color: var(--paper); padding: 9px 16px; border-radius: 999px;
         font-size: 13px; z-index: 60; opacity: 0; transition: opacity .2s, transform .2s;
         pointer-events: none; }
.toast.is-open { opacity: 1; transform: translateX(-50%) translateY(0); }

/* Consultas que corren fuera de la pantalla.
   El `toast` no valía para esto: se va solo a los dos segundos y no lleva a
   ninguna parte, y lo que hace falta aquí es exactamente ir —a la consulta que
   sigue trabajando, o a la que acaba de terminar mientras leías otra cosa—. Va
   abajo a la derecha y no centrado como el toast: el centro es para lo que
   interrumpe, y esto acompaña. */
.envuelo {
  position: fixed; right: 18px; bottom: 18px; z-index: 55;
  display: flex; flex-direction: column; gap: 8px; align-items: flex-end;
  pointer-events: none;
}
.envuelo:not(.is-open) { display: none; }
.envuelo > div { display: flex; flex-direction: column; gap: 8px; align-items: flex-end; }
.envuelo > div:empty { display: none; }
.envuelo__item {
  display: flex; align-items: center; gap: 9px; pointer-events: auto;
  background: var(--surface); border: 1px solid var(--line); border-radius: 10px;
  padding: 8px 10px 8px 12px; font-size: 12.5px; color: var(--muted);
  box-shadow: 0 14px 34px -18px rgba(27,26,23,.5);
  animation: envueloEntra .32s cubic-bezier(.22,.8,.3,1) both;
  max-width: min(360px, calc(100vw - 36px));
}
@keyframes envueloEntra { from { opacity: 0; transform: translateY(8px); } }
.envuelo__t {
  color: var(--ink); font-weight: 500; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; max-width: 190px;
}
.envuelo__seg { font-variant-numeric: tabular-nums; font-size: 11.5px; }
/* El punto que late: es lo que distingue «está trabajando» de «ahí hay una
   tarjeta». Sin él la tira parece un mensaje viejo que se te olvidó cerrar. */
.envuelo__pulso {
  width: 7px; height: 7px; border-radius: 50%; background: var(--cite);
  flex: none; animation: envueloLate 1.4s ease-in-out infinite;
}
@keyframes envueloLate { 50% { opacity: .28; transform: scale(.82); } }
.envuelo__ok { width: 15px; height: 15px; flex: none; fill: none;
               stroke: var(--ok); stroke-width: 2.4;
               stroke-linecap: round; stroke-linejoin: round; }
.envuelo__item--fin { border-color: color-mix(in srgb, var(--ok) 34%, var(--line)); }
.envuelo__b {
  border: 0; background: none; color: var(--cite); cursor: pointer;
  font: inherit; font-size: 12px; padding: 3px 7px; border-radius: 6px;
  transition: background .15s;
}
.envuelo__b:hover { background: var(--surface-2); }
.envuelo__b--x { color: var(--muted); }

/* Parar la consulta. Va junto al rótulo de la traza —donde está mirando quien
   se ha cansado de esperar— y desaparece en cuanto termina. */
.detener {
  display: inline-flex; align-items: center; gap: 5px; margin-left: 10px;
  border: 1px solid var(--line); background: none; color: var(--muted);
  border-radius: 999px; padding: 2px 9px 2px 7px; font: inherit; font-size: 11.5px;
  cursor: pointer; transition: color .15s, border-color .15s;
}
.detener:hover { color: var(--ink); border-color: var(--muted); }
.detener svg { width: 11px; height: 11px; fill: currentColor; stroke: none; }

@media (max-width: 640px) {
  .envuelo { right: 12px; bottom: 12px; left: 12px; align-items: stretch; }
  .envuelo__t { max-width: none; }
}

/* Ayuda flotante propia, en lugar del tooltip gris del navegador: sale enseguida,
   admite una segunda línea con el «para qué» y sirve para lo que el nativo no
   hacía —dar entero el nombre que el chip tuvo que recortar. */
.tip {
  position: fixed; left: 0; top: 0; z-index: 90; max-width: min(340px, calc(100vw - 24px));
  background: var(--ink); color: var(--paper); border-radius: 9px;
  padding: 7px 11px; font-size: 12.5px; line-height: 1.35; text-align: left;
  box-shadow: 0 10px 28px -14px rgba(27,26,23,.55); pointer-events: none;
  opacity: 0; transform: translateY(3px);
  transition: opacity .13s ease, transform .13s ease;
}
.tip.is-open { opacity: 1; transform: none; }
.tip--abajo { transform: translateY(-3px); }
.tip__txt { display: block; font-weight: 520; }
.tip__nota { display: none; }
.tip--doble .tip__nota {
  display: block; margin-top: 2px; font-size: 11.5px; font-weight: 400;
  color: color-mix(in srgb, var(--paper) 60%, transparent);
}
/* La flecha se coloca sobre el elemento señalado, no en el centro de la caja:
   si la caja se pega a un borde de la ventana, sigue apuntando a su sitio. */
.tip::after {
  content: ''; position: absolute; left: var(--flecha, 50%); top: 100%;
  transform: translateX(-50%);
  border: 5px solid transparent; border-top-color: var(--ink); border-bottom: 0;
}
.tip--abajo::after {
  top: auto; bottom: 100%;
  border: 5px solid transparent; border-bottom-color: var(--ink); border-top: 0;
}

/* ── Responsive ───────────────────────────────────────────────────────── */
@media (max-width: 1180px) {
  :root { --source-w: 380px; }
}
@media (max-width: 980px) {
  .app { grid-template-columns: minmax(0, 1fr); }
  .app.source-open, .app.sidebar-hidden, .app.sidebar-hidden.source-open {
    grid-template-columns: minmax(0, 1fr);
  }
  .sidebar { position: fixed; inset: 0 auto 0 0; width: 86vw; max-width: 320px; z-index: 45;
             transform: translateX(-102%); transition: transform .26s cubic-bezier(.22,.8,.3,1);
             box-shadow: var(--shadow-lg); padding: 14px 12px; border-right: 1px solid var(--line); }
  .app:not(.sidebar-hidden) .sidebar { transform: none; }
  #showSidebar { display: inline-flex; }
  .source { position: fixed; inset: 0 0 0 auto; width: min(94vw, 460px); z-index: 46;
            transform: translateX(102%); transition: transform .26s cubic-bezier(.22,.8,.3,1);
            box-shadow: var(--shadow-lg); }
  .app.source-open .source { transform: none; }
  .thread { padding: 18px 14px 4px; }
  .composer-wrap { padding: 4px 14px 12px; }

  /* Un cajón sin velo detrás no parece un cajón: parece que la maquetación se ha
     roto. El velo además dice que el resto está esperando, y se cierra tocándolo,
     que es lo que todo el mundo intenta primero. */
  .scrim { position: fixed; inset: 0; z-index: 44; opacity: 0; pointer-events: none;
           background: color-mix(in srgb, var(--ink) 42%, transparent);
           transition: opacity .26s cubic-bezier(.22,.8,.3,1); }
  .app:not(.sidebar-hidden) .scrim, .app.source-open .scrim { opacity: 1; pointer-events: auto; }
}

@media (max-width: 640px) {
  /* En un teléfono el panel de la fuente es una LÁMINA desde abajo, con asa: a
     media altura se leen a la vez la respuesta y el artículo —que es justo el
     gesto de verificar una cita— y del asa se sube a casi pantalla completa o
     se tira hacia abajo para cerrar (initSheet en app.js). */
  .source {
    /* Porcentajes y no dvh: en un elemento fijo el % resuelve contra el
       viewport y no se rompe con el zoom de página (los dvh sí). */
    inset: auto 0 0 0; width: 100%; max-width: none; height: 62%;
    border-left: 0; border-top: 1px solid var(--line);
    border-radius: 16px 16px 0 0;
    transform: translateY(103%);
    transition: transform .3s cubic-bezier(.22,.8,.3,1),
                height .3s cubic-bezier(.22,.8,.3,1);
  }
  .app.source-open .source { transform: translateY(0); }
  .source.is-alta { height: calc(100% - 34px); }
  /* Mientras se arrastra, el panel sigue al dedo sin muelle de por medio. */
  .source.is-arrastre { transition: none; }
  .source__asa { display: flex; }
  /* El pie legal iba clavado bajo el cajón de escribir y se comía un cuarto de
     la pantalla. Sigue estando —es obligatorio y no se esconde— pero ocupa lo
     que le corresponde. */
  .composer-wrap { padding: 4px 12px 8px; }
  .composer__note { font-size: 10.5px; line-height: 1.35; margin: 6px 0 3px; }
  .legal { font-size: 10.5px; gap: 10px; padding-top: 2px; }
}

/* ── Movimiento ───────────────────────────────────────────────────────────
   Lo justo para que la interfaz explique lo que pasa: la respuesta entra,
   la fuente se desliza, la traza late mientras se piensa. Nada gratuito. */

@keyframes surge { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@keyframes fade  { from { opacity: 0; } to { opacity: 1; } }

/* Cambio de tema con revelado circular (View Transitions): el tema nuevo se
   expande en círculo desde el botón de la luna. Sin fundido cruzado del
   navegador —la capa nueva RECORTA a la vieja—; el círculo lo anima applyTheme
   en app.js, y donde no hay soporte el tema cambia seco, como siempre. */
::view-transition-old(root), ::view-transition-new(root) {
  animation: none; mix-blend-mode: normal;
}
::view-transition-old(root) { z-index: 1; }
::view-transition-new(root) { z-index: 2; }
@keyframes slideIn { from { opacity: 0; transform: translateX(14px); } to { opacity: 1; transform: none; } }
@keyframes sheen {
  0%   { background-position: -180% 0; }
  100% { background-position: 180% 0; }
}

.msg { animation: surge .34s cubic-bezier(.22,.8,.3,1) both; }
.welcome { animation: fade .5s ease both; }
.ejemplos__lista li { animation: surge .4s cubic-bezier(.22,.8,.3,1) both; }
.ejemplos__lista li:nth-child(1) { animation-delay: .03s; }
.ejemplos__lista li:nth-child(2) { animation-delay: .06s; }
.ejemplos__lista li:nth-child(3) { animation-delay: .09s; }
.ejemplos__lista li:nth-child(4) { animation-delay: .12s; }
.ejemplos__lista li:nth-child(5) { animation-delay: .15s; }
.ejemplos__lista li:nth-child(n+6) { animation-delay: .18s; }
.pop { animation: surge .18s cubic-bezier(.22,.8,.3,1) both; }
.source__body > * { animation: slideIn .3s cubic-bezier(.22,.8,.3,1) both; }
.src-cit, .src-rows__n, .src-rows__a { animation: fade .3s ease both; }
.trace__step { animation: surge .22s ease both; }

/* Mientras el modelo trabaja, el rótulo de la traza recorre un brillo: dice
   «sigo aquí» sin ocupar sitio ni pedir atención. La rejilla (.churn) solo
   existe hasta que la respuesta está lista, así que el brillo se apaga solo. */
.churn ~ [data-trace-label] {
  background-image: linear-gradient(90deg, var(--muted) 20%, var(--ink) 50%, var(--muted) 80%);
  background-size: 200% 100%;
  background-clip: text; -webkit-background-clip: text; color: transparent;
  animation: sheen 2.2s linear infinite;
}

/* El botón de enviar acusa el envío. */
.btn--send:active svg { transform: translateX(2px); }
.btn--send svg { transition: transform .12s; }

/* La cita late una vez al abrirse, para que se vea qué se ha pulsado. */
@keyframes citeOpen {
  0%   { box-shadow: inset 0 -2px 0 var(--cite), 0 0 0 0 color-mix(in srgb, var(--cite) 45%, transparent); }
  100% { box-shadow: inset 0 -2px 0 var(--cite), 0 0 0 7px transparent; }
}
.cite.is-open { animation: citeOpen .5s ease-out; }

/* Y al aterrizar la verificación —solo en la respuesta que acaba de llegar—
   cada cita acusa el momento con UN destello escalonado de arriba abajo. Nunca
   en bucle: el oro tiene contrato semántico y un brillo continuo lo abarataría.
   Al reabrir una consulta guardada las citas entran quietas. */
.msg--recien .cite {
  animation: glintCita .8s ease-out both;
  animation-delay: var(--gd, 0ms);
}
@keyframes glintCita {
  0%   { background-color: var(--cite-bg); }
  40%  { background-color: var(--cite-bg-2);
         box-shadow: inset 0 -2px 0 var(--cite); }
  100% { background-color: var(--cite-bg); }
}

/* ── Estados de la respuesta y filtros activos ────────────────────────── */
/* Tres estados y tres colores, en esta escala: verde la respuesta verificada,
   gris la que el propio texto declara incompleta, ámbar la que lleva avisos.
   El gris no es un color menor: es exactamente lo que significa «esto no está
   mal, es que falta». Sin inventar un cuarto tono en una paleta de tres. */
.trace__parcial { color: var(--muted); }

.notice--info { border-color: color-mix(in srgb, var(--accent) 28%, var(--line));
                background: color-mix(in srgb, var(--accent) 6%, transparent);
                color: var(--ink-2); }
.notice svg { width: 16px; height: 16px; flex: none; margin-top: 1px;
              fill: none; stroke: currentColor; stroke-width: 1.7;
              stroke-linecap: round; stroke-linejoin: round; }

.msg__reintento { margin-bottom: 14px; }
.btn--ghost { display: inline-flex; align-items: center; gap: 7px; font-size: 13px;
              padding: 7px 13px; border-radius: 999px; border: 1px solid var(--line-2);
              background: var(--surface); color: var(--ink-2); cursor: pointer; }
.btn--ghost:hover { border-color: var(--accent); color: var(--accent); }
.btn--ghost svg { width: 15px; height: 15px; fill: none; stroke: currentColor;
                  stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }

/* Derecho civil foral: seis territorios donde la respuesta es otra. Se ofrece
   repetir la consulta en el suyo, que es lo único útil que se puede hacer con
   ese aviso. */
.foral { margin-top: 18px; padding: 12px 14px; border: 1px dashed var(--line-2);
         border-radius: var(--radius); background: color-mix(in srgb, var(--surface-2) 45%, transparent); }
.foral__txt { font-size: 13px; color: var(--ink-2); margin-bottom: 9px; }
.foral__ccaa { display: flex; flex-wrap: wrap; gap: 6px; }
.chip-btn { font: inherit; font-size: 12.5px; padding: 5px 11px; border-radius: 999px;
            border: 1px solid var(--line-2); background: var(--surface);
            color: var(--ink-2); cursor: pointer; }
.chip-btn:hover { border-color: var(--accent); color: var(--accent); }

/* Un filtro puesto cambia la respuesta entera: mientras lo haya, el cajón
   entero lo dice. El chip de fecha solo se distinguía de sus vecinos por el
   color del borde, y con «15 jun 2019» puesto se contestaba con el derecho de
   hace siete años sin que nada llamara la atención. */
.composer.is-filtrado { border-color: color-mix(in srgb, var(--accent) 45%, var(--line-2));
                        box-shadow: var(--shadow), inset 3px 0 0 var(--accent); }
.select.is-on { border-color: var(--accent); color: var(--accent); }
.chip-toggle.is-on { color: var(--accent); }
/* `display` explícito le gana al atributo `hidden` de la hoja del navegador, así
   que el botón salía siempre, incluso sin nada que limpiar. */
.chip-limpiar[hidden] { display: none; }
.chip-limpiar { display: inline-flex; align-items: center; gap: 5px; font: inherit;
                font-size: 12.5px; padding: 5px 10px; border-radius: 999px;
                border: 1px dashed var(--line-2); background: transparent;
                color: var(--muted); cursor: pointer; }
.chip-limpiar:hover { border-color: var(--danger); color: var(--danger); border-style: solid; }
.chip-limpiar svg { width: 12px; height: 12px; fill: none; stroke: currentColor;
                    stroke-width: 2; stroke-linecap: round; }

/* Se lee en voz alta y no se ve: para lo que la pantalla ya dice de otra forma. */
.solo-lector { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
               overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* ── Aviso de prueba ─────────────────────────────────────────────────────────
   Quien pregunta sin cuenta ve la respuesta entera, pero no se le guarda nada.
   El aviso va DENTRO de la respuesta y con el botón al lado: descubrirlo al
   recargar, con la consulta ya perdida, es la peor manera de enterarse. */
.prueba {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 18px;
  padding: 12px 14px;
  border: 1px dashed var(--line);
  border-radius: 10px;
  background: var(--bg-soft, transparent);
  font-size: 13px;
  color: var(--muted);
}
.prueba span { flex: 1 1 260px; line-height: 1.45; }
.prueba .btn { flex: 0 0 auto; }

/* El hueco de la cuenta en la barra: el nombre no puede empujar al resto. */
#cuenta { display: flex; align-items: center; }
#cuenta .btn { max-width: 168px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* `hidden` significa oculto, también cuando la clase del elemento trae su
   propio `display`. El botón de descargar la tabla es un `.btn` —`inline-flex`—
   y salía a la vista con el atributo puesto: la regla del navegador para
   `[hidden]` es `display: none` sin más peso que cualquier otra. */
[hidden] { display: none !important; }

/* ── El expediente ───────────────────────────────────────────────────────────
   Los documentos que trae el usuario, en el panel de la izquierda: la misma
   fila que un cliente o una consulta, con su estado mientras se procesa. */
.doc-list { display: flex; flex-direction: column; gap: 1px; }
.doc-item {
  display: flex; align-items: center; gap: 8px; padding: 6px 8px;
  border-radius: 8px; cursor: pointer; font-size: 13px; color: var(--ink-2);
}
.doc-item:hover { background: var(--line); color: var(--ink); }
.doc-item svg { width: 14px; height: 14px; flex: none; color: var(--muted); }
.doc-item__name { flex: 1; min-width: 0; overflow: hidden;
                  text-overflow: ellipsis; white-space: nowrap; }
.doc-item__meta { font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums; }
.doc-item__estado { font-size: 11px; color: var(--cite); }
.doc-item.is-wait .doc-item__name { color: var(--muted); }
.doc-item.is-wait svg { animation: latido 1.4s ease-in-out infinite; }
.doc-item.is-error .doc-item__estado { color: var(--danger); }
/* Quitado de la consulta: se ve que está y que no entra. */
.doc-item.is-off .doc-item__name { opacity: .45; text-decoration: line-through;
                                   text-decoration-thickness: 1px; }
.doc-item.is-off svg { opacity: .45; }
@keyframes latido { 0%, 100% { opacity: .35 } 50% { opacity: 1 } }

.doc-vacio {
  display: grid; gap: 3px; width: 100%; text-align: left; cursor: pointer;
  padding: 10px 10px; border: 1px dashed var(--line-2); border-radius: var(--radius);
  background: transparent; color: var(--ink-2); font: inherit; font-size: 12.5px;
}
.doc-vacio:hover { border-color: var(--accent); color: var(--ink); }
.doc-vacio strong { font-weight: 580; line-height: 1.35; }
.doc-vacio span { color: var(--muted); font-size: 11.5px; }
#grupoExpediente.is-drop { outline: 2px dashed var(--cite); outline-offset: 3px;
                           border-radius: var(--radius); }

.btn--tabla { width: 100%; margin: 8px 0 0; justify-content: center; }
.btn--tabla svg { width: 13px; height: 13px; }

/* El clip del compositor: qué documentos entran en la respuesta. */
.chip-exp.is-on { border-color: color-mix(in srgb, var(--cite) 45%, var(--line-2));
                  background: var(--cite-bg); color: var(--cite); }
.chip-exp span { max-width: 190px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.pop__check { display: flex; align-items: center; gap: 9px; padding: 6px 8px;
              border-radius: 8px; font-size: 13.5px; cursor: pointer; }
.pop__check:hover { background: var(--surface-2); }
.pop__check input { width: auto; margin: 0; flex: none; accent-color: var(--accent); }
.pop__check span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Soltar un fichero sobre la conversación. El velo solo aparece con ficheros
   dentro: arrastrar una consulta a una carpeta ya significa otra cosa. */
.soltar {
  position: absolute; inset: 0; z-index: 40; display: none; place-items: center;
  background: color-mix(in srgb, var(--paper) 84%, transparent);
  backdrop-filter: blur(2px);
}
.main.is-dropping .soltar { display: grid; }
.soltar__caja {
  display: grid; gap: 4px; justify-items: center; text-align: center;
  padding: 26px 34px; border: 2px dashed var(--line-2); border-radius: var(--radius-lg);
  background: var(--surface); font-size: 14.5px; font-weight: 560; color: var(--ink);
  box-shadow: var(--shadow);
}
.soltar__caja span { font-size: 12.5px; font-weight: 400; color: var(--muted); }
.main { position: relative; }

/* El documento abierto en el panel de la fuente: entero, con el fragmento
   citado subrayado — el vecino de una cláusula es el resto del contrato. */
.tag--exp { color: var(--cite); border-color: color-mix(in srgb, var(--cite) 40%, var(--line-2));
            background: var(--cite-bg); }
.doc-body { display: flex; flex-direction: column; gap: 14px; margin-bottom: 16px; }
.doc-frag { border-left: 2px solid var(--line); padding: 2px 0 2px 12px; }
.doc-frag h4 { margin: 0 0 4px; font-size: 12.5px; font-weight: 640; color: var(--ink);
               display: flex; align-items: baseline; gap: 7px; flex-wrap: wrap; }
.doc-frag h4 em { font-style: normal; font-weight: 400; color: var(--muted); }
.doc-frag__p { margin-left: auto; font-size: 11px; color: var(--muted);
               font-variant-numeric: tabular-nums; }
.doc-frag p { margin: 0; font-family: var(--serif); font-size: 14px; line-height: 1.62;
              color: var(--ink-2); white-space: pre-wrap; }
.doc-frag.is-cited { border-left-color: var(--cite); background: var(--cite-bg);
                     border-radius: 0 8px 8px 0; padding-right: 10px; }
.doc-frag.is-cited p { color: var(--ink); }

/* ── Revisión en tabla ──────────────────────────────────────────────────────
   N documentos × M columnas. Ocupa la pantalla porque es la pantalla: leer una
   tabla de veinte contratos en una columna de 440 píxeles no se puede. */
.revision {
  position: fixed; inset: 0; z-index: 85; display: none; padding: 5vh 16px 16px;
  background: color-mix(in srgb, var(--ink) 30%, transparent); backdrop-filter: blur(3px);
}
.revision__caja {
  max-width: 1180px; height: 90vh; margin: 0 auto; display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--line-2);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); overflow: hidden;
  animation: surge .18s cubic-bezier(.22,.8,.3,1) both;
}
.revision__barra { display: flex; align-items: center; gap: 12px; padding: 14px 16px;
                   border-bottom: 1px solid var(--line); }
.revision__titulo { flex: 1; min-width: 0; }
.revision__titulo h2 { margin: 0; font-family: var(--display); font-size: 18px; font-weight: 600; }
.revision__sub { font-size: 12.5px; color: var(--muted); }
.revision__acciones { display: flex; align-items: center; gap: 8px; }
.revision__cuerpo { flex: 1; overflow: auto; padding: 16px; }

.rev-form { display: grid; grid-template-columns: 1fr 1.4fr; gap: 22px; }
.rev-form__col h3 { margin: 0 0 10px; font-size: 13px; font-weight: 640; color: var(--ink); }
.rev-docs { max-height: 46vh; overflow: auto; border: 1px solid var(--line);
            border-radius: var(--radius); padding: 6px; }
.rev-plantillas { display: grid; gap: 8px; }
.rev-plant {
  display: grid; gap: 2px; text-align: left; padding: 10px 12px; cursor: pointer;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--paper); color: var(--ink); font: inherit;
}
.rev-plant:hover { border-color: var(--line-2); }
.rev-plant.is-on { border-color: var(--accent); background: var(--surface-2); }
.rev-plant strong { font-size: 13.5px; font-weight: 620; }
.rev-plant span { font-size: 12.5px; color: var(--ink-2); }
.rev-plant em { font-style: normal; font-size: 11.5px; color: var(--muted); }
.rev-libres { width: 100%; margin-top: 10px; padding: 9px 11px; font: inherit; font-size: 13px;
              border: 1px solid var(--line-2); border-radius: var(--radius);
              background: var(--paper); color: var(--ink); resize: vertical; }
/* El botón que lanza la revisión NO puede quedar bajo el pliegue: con cuatro
   plantillas y la caja de columnas propias, la acción principal empezaba fuera
   de la pantalla y había que descubrirla haciendo scroll. Se queda pegado abajo
   mientras el formulario se desplaza detrás. */
.rev-pie { display: flex; align-items: center; gap: 16px; margin-top: 18px;
           padding: 14px 0 2px; border-top: 1px solid var(--line);
           position: sticky; bottom: -16px; background: var(--surface); }
.rev-pie__nota { flex: 1; font-size: 12.5px; color: var(--muted); line-height: 1.5; }
.rev-espera { padding: 40px; text-align: center; color: var(--muted); font-size: 13.5px; }

.rev-tabla-wrap { overflow: auto; border: 1px solid var(--line); border-radius: var(--radius); }
.rev-tabla { border-collapse: collapse; width: 100%; font-size: 12.5px;
             line-height: 1.45; }
.rev-tabla th, .rev-tabla td { border-bottom: 1px solid var(--line);
                               border-right: 1px solid var(--line);
                               padding: 8px 10px; text-align: left; vertical-align: top; }
.rev-tabla thead th { position: sticky; top: 0; z-index: 1; background: var(--surface-2);
                      font-weight: 620; white-space: nowrap; }
.rev-tabla tbody th { position: sticky; left: 0; background: var(--surface);
                      font-weight: 580; max-width: 230px; }
/* Ancho de columna: 300 y no 260 porque la casilla se lee en horizontal. Con
   una columna estrecha, una respuesta de dos líneas ocupaba diez y la tabla
   dejaba de poder recorrerse de un vistazo, que es para lo que existe. */
.rev-cel { max-width: 300px; min-width: 120px; }
.rev-cel button { all: unset; cursor: pointer; display: block; }
.rev-cel button:hover { color: var(--cite); }
.rev-cel button em { display: block; font-style: normal; font-size: 10.5px;
                     color: var(--muted); margin-top: 3px; }
.rev-cel button:hover em { color: var(--cite); }
.rev-cel.is-vacia { color: var(--muted); }
/* Una casilla con contenido y sin fragmento que la sostenga se ve que no lo
   tiene: es el mismo criterio que con una cita que no resuelve. */
.rev-cel.is-sin-cita { color: var(--ink-2); border-bottom-color: var(--line);
                       background: color-mix(in srgb, var(--warn) 9%, transparent); }
.rev-cel--error { color: var(--danger); }
.rev-cel.is-wait i { display: block; width: 42px; height: 8px; border-radius: 4px;
                     background: var(--line); animation: latido 1.4s ease-in-out infinite; }
.rev-tabla tr.is-wait th { color: var(--muted); }

@media (max-width: 860px) {
  .rev-form { grid-template-columns: 1fr; }
  .revision { padding: 0; }
  .revision__caja { height: 100vh; border-radius: 0; border: 0; }
}
