/* ============================================================
   Caigua 3.0 — Base y componentes
   Requiere tokens.css cargado antes.
   ============================================================ */

/* --- Reinicio --------------------------------------------------- */

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

* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

body {
  background: var(--c-surface);
  color: var(--c-ink);
  font-family: var(--font-ui);
  font-size: var(--t-base);
  line-height: var(--lh-base);
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
}

img, picture, svg, video {
  display: block;
  max-width: 100%;
  height: auto;
}

input, button, textarea, select { font: inherit; color: inherit; }

/* --- Tipografía -------------------------------------------------- */

/* Los títulos son nombres de plantas, y siguen teniendo voz propia: la que era
   serif desde #98 pasa a Caprasimo (#278). Los rótulos de interfaz
   —`.panel__titulo`, `.rotulo`— se quedan en sans y se declaran aparte.

   Caprasimo solo tiene el 400 y ya es una display de trazo grueso: pedirle
   negrita la sintetiza el navegador y sale emborronada. */
h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: var(--fw-normal);
  line-height: var(--lh-tight);
  text-wrap: balance;
  color: var(--c-ink);
}

/* Rótulo en versalitas espaciadas, como la etiqueta de un pliego. Es una pieza
   del sistema, no un `text-transform` suelto en una plantilla. */
.rotulo {
  font-family: var(--font-ui);
  font-size: var(--t-sm);
  text-transform: uppercase;
  letter-spacing: var(--ls-rotulo);
  font-weight: var(--fw-bold);
  color: var(--c-ink-faint);
}

h1 { font-size: var(--t-3xl); letter-spacing: -0.02em; }
h2 { font-size: var(--t-2xl); letter-spacing: -0.01em; }
h3 { font-size: var(--t-xl); }
h4 { font-size: var(--t-lg); line-height: var(--lh-snug); }

/* Sin subrayado por defecto, como hace Ant Design y como se veía la 2.x. La
   excepción es `.prose`, más abajo: dentro de un párrafo, el color no basta
   para saber que algo es un enlace, y ahí el subrayado no se negocia. */
a {
  color: var(--c-primary);
  text-decoration: none;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.15em;
}
a:hover { color: var(--c-primary-hover); text-decoration: underline; }

/* 3px y no 2: el anillo tiene que verse sin buscarlo, y con 2px sobre un borde
   de campo ya azulado casi no se distingue de un `:hover`. El color sale de
   `--c-focus`, que cada superficie puede redefinir — ver la barra lateral. */
:focus-visible {
  outline: 3px solid var(--c-focus);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

/* Enlace de salto para lectores de pantalla y teclado */
.skip-link {
  position: absolute;
  left: -9999px;
  top: var(--s-2);
  background: var(--c-nav);
  color: var(--c-ink-on-dark);
  padding: var(--s-2) var(--s-4);
  border-radius: var(--r-md);
  z-index: 100;
}
.skip-link:focus { left: var(--s-2); }

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* --- Prosa: el cuerpo de las fichas de la wiki ------------------- */

/* El artículo botánico es lo único del sitio que se lee seguido. Iba en serif
   desde #98; con Organic se queda en la de interfaz (#278), y lo que le da
   aire ahora es la interlínea, no el cambio de letra. Los 17px eran para la
   serif, que pedía un punto más; Figtree no lo necesita. */
.prose {
  font-family: var(--font-ui);
  font-size: var(--t-base);
  line-height: var(--lh-prose);
  max-width: var(--w-prose);
}

/* Un enlace en mitad de una frase, distinguido solo por el color, no lo ve
   quien no separa ese azul del negro. Aquí el subrayado es siempre. */
.prose a { text-decoration: underline; }

.prose > * + * { margin-top: var(--s-4); }

/* Prosa dentro de algo que no es un artículo (#147): el detalle de la
   germinación vive en una fila del panel de datos, en la columna de la derecha
   de una rejilla de dos. Hereda el Markdown —negritas, listas, enlaces— pero no
   la tipografía de lectura larga ni la medida máxima, que ahí descuadrarían la
   fila respecto a las de al lado. Un párrafo suelto ocupa lo que ocupaba
   cuando era texto plano, que es la condición para que esto no se note. */
.prose--llano {
  font-family: inherit;
  font-size: inherit;
  line-height: inherit;
  max-width: none;
}

.prose--llano > * + * { margin-top: var(--s-2); }

.prose h2 { margin-top: var(--s-7); font-family: var(--font-ui); }
.prose h3 { margin-top: var(--s-6); font-family: var(--font-ui); }
/* El sangrado **y la viñeta**. Devolver la viñeta hace falta desde que entró
   Tailwind (#92): su `preflight` pone `list-style: none` a toda lista, y el
   contenido botánico de las fichas viene en Markdown, lleno de listas que se
   quedaban sin marca. Es el único destrozo que hizo el reinicio del kit. */
.prose ul, .prose ol { padding-left: var(--s-5); }
.prose ul { list-style: disc; }
.prose ol { list-style: decimal; }
.prose li + li { margin-top: var(--s-2); }

.prose blockquote {
  border-left: 3px solid var(--c-primary);
  padding-left: var(--s-4);
  color: var(--c-ink-soft);
  font-style: italic;
}

.prose code {
  font-family: var(--font-mono);
  font-size: 0.9em;
  background: var(--c-surface-alt);
  padding: 0.1em 0.35em;
  border-radius: var(--r-sm);
}

/* --- Disposición -------------------------------------------------- */

.page {
  max-width: var(--w-page);
  margin-inline: auto;
  width: 100%;
  padding: var(--s-5) var(--s-4);
}

.stack > * + * { margin-top: var(--s-4); }
.stack-lg > * + * { margin-top: var(--s-6); }

.cluster {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  align-items: center;
}

/* 280px de mínimo y no 240: por debajo de eso, la portada de 400px de alto de
   la 2.x queda más alta que ancha y la tarjeta se convierte en una columna. */
/* 220px desde #101: con la portada en 3:2 en vez de 400px de alto, la tarjeta
   deja de ser una columna y caben cuatro por fila en un portátil. */
/* Cuatro por fila a la anchura de página (#280): con `--w-page` en 1200 y 20px
   de hueco, la tarjeta sale a 285. El mínimo sube de 220 a 250 porque la
   portada pasó a 4:3 y con 220 volvía a quedarse en una banda. */
.grid-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 20px;
}

/* En el móvil, dos por fila. Con una sola, una página de 24 fichas son diez
   mil píxeles de scroll, y la proporción 3:2 deja sitio de sobra para dos:
   a 390px salen tarjetas de 171px, con la portada en 114 de alto. */
/* Dos por fila hasta 560 px, y a esa anchura el mínimo de 250 de arriba no cabe
   dos veces: hay que bajarlo aquí o la rejilla se sale de la pantalla. */
@media (max-width: 560px) {
  .grid-cards {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: var(--s-4);
  }
  .card__body { padding: var(--s-3); }
}

/* --- Armazón: barra superior y pie -------------------------------- */

/* Un solo armazón para leer y para trabajar (#98). La barra lateral de 240px
   desapareció: quien llegaba sin sesión veía dos enlaces rodeados de cromo de
   herramienta en una página de contenido. */

.armazon { min-height: 100vh; display: flex; flex-direction: column; }

/* La escalera de apilamiento del sitio, escrita una vez (#190):
 *
 *   20  el área de escritura de Toast UI. **No es nuestra**: el paquete pone
 *       `position: relative` en `.ProseMirror` y `z-index: 20` en
 *       `.toastui-editor-contents`, y su CSS está copiado tal cual y se vuelve
 *       a copiar al actualizar. Es el suelo con el que hay que contar.
 *   30  el cromo que tiene que quedar a la vista mientras se trabaja: esta
 *       barra —con la miga dentro— y la de guardar de #148. Por encima del
 *       editor, que si no la prosa les pasa por encima al desplazar.
 *   50  el visor de fotos, que ocupa la pantalla entera y sí tapa la cabecera.
 *  100  el enlace de salto, que gana a todo o no sirve de nada.
 */
.barra {
  position: sticky;
  top: 0;
  z-index: 30;
  background: var(--c-surface-raised);
  border-bottom: 1px solid var(--c-border);
}

.barra__fila {
  max-width: var(--w-page);
  margin-inline: auto;
  width: 100%;
  display: flex;
  align-items: center;
  gap: var(--s-4);
  min-height: var(--h-barra);
  padding: var(--s-2) var(--s-4);
  flex-wrap: wrap;
}

.barra__marca {
  font-family: var(--font-display);
  font-size: var(--t-lg);
  font-weight: var(--fw-bold);
  letter-spacing: -0.01em;
  color: var(--c-ink);
  text-decoration: none;
  white-space: nowrap;
}
.barra__marca:hover { color: var(--c-ink); }

.barra__logo {
  height: 1.75rem;
  width: auto;
  max-width: 160px;
  object-fit: contain;
}

/* Lo que cede cuando falta sitio es la navegación (#221).

   `.barra__fila` envuelve, y en el HTML el orden es marca → navegación →
   buscador → sesión, así que lo que bajaba de línea era **lo último**: el
   nombre de usuario, debajo de la marca. Se notó al añadir el séptimo enlace
   con el registro de cambios (#74), y solo le pasaba a quien más permisos
   tiene, que es justo quien más enlaces ve.

   Por debajo de 860px esto ya estaba resuelto por la consulta de medios, que
   manda buscador y navegación a sus propias líneas. Lo que faltaba era la
   franja de en medio.

   `min-width: 0` es lo que de verdad lo permite: un contenedor flexible no se
   encoge por debajo de su contenido mínimo sin esto, por mucho `flex-shrink`
   que traiga de fábrica. */
.barra__nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-4);
  font-size: var(--t-base);
  flex: 1 1 auto;
  min-width: 0;
}

.barra__enlace {
  color: var(--c-ink-soft);
  text-decoration: none;
  padding: var(--s-2) 0;
  white-space: nowrap;
}
.barra__enlace:hover { color: var(--c-ink); text-decoration: none; }

/* La sección actual lleva peso y filete. El filete la distingue también para
   quien no separe el azul del gris: el color no puede ser la única señal. */
.barra__enlace--activo {
  color: var(--c-ink);
  font-weight: var(--fw-medium);
  box-shadow: inset 0 -2px 0 var(--c-primary);
}

.barra__buscar {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: var(--s-2);
  background: var(--c-surface);
  border: 1px solid var(--c-border-strong);
  border-radius: var(--r-full);
  padding-inline: var(--s-3);
  min-width: 12rem;
  flex: 0 1 18rem;
}
.barra__buscar:focus-within { border-color: var(--c-primary); }

.barra__lupa { width: 16px; height: 16px; color: var(--c-ink-faint); flex: 0 0 auto; }

/* El campo no lleva `.input`: dentro de la píldora sobra su borde y su fondo. */
.barra__campo {
  flex: 1;
  min-width: 0;
  min-height: 40px;
  border: 0;
  background: none;
  color: inherit;
  outline: none;
}
.barra__campo::placeholder { color: var(--c-ink-faint); }

/* La sesión no baja de línea nunca (#221): es donde se entra, se sale y está
   el menú de la cuenta, y una barra en la que el nombre cambia de sitio según
   los permisos de quien mira es una barra que se mueve sola. */
.barra__sesion {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  font-size: var(--t-base);
  flex: 0 0 auto;
}

/* Sin buscador —el host de la app no lo tiene— la sesión ocupa su sitio. */
.barra__nav + .barra__sesion { margin-left: auto; }

/* Por encima del punto de ruptura la fila **no envuelve** (#223).

   #221 hizo que la navegación cediera antes que la sesión, y no bastó: mientras
   la fila pueda envolver, cualquier elemento nuevo puede volver a empujar el
   nombre de usuario a una segunda línea, y el que lo empuja es siempre el
   último de la fila. Con `nowrap` eso deja de ser posible: lo que sobra se
   desplaza dentro de la navegación, que es exactamente lo que ya hace la
   disposición estrecha de aquí abajo.

   La garantía la da **que la fila no envuelva**, y nada más. La navegación
   llevó además `overflow-x: auto` durante dos commits, y fue un error (#225):
   un elemento con `overflow` crea un contenedor de recorte, así que el panel
   del menú de #223 quedaba encerrado en la franja de la barra y el navegador
   sacaba desplazamiento para poder enseñarlo. Lo que sobra se reparte dentro
   de la navegación en dos líneas, que crece la barra de alto y no recorta
   nada. */
@media (min-width: 860px) {
  .barra__fila { flex-wrap: nowrap; }
}

@media (max-width: 859px) {
  .barra__fila { gap: var(--s-3); }
  .barra__buscar { order: 3; flex: 1 1 100%; margin-left: 0; }
  /* Sin `overflow-x: auto` (#225): recortaba el panel del menú igual que
     arriba, y aquí venía de antes. Envolver en tres líneas en un móvil es
     mejor que un desplazamiento que esconde enlaces y encierra el menú. */
  .barra__nav { order: 4; flex: 1 1 100%; gap: var(--s-5); flex-wrap: wrap; }
  .barra__sesion { margin-left: auto; }
}

/* El pie cierra la página (#285): salvia muy oscura y texto crema, no papel
   alzado con un filete arriba. Los ratios sobre `--c-nav`: la crema da 11.8:1 y
   el wash de salvia de los enlaces, 13.0:1. */
.site-footer {
  background: var(--c-nav);
  padding-block: var(--s-6);
  /* `auto` y no una medida: `.armazon` es una columna flex de alto mínimo la
     pantalla, y esto es lo que empuja el pie abajo del todo en una página
     corta. Cambiándolo por un margen fijo se quedaba a media pantalla con una
     franja de crema debajo. */
  margin-top: auto;
  color: var(--c-ink-on-dark);
  font-size: var(--t-sm);
  text-align: center;
}

.site-footer__nombre {
  font-family: var(--font-display);
  font-size: var(--t-md);
  margin-bottom: var(--s-3);
}

/* Los enlaces del pie no se pintan con `--c-primary`: sobre la banda oscura la
   terracota se queda en 1.9:1. Van en el wash de salvia y se distinguen por el
   subrayado, que es lo que no depende del color. */
/* `--c-ink-on-dark` y no el wash de salvia: ese par es **claro en el tema claro
   y oscuro en el oscuro** —es el fondo del chip de familia—, así que sobre esta
   banda daba 13:1 en claro y **1.3:1 en oscuro**, invisible. `--c-ink-on-dark`
   significa «texto sobre oscuro» en los dos temas, que es lo que esto es
   (#287). */
.site-footer a {
  color: var(--c-ink-on-dark);
  text-decoration: underline;
}

.site-footer a:hover { color: var(--c-ink-on-dark); }

/* Secundarios, y legibles: la crema al 85% sobre la banda da 8.99:1. La
   opacidad aquí es tono, no una forma de apagar algo por debajo del umbral. */
.site-footer__legal,
.site-footer__licencia { opacity: 0.85; }

.site-footer__licencia { max-width: 60ch; margin-inline: auto; }

/* Un documento legal se lee seguido, con su medida y su filete de acento, como
   una sección del artículo de una ficha (#285). */
.legal-texto {
  max-width: var(--w-prose);
  margin-top: var(--s-5);
  padding-top: var(--s-4);
  border-top: 3px solid var(--c-accent);
}

/* --- El interruptor de tema (#266) ---------------------------------- */

/* Un solo botón que cicla los tres valores (#289), como el del admin de Django.

   Eran tres botones con su palabra escrita, y ocupaban media cabecera: tanto
   que hubo que esconderlos por debajo de 860 px. Con 36 px caben también en el
   móvil, así que **ya no se esconde en ninguna anchura** — que era el motivo.

   El icono no publica nada por su cuenta: el estado y lo que pasa al pulsar van
   en `aria-label` y en `title`, escritos por el guión (#96).

   Nace con `hidden` en la plantilla y lo destapa el guión. Sin JavaScript, un
   botón que no responde es peor que no tenerlo — y el tema sigue funcionando,
   porque sin atributo manda `prefers-color-scheme`. */
.tema__boton {
  display: inline-grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border: 1px solid transparent;
  border-radius: var(--r-full);
  background: none;
  color: var(--c-ink-soft);
  cursor: pointer;
  transition: color var(--e-fast), background var(--e-fast);
}

.tema__boton:hover {
  color: var(--c-ink);
  background: var(--c-hover);
}

/* Los iconos del interruptor son iconografía y no ilustración: toman el color
   del botón. Los otros once del sprite conservan el suyo a propósito. */
.tema__boton .icono { width: 18px; height: 18px; }

/* --- Miga de pan --------------------------------------------------- */

.miga {
  border-top: 1px solid var(--c-border);
  background: var(--c-surface);
  font-size: var(--t-sm);
}

.miga .page { padding-block: var(--s-2); }

.miga .page {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2);
  font-size: var(--t-base);
  color: var(--c-ink-soft);
}

.miga a { color: var(--c-ink-soft); text-decoration: none; }
.miga a:hover { color: var(--c-primary); }

/* Los pasos cuelgan de `.page`, no de `.miga`: con dos elementos el separador
   que faltaba no se notaba, y con diecinueve (#134) se leía como una sola
   frase sin espacios. */
.miga .page > * + *::before {
  content: "/";
  margin-right: var(--s-2);
  color: var(--c-border-strong);
}

.miga [aria-current="page"] { color: var(--c-primary); }

/* Los escalones que todavía no tienen página. Se leen —el árbol se enseña
   entero (#134)— pero no compiten con el nombre de lo que se ha venido a ver.
   La regla no es «por encima de Spermatophyta» sino «sin página», que es
   derivable y acaba diciendo lo mismo. */
.miga__paso {
  color: var(--c-ink-soft);
  font-size: var(--t-sm);
}

/* --- Menú de usuario ---------------------------------------------- */

/* Es un <details>: abre y cierra sin JavaScript. menu.js solo añade el cierre
   con Escape y al pulsar fuera. */

.menu { position: relative; }

.menu__disparador {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  padding: var(--s-2) var(--s-3);
  min-height: 44px;              /* mismo objetivo táctil que los botones */
  border-radius: var(--r-md);
  cursor: pointer;
  list-style: none;              /* fuera el triángulo del navegador */
  font-weight: var(--fw-medium);
}

.menu__disparador::-webkit-details-marker { display: none; }

.menu__disparador::after {
  content: "";
  width: 0.4em;
  height: 0.4em;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: translateY(-0.15em) rotate(45deg);
  transition: transform var(--e-fast);
}

.menu[open] .menu__disparador::after {
  transform: translateY(0.1em) rotate(-135deg);
}

.menu__disparador:hover { background: rgba(253, 252, 248, 0.14); }

/* Un puente invisible sobre el hueco que hay entre el disparador y el panel
   (#224). Sin él, bajar el puntero al menú lo saca del `<details>` durante ocho
   píxeles y dispara el cierre; el retardo del guion lo tapaba, pero es mejor
   que el hueco no exista que compensarlo con tiempo. */
.menu__panel::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: calc(-1 * var(--s-2));
  height: var(--s-2);
}

.menu__panel {
  position: absolute;
  top: calc(100% + var(--s-2));
  right: 0;
  z-index: 50;
  min-width: 12rem;
  padding: var(--s-1);
  background: var(--c-surface-raised);
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  box-shadow: var(--sh-lg);
}

.menu__opcion {
  display: block;
  width: 100%;
  padding: var(--s-2) var(--s-3);
  border: 0;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--c-ink);
  text-align: left;
  text-decoration: none;
  font-size: var(--t-sm);
  cursor: pointer;
}

/* Dos señales, no una: el fondo de sobrevuelo es tenue por definición, así que
   el color del texto cambia también. Quien no distinga el fondo ve el texto. */
.menu__opcion:hover {
  background: var(--c-hover);
  color: var(--c-primary);
}

.menu__opcion--salir { color: var(--c-danger); }
.menu__opcion--salir:hover {
  background: var(--c-danger-wash);
  color: var(--c-danger);
}

.menu__separador {
  height: 0;
  margin: var(--s-1) 0;
  border: 0;
  border-top: 1px solid var(--c-border);
}

/* --- Tarjeta ------------------------------------------------------ */

.card {
  /* El sistema de coordenadas del enlace estirado (#290). */
  position: relative;
  background: var(--c-surface-raised);
  /* Sin borde desde #280: sobre la crema de la página la arena de la tarjeta ya
     se despega sola, y un filete siguiendo una esquina de 32px se ve. */
  border-radius: var(--r-xl);
  overflow: hidden;
  box-shadow: var(--sh-sm);
  transition: box-shadow var(--e-base), transform var(--e-base);
}

a.card:hover, .card:hover {
  box-shadow: var(--sh-md);
  transform: translateY(-2px);
}

/* 3:2 y recorte al centro (#101). Antes eran los 400px fijos de
   `.seed-card-image` de la 2.x, con el argumento de que la portada distingue
   una variedad de otra. Sigue siendo verdad y sigue distinguiéndolas: lo que
   cambia es que en una pantalla de portátil cabían **tres** tarjetas y ahora
   caben ocho, así que se compara de un vistazo en vez de a base de scroll.

   Proporción y no altura fija: la caja reserva su hueco antes de que llegue la
   imagen, sea cual sea el ancho de la columna (#95). */
/* La foto «lavada» de Organic (#280): baja el croma y sube el blanco para que
   las fotos no compitan con una paleta que ya es cálida. La lleva **toda foto
   de contenido** —portadas, miniaturas de tabla, galería—, y no la lleva el
   taller de fotos: ahí se juzga una foto, y una foto lavada no se juzga. */
.washed { filter: saturate(0.6) contrast(0.85) brightness(1.1) opacity(0.94); }

/* En oscuro el filtro se da la vuelta (#287). Subir el blanco es lo que funde
   una foto con la crema; sobre tierra hace justo lo contrario y la foto
   deslumbra — en la ficha, la portada salía como un foco encima de la página.
   Mismo croma y mismo contraste, y la luz hacia abajo. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .washed {
    filter: saturate(0.6) contrast(0.85) brightness(0.82) opacity(0.94);
  }
}

:root[data-theme="dark"] .washed {
  filter: saturate(0.6) contrast(0.85) brightness(0.82) opacity(0.94);
}

/* Más alto que la 3:2 de #101: en la rejilla de cuatro de Organic la tarjeta es
   más estrecha, y en 3:2 la portada se quedaba en una banda. */
.card__marco { aspect-ratio: 4 / 3; }

.card__media {
  height: 100%;
  background: var(--c-surface-alt);
  object-fit: cover;
  object-position: center;
  width: 100%;
}

.card__media--vacia {
  display: grid;
  place-items: center;
  color: var(--c-ink-faint);
  font-size: var(--t-sm);
}

/* La franja de familia de #101 se fue con #279, y con ella lo único de la
   tarjeta que era solo color. Lo que agrupaba la rejilla lo dice el chip con
   palabras, que es lo que se lee igual sin distinguir catorce tonos. */

.card__body {
  padding: var(--s-3) var(--s-4) var(--s-4);
  display: grid;
  gap: var(--s-1);
  justify-items: start;
}

/* El nombre en la de titulares: es lo que se ha venido a leer. */
.card__title {
  font-family: var(--font-display);
  font-size: 1.0625rem;   /* 17px */
  line-height: 1.2;
}

/* El enlace estirado (#290). La tarjeta era un `<a>` entero y por eso el chip
   de familia no podía ser un enlace —uno dentro de otro no es HTML válido—.
   Ahora la tarjeta es un `<div>`, el nombre lleva el enlace y este `::after` lo
   estira hasta los bordes: se sigue pulsando en cualquier sitio.

   Con `z-index: 1`, que es lo que deja al chip ponerse por encima con 2. Sin él
   los dos quedarían en el mismo plano y ganaría el último del documento, que es
   el chip: la tarjeta entera filtraría por familia. */
.card__enlace::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
}

/* La fila de abajo: el chip de familia a la izquierda y el año en miniatura a
   la derecha, en una sola línea. */
.card__pie {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--s-2);
  width: 100%;
  min-width: 0;
  margin-top: var(--s-2);
}

/* El chip cede y los puntos no: el nombre de la familia sabe partirse y una
   tira de doce puntos no.

   Y por encima del enlace estirado (#290): con `z-index: 2` se queda con su
   trozo de la tarjeta y lleva a su filtro, mientras el resto sigue abriendo la
   ficha. `position: relative` porque `z-index` no hace nada sin él. */
.card__pie .familia-chip {
  min-width: 0;
  position: relative;
  z-index: 2;
}

/* El año en miniatura: doce barritas para ver de un vistazo qué se siembra
   ahora. El dato va escrito en el `aria-label` de la plantilla — esto es el
   resumen, no el portador (#96). */
.mini-anyo {
  display: grid;
  grid-template-columns: repeat(12, 7px);
  gap: 3px;
  /* El relleno agranda la zona que responde al `title` (#164) sin cambiar lo
     que se ve: seis píxeles de alto son muy poco para apuntar con el ratón.
     Los márgenes lo descuentan por arriba y por abajo, así que la tarjeta mide
     exactamente igual que antes y solo crece la zona sensible. */
  padding-block: var(--s-2);
  margin-top: calc(var(--s-1) - var(--s-2));
  margin-bottom: calc(-1 * var(--s-2));
}

.mini-anyo__barra {
  height: 7px;
  border-radius: var(--r-full);
  background: var(--c-surface-alt);
}

/* En el azul de la siembra, **no en el de la familia**. La familia ya la dicen
   la franja de arriba y el punto del chip; pintar además con ella las barras
   convertía la rejilla en un muestrario, y sobre todo hacía que la misma barra
   significara siembra aquí y familia allí. En la ficha la fila de siembra es
   `--c-primary` (#108), y esto es la misma fila en pequeño. */
.mini-anyo__barra--on { background: var(--c-accent-2); }

/* Hoy, marcado con un anillo: sobre un punto de siete píxeles el trazo de
   debajo que llevaba se leía como una barra torcida. */
.mini-anyo__barra--hoy { box-shadow: 0 0 0 2px var(--c-ink-soft); }

/* En color de texto y no en azul de enlace: la tarjeta entera es el enlace, y
   pintar su título como si fuera uno suelto sugiere que hay dos destinos. El
   azul llega al sobrevolar, que es cuando hace falta la señal. */
.card__title {
  font-size: var(--t-md);
  font-weight: var(--fw-medium);
  line-height: var(--lh-snug);
  color: var(--c-ink);
  transition: color var(--e-fast);
}

.card:hover .card__title { color: var(--c-primary); }

/* Ni subrayado al sobrevolar: la tarjeta ya se levanta y la foto se acerca. */
a.card:hover { text-decoration: none; }

/* El nombre científico NO va en cursiva. La ficha es un cultivar y la notación
   del ICNCP escribe `Beta vulgaris 'Bright Lights'` en redonda (#4). El
   binomio solo iría en cursiva suelto, y aquí nunca lo está. */
.card__meta {
  font-style: italic;
  color: var(--c-ink-faint);
  font-size: var(--t-sm);
}

/* --- Etiquetas ---------------------------------------------------- */

.tag {
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
  padding: 0.15em 0.6em;
  border-radius: var(--r-full);
  font-size: var(--t-xs);
  font-weight: var(--fw-medium);
  background: var(--c-surface-alt);
  color: var(--c-ink-soft);
  white-space: nowrap;
}

.tag--success { background: var(--c-success-wash); color: var(--c-success); }
.tag--warning { background: var(--c-warning-wash); color: var(--c-warning); }
.tag--danger  { background: var(--c-danger-wash);  color: var(--c-danger); }
.tag--info    { background: var(--c-info-wash);    color: var(--c-info); }
.tag--primary    { background: var(--c-primary-wash);    color: var(--c-primary); }

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

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  padding: var(--s-2) var(--s-4);
  min-height: 44px;              /* objetivo táctil accesible */
  border: 1px solid transparent;
  /* Píldora desde #280, que es lo que declaró #277 y aquí se aplica. El
     `.textarea` se queda en el radio medio: una caja de ocho líneas con las
     esquinas redondas del todo no es una píldora, es un error. */
  border-radius: var(--r-full);
  font-weight: var(--fw-medium);
  cursor: pointer;
  text-decoration: none;
  transition: background var(--e-fast), border-color var(--e-fast);
}

.btn--primary {
  background: var(--c-primary);
  color: var(--c-on-primary);
}
.btn--primary:hover { background: var(--c-primary-hover); color: var(--c-on-primary); }

.btn--ghost {
  background: transparent;
  border-color: var(--c-border-strong);
  color: var(--c-ink);
}
.btn--ghost:hover { background: var(--c-surface-alt); }

.btn--danger { background: var(--c-danger); color: #FFFFFF; }

/* Sobre la cabecera verde bosque: ni --c-primary ni --c-border-strong tienen
   contraste suficiente contra ese fondo. Texto y borde en crema dan 13.9:1. */
.btn--on-dark {
  background: transparent;
  border-color: var(--c-ink-on-dark);
  color: var(--c-ink-on-dark);
}
.btn--on-dark:hover {
  background: rgba(253, 252, 248, 0.14);
  color: var(--c-ink-on-dark);
}

.btn[disabled] { opacity: 0.5; cursor: not-allowed; }

/* --- Campos de formulario ---------------------------------------- */

.field { display: grid; gap: var(--s-2); }

.field__label {
  font-size: var(--t-sm);
  font-weight: var(--fw-medium);
  color: var(--c-ink-soft);
}

.field__hint { font-size: var(--t-sm); color: var(--c-ink-faint); }
.field__error { font-size: var(--t-sm); color: var(--c-danger); }

/* ============================================================
   Los campos bajan a `--r-sm` (#286)
   ------------------------------------------------------------
   #277 declaró que botones, campos y etiquetas iban a la
   píldora. Los campos nunca llegaron a estarlo —se quedaron en
   `--r-md`— y aun así, con el formulario de edición delante, el
   problema estaba:

   **A 44 px de alto, 16 px de radio y una píldora se ven
   igual.** Una píldora de 44 de alto es un radio efectivo de 22,
   y la diferencia con 16 no la distingue nadie. En
   «Identificación», el campo del nombre científico y el botón
   «Consultar las fuentes» salían con la misma silueta, uno
   encima del otro, y no había forma de saber cuál se rellena y
   cuál se pulsa. La caja de la taxonomía, que envuelve tres
   líneas, salía como un óvalo alrededor de un párrafo.

   Así que la píldora se queda donde dice «esto se pulsa»
   —botones, etiquetas, segmentados, la cinta de meses, el
   buscador de la barra y los desplegables del cajón de filtros—
   y **lo que se rellena baja a `--r-sm`**. Ocho contra veintidós
   sí se distingue, y la forma vuelve a decir la función.
   ============================================================ */

.input, .textarea, .select {
  width: 100%;
  padding: var(--s-2) var(--s-4);
  min-height: 44px;
  background: var(--c-surface-raised);
  border: 1px solid var(--c-border-strong);
  border-radius: var(--r-sm);
  transition: border-color var(--e-fast), box-shadow var(--e-fast);
}

.input:focus, .textarea:focus, .select:focus {
  outline: none;
  border-color: var(--c-primary);
  box-shadow: 0 0 0 3px var(--c-primary-wash);
}

.input[aria-invalid="true"] { border-color: var(--c-danger); }

/* Los campos de fichero (#286). Django los pinta sin clase, así que se salían
   del sistema entero: en Ajustes había tres botones azules del navegador
   —«Choose File»— en medio de una pantalla en crema y terracota.

   Se viste el botón interno con `::file-selector-button`, que es el estándar y
   el que entienden los tres navegadores; el campo en sí se queda transparente,
   porque lo que hay a su lado es el nombre del fichero y no un valor que se
   escriba. */
input[type="file"] {
  font: inherit;
  color: var(--c-ink-soft);
  max-width: 100%;
}

input[type="file"]::file-selector-button {
  font: inherit;
  font-weight: var(--fw-medium);
  margin-right: var(--s-3);
  padding: var(--s-2) var(--s-4);
  min-height: 40px;
  border: 1px solid var(--c-border-strong);
  border-radius: var(--r-full);
  background: var(--c-surface-raised);
  color: var(--c-ink);
  cursor: pointer;
  transition: border-color var(--e-fast), background var(--e-fast);
}

input[type="file"]::file-selector-button:hover {
  border-color: var(--c-primary);
  background: var(--c-primary-wash);
}

/* Los dos extremos de un rango, en la misma línea (#191). Cada mitad ocupa lo
   que pida su rótulo entero —«germina desde (días)» no se parte— y el sobrante
   se queda a la derecha: son dos cifras, no media página de formulario.

   `wrap` para el estrecho: ahí vuelven a apilarse, que es lo que hacían antes y
   sigue siendo lo correcto cuando no caben. */
.pareja {
  display: flex;
  flex-wrap: wrap;
  align-items: start;
  gap: var(--s-3) var(--s-4);
}

.pareja .field { flex: 0 1 auto; }

/* Del tamaño de lo que se escribe dentro. `min-height` lo pone `.input`, así
   que sigue siendo un blanco de 44 px de alto para el dedo. */
.input--corto { width: 8rem; }

.textarea { min-height: 8rem; resize: vertical; }

/* --- Autocompletado (#106) ---------------------------------------- */

/* La caja la crea el script alrededor del campo. Sin script no existe, y el
 * campo queda exactamente como estaba. */
.autocompletar { position: relative; }

/* Absoluta y por encima: la lista aparece y desaparece sin mover ni un píxel
 * de lo que hay debajo. Un salto de maquetación aquí sería CLS, y el CLS
 * cuenta para el posicionamiento (#95). */
.autocompletar__lista {
  position: absolute;
  z-index: 20;
  inset-inline: 0;
  top: calc(100% + var(--s-1));
  max-height: 16rem;
  overflow-y: auto;
  margin: 0;
  padding: var(--s-1);
  list-style: none;
  background: var(--c-surface-raised);
  border: 1px solid var(--c-border-strong);
  border-radius: var(--r-md);
  box-shadow: var(--sh-md);
}

.autocompletar__opcion {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-3);
  padding: var(--s-2) var(--s-3);
  border-radius: var(--r-sm);
  cursor: pointer;
}

.autocompletar__opcion:hover,
.autocompletar__opcion.es-activa {
  background: var(--c-primary-wash);
}

/* El fondo no puede ser lo único que distinga la opción recorrida: quien no
 * distingue ese contraste se queda sin saber dónde está. */
.autocompletar__opcion.es-activa {
  box-shadow: inset 3px 0 0 var(--c-primary);
}

.autocompletar__valor { font-weight: var(--fw-medium); }

.autocompletar__nota {
  font-size: var(--t-sm);
  color: var(--c-ink-faint);
  white-space: nowrap;
}

/* --- Tabla -------------------------------------------------------- */

/* La tabla desborda dentro de su caja; la página nunca hace scroll horizontal.
   El radio va aquí y no en la `<table>`: es el contenedor el que recorta, y una
   tabla con `border-collapse` no respeta esquinas redondeadas. */
.table-wrap {
  overflow-x: auto;
  background: var(--c-surface-raised);
  border-radius: var(--r-md);
  /* `position: relative` no es decoración y cuesta explicarlo, así que queda
     escrito (#288). Sin él, y **aunque la caja scrolle de verdad**, el ancho de
     la tabla se le sumaba a la página: en un móvil de 390 px `<html>` medía 802
     y se podía arrastrar la pantalla 412 px hasta un rectángulo de crema vacía.

     Medido en Chromium: 802 → 390. Sirven igual `contain: paint` y
     `contain: layout`; se elige este por ser el más antiguo y el que menos
     promete. Lo que **no** sirve es tocar `overflow-y`. */
  position: relative;
}

.table { width: 100%; border-collapse: collapse; font-size: var(--t-sm); }

/* Cabeceras en la de titulares, como el resto de rótulos de Organic (#281).
   Caprasimo solo trae el 400, así que el peso no distingue: lo hace la letra. */
.table th {
  background: transparent;
  text-align: left;
  font-family: var(--font-display);
  font-weight: var(--fw-normal);
  font-size: 0.78125rem;   /* 12.5px */
  color: var(--c-ink-soft);
  padding: var(--s-3);
  border-bottom: 1px solid var(--c-border);
  white-space: nowrap;
}

.table td { padding: var(--s-3); border-bottom: 1px solid var(--c-border); }
.table tbody tr:hover { background: var(--c-surface-alt); }

/* La tabla del catálogo, con las nueve columnas de la 2.x (#270).

   `min-width` y no `nowrap` en las celdas: con nueve columnas la tabla no cabe
   en un móvil, y lo que hace `.table-wrap` es dejarla desplazarse en su caja.
   Sin un ancho mínimo el navegador la comprime hasta que «Nombre científico»
   sale a una palabra por línea, que es peor que el desplazamiento. */
.table--catalogo { min-width: 60rem; }

.table__foto { width: 72px; padding-right: 0; }

/* Redonda y recortada (#281). Las fotos del catálogo vienen con la proporción
   que traía cada una, y una columna de miniaturas de alturas distintas hace que
   las filas dejen de leerse como filas. `width`/`height` los pone el `<img>`
   desde `_imagen.html` para reservar el hueco; esto los ajusta al círculo.

   44 y no 56: el círculo recorta más que el cuadrado —se lleva las esquinas— y
   con nueve columnas la fila no puede crecer. */
.table__miniatura {
  width: 44px;
  height: 44px;
  object-fit: cover;
  border-radius: var(--r-full);
  display: block;
}

.table__miniatura--vacia {
  display: grid;
  place-items: center;
  background: var(--c-surface-alt);
  color: var(--c-ink-faint);
}

.table__miniatura--vacia .empty__dibujo { width: 24px; height: 24px; }

/* Un valor que existe y dice que no hay nada —«Desconocido», «Agotada»—, que no
   es lo mismo que un hueco: el hueco es `_sin_dato.html`. */
.table__apagado { color: var(--c-ink-faint); }

/* Varios años de plan en una celda, sin que los distintivos se peguen (#267). */
.anos-del-plan { display: inline-flex; flex-wrap: wrap; gap: var(--s-1); }

/* Un sobre por línea, como en la tabla del inventario. */
.sobre { display: block; white-space: nowrap; }
.sobre--agotado { color: var(--c-ink-faint); text-decoration: line-through; }

/* --- Calendario de siembra --------------------------------------- */

.months {
  display: flex;
  justify-content: space-between;
  list-style: none;
  padding: 0;
  gap: var(--s-1);
  max-width: 520px;
}

/* Círculos de 34 px, como la maqueta. El mes inactivo va en contorno y no en
   relleno: sobre la arena del panel un relleno claro no se distingue del
   fondo. */
/* 34 px es el **máximo**, no el ancho: doce círculos fijos de 34 con sus huecos
   suman 452 px y en un móvil de 390 sacaban scroll horizontal, que es una regla
   dura del proyecto. Encogen hasta donde haga falta y siguen siendo redondos
   porque el alto lo pone `aspect-ratio`. */
.months__cell {
  flex: 1 1 0;
  min-width: 0;
  max-width: 34px;
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  font-size: var(--t-xs);
  background: transparent;
  border: 2px solid var(--c-surface-alt);
  color: var(--c-ink-faint);
  border-radius: var(--r-full);
}

/* El estado activo no se distingue solo por color: también cambia el
   peso tipográfico, para quien no percibe la diferencia cromática. */
.months__cell--on {
  background: var(--c-primary);
  color: var(--c-on-primary);
  font-weight: var(--fw-bold);
}

/* --- Avisos ------------------------------------------------------- */

.notice {
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-md);
  border-left: 3px solid;
  font-size: var(--t-sm);
}

.notice--info    { background: var(--c-info-wash);    border-color: var(--c-info); }
.notice--success { background: var(--c-success-wash); border-color: var(--c-success); }
.notice--warning { background: var(--c-warning-wash); border-color: var(--c-warning); }
.notice--danger  { background: var(--c-danger-wash);  border-color: var(--c-danger); }

/* --- Estado vacío ------------------------------------------------- */

.empty {
  text-align: center;
  padding: var(--s-8) var(--s-4);
  color: var(--c-ink-faint);
}

/* --- Pestañas de sección ------------------------------------------ */

.tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-1);
  border-bottom: 1px solid var(--c-border);
}

.tabs__item {
  padding: var(--s-3) var(--s-4);
  text-decoration: none;
  color: var(--c-ink-soft);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}

.tabs__item:hover { background: var(--c-surface-alt); }

/* La pestaña activa no se marca solo con color: el subrayado y el peso la
   distinguen también sin percepción cromática. */
.tabs__item--activo {
  color: var(--c-primary);
  border-bottom-color: var(--c-primary);
  font-weight: var(--fw-bold);
}

/* --- Vista previa de un fichero subido ---------------------------- */

.preview {
  display: block;
  background: var(--c-surface-alt);
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  padding: var(--s-2);
  object-fit: contain;
}

.preview--logo    { height: 4rem;   max-width: 100%; width: auto; }
.preview--favicon { height: 2.5rem; width: 2.5rem; }

/* La imagen de reserva se previsualiza en el mismo 4:3 y con el mismo recorte
   con los que va a salir en la ficha (#172): una vista previa que la enseñara
   entera no avisaría de que se le van a comer los lados. */
.preview--semilla {
  width: 100%;
  max-width: 240px;
  aspect-ratio: 4 / 3;
  padding: 0;
  object-fit: cover;
}

/* --- Franja de estado del sitio ----------------------------------- */

/* Va pegada bajo la cabecera y ocupa el ancho completo: un modo encendido no
   es un detalle que deba competir con el contenido por la atención. */
.banda {
  padding-block: var(--s-3);
  font-size: var(--t-sm);
  border-bottom: 1px solid;
}

.banda--aviso {
  background: var(--c-warning-wash);
  border-bottom-color: var(--c-warning);
  color: var(--c-warning);
}

/* --- Interruptor --------------------------------------------------- */

.interruptor {
  display: flex;
  align-items: flex-start;
  gap: var(--s-3);
}

/* Objetivo táctil accesible: una casilla de 13px por defecto no lo es. */
.interruptor__casilla {
  width: 1.5rem;
  height: 1.5rem;
  margin-top: 0.15em;
  flex: none;
  accent-color: var(--c-primary);
  cursor: pointer;
}

.interruptor label { cursor: pointer; }

/* --- Trampa para robots -------------------------------------------- */

/* Un campo que una persona no ve y no rellena, y un robot que rellena todo, sí.
   No se usa display:none: algunos robots lo detectan y saltan el campo. Se
   saca del flujo con posición absoluta, que cuesta más de distinguir.
   La plantilla lo marca además con aria-hidden y tabindex="-1", para que quien
   navega con teclado o con lector de pantalla no se lo encuentre. */
.trampa {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* ============================================================
   Catálogo — la parte que reproduce el panel de Semillas de la 2.x (#68)
   ============================================================ */

/* --- Barra de herramientas del listado ----------------------------- */

/* Buscador, filtros y conmutador de vista, en una fila que se parte sola.
   En la 2.x era el `PanelToolbar`. */
.toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--s-3);
  background: var(--c-surface-raised);
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  padding: var(--s-4);
  box-shadow: var(--sh-sm);
}

.toolbar__campo { display: grid; gap: var(--s-1); }
.toolbar__campo--ancho { flex: 1 1 16rem; }

.toolbar__etiqueta {
  font-size: var(--t-sm);
  color: var(--c-ink-soft);
  font-weight: var(--fw-medium);
}

.toolbar__acciones { display: flex; gap: var(--s-2); margin-left: auto; }

/* --- Conmutador de vista (el Segmented de la 2.x) ------------------ */

.vistas {
  display: inline-flex;
  background: var(--c-surface);
  border-radius: var(--r-full);
  padding: 4px;
  gap: 2px;
}

.vistas__opcion {
  display: inline-flex;
  align-items: center;
  min-height: 32px;
  padding-inline: var(--s-3);
  border-radius: var(--r-full);
  font-size: var(--t-sm);
  text-decoration: none;
  color: var(--c-ink-soft);
}

.vistas__opcion:hover { color: var(--c-ink); }

/* El activo, relleno de terracota (#280). Estaba en arena sobre la crema del
   segmentado y no se distinguía del inactivo: el conmutador no decía en qué
   vista estabas, que es lo único que tiene que decir.

   `--c-primary` y no la terracota media de las maquetas porque lleva texto
   encima: sobre #c67139 el crema se queda en 3.03:1. */
.vistas__opcion--activa {
  background: var(--c-primary);
  color: var(--c-on-primary);
  font-weight: var(--fw-medium);
}

/* ============================================================
   El chip de familia (#279)
   ------------------------------------------------------------
   Fue el acento de la página: catorce familias, catorce colores,
   sin leyenda que aprender (#99). Ya no.

   #99 resolvía un problema real —recorrer la rejilla y saber de
   qué familia es cada cosa sin leer—, pero el color escrito en
   el admin necesitaba una función entera, `colors.sobre_papel()`,
   para ser legible sobre el papel, y eso ya era la señal de que
   no cabía en el sistema. Sobre una paleta que además tiene
   temperatura propia, catorce tonos arbitrarios son ruido.

   Organic pone la distinción donde se lee de todas formas: en el
   texto del chip, que dice el nombre de la familia. Uno solo, en
   salvia, igual en todas partes. Con él se fueron el punto y la
   franja de la tarjeta, que eran solo color.

   El dato sigue en la base y `Taxon.color` se sigue editando: si
   se echa de menos, volver es barato.
   ============================================================ */

.familia-chip {
  display: inline-flex;
  align-items: center;
  align-self: start;
  padding: 2px var(--s-3);
  border-radius: var(--r-full);
  background: var(--c-accent-2-wash);
  color: var(--c-accent-2-deep);
  font-size: var(--t-sm);
  text-decoration: none;
}

/* Un paso al sobrevolar, como el resto de lo que se puede pulsar. No cambia el
   color del texto: el chip ya es un relleno, y teñir la letra sobre un fondo
   claro es donde se pierden los ratios. */
.familia-chip:hover { filter: brightness(0.95); }

/* --- Paginación ---------------------------------------------------- */

.paginacion {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  font-size: var(--t-base);
}

.paginacion__enlace {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 38px;
  min-height: 38px;
  padding-inline: var(--s-2);
  border: 1px solid var(--c-border-strong);
  border-radius: var(--r-full);
  background: var(--c-surface-raised);
  text-decoration: none;
  color: var(--c-ink);
}

.paginacion__enlace:hover { border-color: var(--c-accent); color: var(--c-primary); }

/* La página en la que se está: círculo relleno, no contorno. El fondo es
   `--c-primary` y no la terracota media de la maqueta porque lleva un número
   encima: sobre #c67139 el crema se queda en 3.03:1 y sobre este da 5.7:1. */
.paginacion__enlace--activo {
  background: var(--c-primary);
  border-color: var(--c-primary);
  color: var(--c-on-primary);
  font-weight: var(--fw-medium);
}

.paginacion__resumen { color: var(--c-ink-soft); font-size: var(--t-sm); }

/* La cabecera del índice, sin las cifras de inventario (#101). */
.indice-cabecera {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-6);
  margin-bottom: var(--s-5);
}

.indice-cabecera > div:first-child { flex: 1 1 20rem; }

/* 46ch y no la medida de lectura entera: es una entradilla de dos líneas al
   lado de las cifras, no un artículo. */
.indice-cabecera__entradilla {
  color: var(--c-ink-soft);
  max-width: 46ch;
  margin-top: var(--s-3);
  font-size: var(--t-md);
  text-wrap: pretty;
}

/* --- Ficha de semilla ---------------------------------------------- */

/* La cabecera: portada en 4:3 al lado del título (#100). A todo lo ancho
   empujaba el nombre —que es lo que se ha venido a leer— por debajo del doblez
   en cualquier portátil. */
/* ============================================================
   La cabecera de la ficha, a sangre (#282)
   ------------------------------------------------------------
   La portada ocupa el ancho entero de la página y 430 px de
   alto, con un degradado que la funde con el papel; encima, el
   chip de familia, el nombre y el científico.

   **A sangre de la página, no de la ventana.** `100vw` con
   márgenes negativos saca la foto hasta el borde del navegador,
   pero cuenta la barra de scroll dentro del ancho y aparece un
   scroll horizontal — que es una de las reglas duras del
   proyecto. Se cancela el relleno de `.page` y ya está: la
   maqueta es una tarjeta de 1240 px, así que su «a sangre» es
   exactamente esto.

   La barra superior tampoco se pinta encima. Es `sticky` desde
   #98: transparente se quedaría transparente al bajar, sobre el
   artículo, y ahí no se lee. Cambiarla en el umbral del scroll
   pide JavaScript, y la ficha es nivel 1.
   ============================================================ */

.ficha-cabecera {
  position: relative;
  /* Cancela el relleno lateral de `.page` sin salirse de ella. */
  margin-inline: calc(-1 * var(--s-4));
  margin-bottom: var(--s-6);
  border-radius: var(--r-xl);
  overflow: hidden;
  background: var(--c-surface-raised);
}

.ficha-cabecera__portada {
  position: relative;
  margin: 0;
  height: var(--h-cover);
}

.ficha-cabecera__portada img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Sin foto: la arena con el brote, el mismo hueco que la tarjeta del índice.
   Más bajo, que 430 px de nada es un agujero. */
.ficha-cabecera__portada--vacia {
  display: grid;
  place-items: center;
  height: 240px;
  color: var(--c-ink-faint);
}

/* El degradado. Oscurece un punto arriba —para que el crédito se lea— y funde
   con el papel abajo, que es donde va el nombre. Los colores salen de los
   tokens con `color-mix`: la maqueta traía `#f5ead8` a fuego, y ese hexadecimal
   dejaría el degradado apuntando al papel claro en tema oscuro. */
.ficha-cabecera__velo {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(
    180deg,
    color-mix(in srgb, var(--c-nav) 25%, transparent),
    transparent 30%,
    transparent 55%,
    var(--c-surface) 96%
  );
}

/* El texto, sobre el degradado. `position: absolute` solo cuando hay foto: sin
   ella la cabecera es un bloque de arena y el texto va debajo, en el flujo. */
.ficha-cabecera__texto {
  display: grid;
  gap: var(--s-2);
  justify-items: start;
  padding: var(--s-5) var(--s-6) var(--s-5);
}

.ficha-cabecera--portada .ficha-cabecera__texto {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding-bottom: var(--s-4);
}

.ficha-cabecera h1 {
  font-size: var(--t-hero);
  margin: 0;
  text-wrap: balance;
}

/* En pantallas estrechas 64 px de titular no caben, y la foto de 430 se come
   la primera pantalla entera. */
@media (max-width: 720px) {
  .ficha-cabecera h1 { font-size: var(--t-3xl); }
  .ficha-cabecera__portada { height: 260px; }
}

/* Las acciones, en su fila (#282). Estaban al lado del nombre, y el nombre está
   ahora sobre una foto. */
.ficha-acciones {
  display: flex;
  justify-content: flex-end;
  margin-bottom: var(--s-5);
}

/* El enlace que amplía la portada ocupa la banda entera: lo que reserva el
   hueco antes de que la imagen llegue —que aquí es CLS y cuenta para el
   posicionamiento (#95)— es el alto fijo de `.ficha-cabecera__portada`. */
.ficha-cabecera__foto { display: block; height: 100%; }

.ficha-cabecera__familia { margin: 0; }

/* En cursiva y no en otra letra: un nombre científico se escribe en cursiva
   por convención botánica, y eso ya lo distingue sin cambiar de familia. */
.ficha-cabecera__cientifico {
  font-family: var(--font-ui);
  font-style: italic;
  font-size: var(--t-lg);
  color: var(--c-ink-soft);
  margin: 0;
}

/* Las glosas —etimología, origen y distribución— abren el artículo (#282). En
   tres columnas, que es lo que hace la maqueta, y no en la columna estrecha de
   la cabecera, que ahora es una foto a sangre.

   Se pintan siempre las tres, escritas o no (#174): la raya dice que el campo
   existe y está vacío.

   Lo de aquí quita los márgenes que el navegador trae de serie, incluido el
   sangrado de 40 px que le pone a todo `<dd>`. */
.glosas {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--s-2) var(--s-5);
  margin: 0 0 var(--s-6);
  padding-bottom: var(--s-5);
  border-bottom: 1px solid var(--c-border);
}

/* Cada rótulo en su columna y cada texto debajo del suyo: con el flujo normal
   de la rejilla, tres rótulos y tres textos se colocarían en dos filas
   descolocadas. */
.glosas__nombre { grid-row: 1; }
.glosas__texto  { grid-row: 2; }

@media (max-width: 720px) {
  .glosas { grid-template-columns: 1fr; }
  .glosas__nombre, .glosas__texto { grid-row: auto; }
}

.glosas__nombre {
  font-family: var(--font-display);
  font-size: var(--t-sm);
  font-weight: var(--fw-normal);
  color: var(--c-primary-hover);
}

.glosas__texto {
  margin: 0;
  font-size: var(--t-base);
  color: var(--c-ink-soft);
}

.glosas__texto > :first-child { margin-top: 0; }
.glosas__texto > :last-child { margin-bottom: 0; }

/* La glosa sin escribir (#174). Más apagada que la escrita: la raya está para
   decir que el campo existe y está vacío, no para competir con el texto de la
   de al lado cuando solo una de las dos tiene algo. */
.glosas__texto--vacio { color: var(--c-ink-faint); }

/* El titular: el nombre a la izquierda, las acciones al extremo derecho de la
   columna (#171). Antes colgaban al final del texto, y el hueco entre el nombre
   y el botón era de dos párrafos de glosa; ahora comparten línea y el hueco es
   el de la propia columna.

   `align-items: baseline` para que el botón se apoye en la primera línea del
   nombre y no en su centro, que con un nombre de dos líneas lo dejaría a media
   altura. `flex-shrink: 0` en las acciones: el que cede sitio es el nombre, que
   sabe partirse, y no la fila de botones, que no.

   El derechazo lo da `margin-left: auto` y no `justify-content: space-between`
   porque la fila envuelve: con un nombre largo en una columna estrecha los
   botones bajan a su propia línea, y el margen los mantiene a la derecha
   también allí, mientras que `space-between` los devolvería al margen
   izquierdo. */
.ficha-cabecera__titular {
  display: flex;
  align-items: baseline;
  gap: var(--s-4);
  flex-wrap: wrap;
}

.ficha-cabecera__titular h1 { margin: 0; }

.ficha-cabecera__acciones {
  display: flex;
  gap: var(--s-2);
  margin-top: var(--s-2);
}

/* En el titular no hay nada encima de lo que separarse —el aire lo pone el
   `gap`—, y un margen superior desplazaría la fila respecto de la línea base
   del nombre. La ficha del taxón sigue usando la clase suelta, y allí el margen
   sí hace falta. */
.ficha-cabecera__titular .ficha-cabecera__acciones {
  margin-top: 0;
  margin-left: auto;
  flex-shrink: 0;
}

/* La regla del año, a lo ancho y antes que ningún dato (#100). */
/* La franja de calendario (#282): panel de arena en vez de filete, con el
   rótulo a la izquierda y las épocas a la derecha. Es lo primero tras la
   cabecera, que es lo que pide la maqueta y lo que ya decía #100 — la pregunta
   que trae a la gente a una ficha de semilla es cuándo se siembra.

   La maqueta enseña **una** fila de meses. Aquí hay tres: siembra, floración y
   cosecha, que #108 añadió a propósito y son dato de verdad. Lo que se toma de
   la maqueta es la forma —el panel y los círculos—, no el recorte. */
.regla {
  display: grid;
  grid-template-columns: minmax(0, 12rem) minmax(0, 1fr);
  gap: var(--s-3) var(--s-6);
  align-items: center;
  margin-bottom: var(--s-7);
  padding: var(--s-5) var(--s-6);
  background: var(--c-surface-raised);
  border-radius: var(--r-xl);
}

/* El rótulo ocupa la primera columna de todas las filas que haya. */
.regla > .rotulo {
  grid-column: 1;
  grid-row: 1 / -1;
  align-self: center;
  font-family: var(--font-display);
  font-size: var(--t-lg);
  text-transform: none;
  letter-spacing: normal;
  color: var(--c-ink);
}

.regla > :not(.rotulo) { grid-column: 2; }

@media (max-width: 720px) {
  .regla { grid-template-columns: 1fr; padding: var(--s-4); }
  .regla > .rotulo { grid-column: 1; grid-row: auto; }
  .regla > :not(.rotulo) { grid-column: 1; }
}

.regla__fila { display: grid; gap: var(--s-2); }

.regla__frase { color: var(--c-ink); }

/* La primera es la respuesta que trae a la gente: cuándo se siembra. */
.regla__frase--lead { font-size: var(--t-md); }

/* El rótulo de la época (#173). En negrita y en color apagado: son tres filas
   una debajo de otra y lo que hay que poder recorrer en vertical es el rótulo,
   pero el dato —los meses— es lo que se ha venido a leer y se queda con el
   color fuerte. */
.regla__epoca {
  font-weight: var(--fw-bold);
  color: var(--c-ink-soft);
}

.regla__frase a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
  font-weight: var(--fw-medium);
}
.regla__frase a:hover { color: var(--c-primary); }

/* La banda ocupa el ancho disponible, no los 420px de la columna estrecha.
   Pero **sin `aspect-ratio`**: doce celdas cuadradas repartidas en 1.080px son
   celdas de 87px, y tres filas de eso ocupaban más alto que el artículo. La
   altura se fija y el ancho que sobre lo reparte la rejilla. */
.regla .months { max-width: none; }
.regla .months__cell { aspect-ratio: auto; height: 2.25rem; }

/* El mes de hoy, marcado en las tres filas. Es un contorno y no un relleno
   para que se distinga tanto en la celda encendida como en la apagada. */
.months__cell--hoy {
  outline: 2px solid var(--c-ink);
  outline-offset: -2px;
}

/* El artículo manda y el carril acompaña (#282): antes eran 3fr contra 2fr
   porque el carril llevaba Datos, Germinación y los bloques privados. Ahora
   solo lleva fotos, así que se queda en una columna fija y estrecha. */
.ficha {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 220px;
  gap: 44px;
  align-items: start;
}

@media (max-width: 860px) {
  .ficha { grid-template-columns: 1fr; gap: var(--s-6); }
}

/* El cuerpo es un artículo (#100): filete arriba y rótulo en versalitas, en
   lugar de una caja blanca con sombra por cada sección. Con textos de 441
   caracteres de mediana, el marco pesaba más que lo de dentro. */
.articulo { display: grid; gap: var(--s-7); }
.carril   { display: grid; gap: var(--s-4); }

/* Datos y Germinación, lado a lado dentro del artículo (#282). `auto-fit` con
   mínimo: con los dos caben en dos columnas, con uno solo ocupa el ancho. */
.paneles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: var(--s-4);
  margin: var(--s-6) 0;
}

/* Dentro del flujo son tarjetas, no secciones con filete: el filete separa
   prosa de prosa y esto no es prosa. */
.paneles > .seccion {
  margin: 0;
  padding: var(--s-4) var(--s-5);
  border-top: 0;
  background: var(--c-surface-raised);
  border-radius: var(--r-xl);
}

.paneles > .seccion > .rotulo { color: var(--c-accent-2-text); }

/* «Últimos cambios» cierra el artículo con la misma forma de panel, y con
   medida: es una lista de fechas, no un texto que se lea seguido. */
.articulo > .seccion.seccion--cambios,
.articulo > .seccion--privada {
  margin-top: var(--s-6);
  padding: var(--s-4) var(--s-5);
  border-top: 0;
  background: var(--c-surface-raised);
  border-radius: var(--r-xl);
}

.articulo > .seccion.seccion--cambios { max-width: 420px; }

/* --- El carril de fotos, en círculo (#282) -------------------------- */

.galeria-carril {
  display: grid;
  gap: var(--s-3);
}

.galeria-carril__foto {
  display: block;
  aspect-ratio: 1;
  border-radius: var(--r-full);
  overflow: hidden;
}

.galeria-carril__imagen {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* En móvil el carril baja debajo del artículo, y ahí una columna de círculos
   grandes es una escalera: se ponen en fila. */
@media (max-width: 860px) {
  .galeria-carril {
    grid-template-columns: repeat(auto-fill, minmax(88px, 1fr));
  }
}

.seccion { padding-top: var(--s-3); border-top: 1px solid var(--c-border); }

/* El filete de la primera sección es el acento de la página. Era el color de
   la familia (#99); desde #279 es la terracota, igual en todas las fichas. */
.articulo > .seccion:first-child { border-top-color: var(--c-accent); }

/* `.rotulo` ya existe arriba, en la sección de tipografía: es una pieza del
   sistema desde #98 y no se vuelve a declarar aquí. Redeclararla con otro
   tamaño y otro `letter-spacing` era una colisión de cascada de las que gana
   quien va última — exactamente lo que costó el destrozo de #94. Lo único que
   necesita el rótulo dentro de una sección es separarse de lo que viene. */
.seccion > .rotulo, .regla > .rotulo { margin-bottom: var(--s-3); }

/* Lo que solo ve quien tiene sesión se sigue distinguiendo del resto (#110),
   ahora sin caja: fondo tenue y filete grueso a la izquierda. */
.seccion--privada {
  border-top-color: var(--c-border-strong);
  border-left: 3px solid var(--c-border-strong);
  padding-left: var(--s-4);
  background: var(--c-surface-alt);
  padding-bottom: var(--s-4);
  padding-right: var(--s-4);
}

.panel {
  background: var(--c-surface-raised);
  border: 1px solid var(--c-border);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-sm);
  padding: var(--s-5);
}

/* Lo que solo ve quien tiene sesión, dentro de una página pública (#110). El
   borde marcado no es adorno: dice que ese trozo no es parte de la ficha que
   lee todo el mundo, y quien escribe ahí conviene que lo tenga claro. El texto
   de debajo del título lo dice además con palabras, porque un borde de color
   no se lo cuenta a nadie que no lo vea. */
.panel--privado {
  border-color: var(--c-border-strong);
  border-left-width: 3px;
  background: var(--c-surface-alt);
}

.panel__titulo {
  font-family: var(--font-ui);
  font-size: var(--t-md);
  font-weight: var(--fw-medium);
  margin-bottom: var(--s-4);
  padding-bottom: var(--s-3);
  border-bottom: 1px solid var(--c-border);
}

/* Lista de pares dato/valor: el `Descriptions` de Ant. */
.datos { display: grid; gap: var(--s-3); }

.datos__fila {
  display: grid;
  grid-template-columns: minmax(8rem, 1fr) minmax(0, 2fr);
  gap: var(--s-3);
  font-size: var(--t-base);
}

.datos__clave { color: var(--c-ink-soft); }
.datos__valor { color: var(--c-ink); }

/* El valor que falta (#175), apagado como la glosa vacía de la cabecera: la
   raya está para decir que el hueco existe, no para leerse igual que un dato. */
.datos__valor--vacio { color: var(--c-ink-faint); }

/* La prosa que acompaña a un dato (#269): hoy la de la polinización, debajo de
   su escala. No es una fila de clave y valor —no tiene clave— sino el párrafo
   que explica la de encima, así que ocupa el ancho entero del panel y se
   separa un poco de ella para que se lea como su explicación y no como el
   siguiente dato de la lista. */
.datos__nota {
  font-size: var(--t-sm);
  color: var(--c-ink-soft);
  margin-top: calc(var(--s-2) * -1);
}

/* --- Galería de la ficha ------------------------------------------- */

.galeria {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: var(--s-3);
}

.galeria__foto {
  width: 100%;
  height: 120px;
  object-fit: cover;
  border-radius: var(--r-md);
  border: 1px solid var(--c-border);
}

.portada {
  width: 100%;
  height: var(--h-cover);
  object-fit: cover;
  object-position: center;
  border-radius: var(--r-lg);
  border: 1px solid var(--c-border);
}

/* --- Planificador (#259, #267) --------------------------------------- */

/* Las semillas de un año. Sin viñeta: lo que agrupa es el rótulo del año, y
   una viñeta por semilla añadiría una segunda jerarquía donde solo hay una. */
.planificador__semillas {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--s-2);
}

.planificador__semillas .card__meta { margin-left: var(--s-2); }

/* Las nueve casillas de la ficha. Sin el marco ni el hueco del `fieldset`, que
   aquí no rotula nada: la leyenda es para el lector de pantalla y el título de
   la sección ya está encima. Se envuelven, que en un móvil son tres filas. */
.planificador__anos {
  border: 0;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2) var(--s-3);
}

/* La casilla y su año van juntas y no se parten a mitad de línea: «Año» arriba
   y «3» abajo se lee como dos cosas. */
.planificador__ano {
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
  white-space: nowrap;
}

/* --- Escala de polinización ---------------------------------------- */

/* Cinco peldaños. Sin leyenda todavía (#6), así que se acompaña siempre del
   número: un color solo no significa nada para nadie. */
/* `gap` mayor entre los extremos y la tira que entre peldaño y peldaño: los
   cinco bloques tienen que leerse como una sola cosa, y los nombres como lo que
   la rotula por fuera (#263). */
/* Envuelve desde #288: con los dos extremos escritos —«Exógama» y «Endógama»—
   la tira mide 384 px y a 360 sacaba la página de su sitio. Envolviendo, los
   nombres pasan debajo de los puntos en vez de empujar. */
.escala {
  display: inline-flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  align-items: center;
}

/* Los cinco peldaños, en su propia caja: así el hueco entre ellos es de 3 px y
   el que los separa de los nombres de los extremos es el de `.escala`. Con
   todos en el mismo contenedor haría falta un margen negativo, y `:last-of-type`
   no serviría para excluir el último —los extremos también son `span`—. */
.escala__pasos { display: inline-flex; gap: 3px; align-items: center; }

.escala__paso {
  width: 14px;
  height: 6px;
  border-radius: var(--r-full);
  background: var(--c-border);
}

.escala__paso--lleno { background: var(--c-accent); }

/* La misma escala dentro de una celda de la tabla (#270). Sin los nombres de
   los extremos, que allí no caben en nueve columnas: la frase entera está en el
   `aria-label` y en el `title`, que es lo que lee cada uno.

   Cinco puntos y no cinco barras desde #281: la fila ya es estrecha y las
   barras la ensanchaban más que la cifra que resumen. El vacío va en el wash de
   la terracota y no en el gris del borde, para que los cinco se lean como una
   escala y no como cinco cosas distintas. */
.escala--compacta .escala__paso {
  width: 8px;
  height: 8px;
  background: var(--c-primary-wash);
}

/* Y el lleno otra vez, que si no lo pierde: la regla de arriba es más
   específica que `.escala__paso--lleno` y va después. */
.escala--compacta .escala__paso--lleno { background: var(--c-accent); }

/* Cómo se llama cada extremo, a los lados de la tira (#263). El color de los
   bloques no es el portador del dato —lo prohíbe la regla de color de #3 y lo
   dejaría fuera de un lector de pantalla—: el dato es el texto, y los bloques
   son el resumen visual de algo que ya está escrito.

   Aquí estuvo `.escala__nota`, el párrafo de catálogo que #6 puso debajo de la
   etiqueta. Los dos extremos dicen lo mismo —hacia dónde va la escala— y caben
   en la propia fila. */
.escala__extremo {
  font-size: var(--t-sm);
  color: var(--c-ink-soft);
  white-space: nowrap;
}

/* ============================================================
   Lo que hace la wiki más visual sin una línea de JavaScript (#69)
   ============================================================ */

/* --- Iconos --------------------------------------------------------- */

/* Los nueve SVG de la 2.x, incrustados como sprite en la plantilla base.
   Conservan sus colores —son ilustraciones, no iconografía monocroma— así que
   aquí solo se les da tamaño y se les quita de en medio del texto. */
.icono {
  width: 20px;
  height: 20px;
  flex: none;
}


.icono--grande { width: 40px; height: 40px; }

/* --- Portada del índice --------------------------------------------- */

/* La cabecera de una página que no es el catálogo. Era una caja con borde y
   sombra; desde #283 es lo mismo que la del índice —titular y entradilla, sin
   marco—, que es lo que hace que las dos se lean como el mismo sitio. */
.portadilla {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-4);
  margin-bottom: var(--s-6);
}

.portadilla__texto { flex: 1 1 20rem; }

.portadilla h1 { font-size: var(--t-4xl); margin: 0; }

.portadilla__texto p {
  color: var(--c-ink-soft);
  margin-top: var(--s-3);
  font-size: var(--t-md);
  max-width: 46ch;
  text-wrap: pretty;
}

/* Las tres cifras del catálogo, en círculos (#280).

   #101 se las llevó del índice y tenía razón en lo que dijo: «260 semillas · 36
   familias · 132 especies» en una banda a todo lo ancho se comía la primera
   pantalla y le hablaba a quien administra, no a quien busca cuándo sembrar un
   puerro. Vuelven en otro sitio y por eso vuelven: **al lado del titular, en el
   hueco de la derecha que estaba vacío**, sin robarle una fila a nada.

   Solo salen en la rejilla y solo sin filtros: son las del catálogo entero, y
   al lado de una lista recortada dirían otra cosa que el recuento de abajo. */
.cifras {
  display: flex;
  gap: var(--s-3);
  flex: none;
}

.cifra {
  width: 118px;
  height: 118px;
  border-radius: var(--r-full);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  flex: none;
}

/* El del medio, desplazado: tres círculos iguales en fila son un gráfico; con
   uno caído son una composición, que es lo que pide la maqueta. */
.cifra:nth-child(2) { margin-top: 26px; }

/* Cada uno en su wash, con el texto que ese wash aguanta: 9.5:1, 9.1:1 y
   12.4:1. Ninguno es color por color — los tres son la misma pareja
   fondo/tinta que ya usan las etiquetas. */
.cifra--semillas { background: var(--c-primary-wash);  color: var(--c-primary-hover); }
.cifra--familias { background: var(--c-accent-2-wash); color: var(--c-accent-2-deep); }
.cifra--especies { background: var(--c-surface-raised); color: var(--c-ink); }

.cifra__numero {
  display: block;
  font-family: var(--font-display);
  font-size: 1.875rem;   /* 30px */
  line-height: var(--lh-tight);
  color: inherit;
}

.cifra__etiqueta {
  font-size: 0.71875rem;  /* 11.5px */
  color: inherit;
}

/* En el móvil no caben tres de 118 al lado del titular: pasan debajo, más
   pequeños y sin el escalón, que a esa anchura solo desordena. */
@media (max-width: 720px) {
  .cifra { width: 88px; height: 88px; }
  .cifra:nth-child(2) { margin-top: 0; }
  .cifra__numero { font-size: var(--t-xl); }
}

/* --- Tarjetas con más vida ------------------------------------------ */

/* La foto se acerca un poco dentro de su marco al pasar por encima. El marco
   no se mueve: si creciera, la rejilla entera bailaría. */
.card__marco { overflow: hidden; }

.card__marco .card__media { transition: transform var(--e-base); }
.card:hover .card__marco .card__media { transform: scale(1.04); }

@media (prefers-reduced-motion: reduce) {
  .card:hover .card__marco .card__media { transform: none; }
}

/* --- Cabecera de familia -------------------------------------------- */

/* La banda toma el color de la familia, que hasta ahora solo se veía en un
   punto de 10px. El color va como fondo de una franja estrecha y el texto
   nunca se apoya en él: los 36 valores heredados no dan contraste garantizado
   sobre blanco ni sobre negro, y no se puede saber cuál tocará. */
/* ============================================================
   Las páginas de taxonomía (#283)
   ============================================================ */

/* La banda de cabecera de una rama, sobre el wash de salvia. La franja de color
   de familia que llevaba arriba se fue: era el último hexadecimal en crudo que
   quedaba en una plantilla, y encima el que #99 ya había corregido en el resto
   del sitio por ilegible. */
.cabecera-familia {
  background: var(--c-accent-2-wash);
  border-radius: var(--r-xl);
  overflow: hidden;
  margin-bottom: var(--s-6);
}

.cabecera-familia__cuerpo {
  display: flex;
  align-items: center;
  gap: var(--s-5);
  padding: var(--s-6);
}

/* El círculo con la inicial. Decorativo: el nombre entero está al lado. */
.cabecera-familia__inicial {
  width: 88px;
  height: 88px;
  flex: none;
  display: grid;
  place-items: center;
  border-radius: var(--r-full);
  /* El peldaño de texto y no `--c-accent-2`, que es el de chrome: con la crema
     encima aquel da 3.53:1 y esto lleva una letra. Con este, 5.4:1. */
  background: var(--c-accent-2-text);
  color: var(--c-on-primary);
  font-family: var(--font-display);
  font-size: var(--t-2xl);
}

.cabecera-familia h1 { margin: 0; font-size: var(--t-3xl); }

/* «Familia · Malváceas · 5 semillas · 3 géneros». Los recuentos salen de lo que
   puede ver quien mira (#275), no del catálogo entero. */
.cabecera-familia__metadatos {
  margin: var(--s-2) 0 0;
  color: var(--c-accent-2-deep);
}

@media (max-width: 720px) {
  .cabecera-familia__cuerpo { padding: var(--s-4); gap: var(--s-4); }
  .cabecera-familia__inicial { width: 56px; height: 56px; font-size: var(--t-lg); }
}

/* --- La rejilla de familias del índice de taxonomía (maqueta 1f) ---- */

.rejilla-familias {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 22px;
  margin-bottom: var(--s-7);
}

/* `align-content: start` y la etiqueta empujada abajo: sin ellos, una familia
   sin nombre común —Amaryllidaceae, Fabaceae— tiene una línea menos, la rejilla
   la centra y la tarjeta se descoloca respecto a sus vecinas. */
.familia-tarjeta {
  display: grid;
  justify-items: center;
  align-content: start;
  gap: var(--s-2);
  padding: 26px 20px;
  background: var(--c-surface-raised);
  border-radius: var(--r-xl);
  text-align: center;
  text-decoration: none;
  color: inherit;
  transition: box-shadow var(--e-base), transform var(--e-base);
}

.familia-tarjeta:hover {
  box-shadow: var(--sh-md);
  transform: translateY(-2px);
}

/* Los dos tonos alternan por posición y no por ningún dato: es ritmo, y quien
   no los distinga tiene el nombre escrito debajo. */
.familia-tarjeta__inicial {
  width: 76px;
  height: 76px;
  display: grid;
  place-items: center;
  border-radius: var(--r-full);
  background: var(--c-primary-wash);
  color: var(--c-primary-hover);
  font-family: var(--font-display);
  font-size: var(--t-2xl);
  margin-bottom: var(--s-2);
}

.familia-tarjeta__inicial--salvia {
  background: var(--c-accent-2-wash);
  color: var(--c-accent-2-deep);
}

.familia-tarjeta__nombre {
  font-family: var(--font-display);
  font-size: var(--t-md);
  line-height: 1.2;
}

.familia-tarjeta__comun { font-size: var(--t-sm); color: var(--c-ink-soft); }

.familia-tarjeta .tag { margin-top: auto; }

/* --- La página de una rama: el árbol y sus semillas (maqueta 1g) ---- */

.rama-pagina {
  display: grid;
  grid-template-columns: 380px minmax(0, 1fr);
  gap: 48px;
  align-items: start;
}

@media (max-width: 860px) {
  .rama-pagina { grid-template-columns: 1fr; gap: var(--s-6); }
}

.arbol-rama__raiz {
  font-family: var(--font-display);
  font-size: var(--t-md);
  margin: var(--s-3) 0 var(--s-2);
}

.arbol-rama__grupos,
.arbol-rama__nodos {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Las líneas verticales que atan la rama: la del primer nivel más marcada que
   la del segundo, que es lo que deja seguir el escalón sin contar. */
.arbol-rama__grupos {
  margin-left: var(--s-2);
  padding-left: var(--s-4);
  border-left: 2px solid var(--c-accent-2);
}

.arbol-rama__nodos {
  margin-left: var(--s-2);
  padding-left: var(--s-4);
  border-left: 2px solid var(--c-accent-2-wash);
}

.arbol-rama__grupo { margin-bottom: var(--s-4); }

.arbol-rama__rango {
  font-size: var(--t-sm);
  color: var(--c-ink-soft);
}

.arbol-rama__nodos > li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s-2);
  min-width: 0;
  padding: 2px 0;
}

.arbol-rama__nodos > li > * { min-width: 0; overflow-wrap: anywhere; }

.arbol-rama__nodo { font-style: italic; }

.arbol-rama__comun { font-size: var(--t-sm); color: var(--c-ink-soft); }

/* El recuento, como etiqueta terracota clara: es lo que dice cuánto hay debajo
   antes de entrar. */
.arbol-rama__cuenta {
  font-size: var(--t-xs);
  padding: 1px var(--s-2);
  border-radius: var(--r-full);
  background: var(--c-primary-wash);
  color: var(--c-primary-hover);
}

/* Tres por fila, que es lo que cabe al lado del árbol. */
.rama-pagina__semillas .grid-cards {
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
}

/* --- Visor de fotos, con :target y sin JavaScript -------------------- */

/* Pulsar la foto lleva a `#foto-3`, y el visor aparece porque coincide con el
   fragmento de la URL. Cerrar es volver a `#`, así que el botón de atrás del
   navegador también lo cierra: es historia real, no estado de un componente.

   La alternativa era <dialog>, que exige JavaScript para abrirse. */
.visor {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: none;
  place-items: center;
  padding: var(--s-5);
  background: rgba(0, 0, 0, 0.85);
  /* Es una <figure> desde que lleva crédito (#46), y la <figure> trae margen
     propio del navegador. Sobre un `inset: 0` ese margen encoge la caja. */
  margin: 0;
}

.visor:target { display: grid; }

.visor__imagen {
  max-width: 100%;
  max-height: 90vh;
  width: auto;
  object-fit: contain;
  border-radius: var(--r-md);
}

/* La atribución de la foto ampliada. Absoluta y no una fila más de la rejilla
   para que la imagen siga centrada en la pantalla; va después de `visor__fuera`
   en el documento, así que su enlace queda por encima de la capa que cierra y
   se puede pulsar. */
.visor__credito {
  position: absolute;
  bottom: var(--s-4);
  left: 50%;
  transform: translateX(-50%);
  max-width: min(90%, 40rem);
  padding: var(--s-2) var(--s-3);
  border-radius: var(--r-md);
  background: rgba(0, 0, 0, 0.6);
  color: #fff;
  font-size: var(--t-sm);
  text-align: center;
}

.visor__credito a { color: inherit; }

/* El cierre ocupa toda la pantalla por detrás de la imagen: pulsar fuera
   cierra, como en la 2.x. */
.visor__fuera {
  position: absolute;
  inset: 0;
  cursor: zoom-out;
}

.visor__cerrar {
  position: absolute;
  top: var(--s-4);
  right: var(--s-4);
  z-index: 1;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: var(--r-full);
  background: var(--c-surface-raised);
  color: var(--c-ink);
  text-decoration: none;
  font-size: var(--t-lg);
  box-shadow: var(--sh-md);
}

/* La foto ampliable avisa de que lo es. */
.ampliable { cursor: zoom-in; display: block; }

/* --- Estado vacío ilustrado ------------------------------------------ */

.empty__dibujo {
  width: 72px;
  height: 72px;
  margin-inline: auto;
  opacity: 0.85;
}

/* ============================================================
   Revisiones e historial (#71)
   ============================================================ */

.ficha__titulo {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--s-4);
}
.ficha__titulo > div:first-child { flex: 1 1 20rem; }

.revision { display: grid; gap: var(--s-4); }

.revision__cabecera {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
}

.revision__autor { font-weight: var(--fw-medium); }

.revision__motivo {
  border-left: 3px solid var(--c-border-strong);
  padding-left: var(--s-4);
  color: var(--c-ink-soft);
}

.revision__validacion { border-top: 1px solid var(--c-border); padding-top: var(--s-3); }

/* --- Tabla de cambios ----------------------------------------------- */

/* El antes en rojo tenue y el después en verde tenue, como cualquier diff. El
   color acompaña a la posición y al encabezado de columna: quien no separe esos
   dos tonos sigue leyendo «Antes» y «Después» arriba. */
.cambios td { vertical-align: top; white-space: pre-wrap; }
.cambios th[scope="row"] { text-align: left; white-space: nowrap; }

.cambios__antes {
  background: var(--c-danger-wash);
  color: var(--c-ink);
  text-decoration: line-through;
  text-decoration-color: var(--c-danger);
}

.cambios__despues { background: var(--c-success-wash); color: var(--c-ink); }

/* --- Estadísticas ---------------------------------------------------- */

/* Rejilla de cifras. 11rem de mínimo: por debajo, un número de cuatro dígitos
   y su etiqueta dejan de caber en la misma tarjeta. */
.metricas {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
  gap: var(--s-4);
}

.metrica {
  background: var(--c-surface-raised);
  border: 1px solid var(--c-border);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-sm);
  padding: var(--s-4);
  display: grid;
  gap: var(--s-1);
  align-content: start;
}

/* El panel ya trae fondo propio; una tarjeta blanca sobre otra blanca se pierde. */
.panel .metrica { background: var(--c-surface); box-shadow: none; }

.metrica__numero {
  font-size: var(--t-2xl);
  font-weight: var(--fw-bold);
  line-height: var(--lh-tight);
  color: var(--c-primary);
}

.metrica__etiqueta { font-size: var(--t-sm); color: var(--c-ink-soft); }
.metrica__nota { font-size: var(--t-xs); color: var(--c-ink-faint); }

/* La cola pendiente con trabajo dentro se marca. El borde acompaña al número,
   nunca lo sustituye: quien no distinga el color sigue leyendo la cifra. */
.metrica--atencion { border-color: var(--c-warning); }
.metrica--atencion .metrica__numero { color: var(--c-warning); }

/* --- Gráfica de barras ------------------------------------------------ */

.grafica { margin: 0; }

.grafica__titulo {
  font-size: var(--t-base);
  font-weight: var(--fw-medium);
  color: var(--c-ink-soft);
  margin-top: var(--s-5);
  margin-bottom: var(--s-3);
}

/* El lienzo reserva a la izquierda el sitio de las cifras del eje. Van en HTML
   y no dentro del SVG: el dibujo se estira al ancho disponible, y una letra
   estirada en un móvil de 320px no la lee nadie. */
.grafica__lienzo {
  position: relative;
  padding-left: 2.75rem;
}

.grafica__marcas {
  position: absolute;
  left: 0;
  top: 0;
  width: 2.5rem;
  height: 10rem;      /* el alto del dibujo: los % de abajo cuelgan de aquí */
}

.grafica__marca {
  position: absolute;
  right: 0;
  transform: translateY(50%);   /* la cifra centrada en su línea de rejilla */
  font-size: var(--t-xs);
  color: var(--c-ink-faint);
  font-variant-numeric: tabular-nums;
}

.grafica__area { position: relative; }

/* preserveAspectRatio="none": las barras se estiran al ancho que haya y la
   altura la fija esta regla, no el viewBox. Dentro solo hay rectángulos y
   líneas, a los que estirarse no les hace nada. */
.grafica__svg {
  display: block;
  width: 100%;
  height: 10rem;
  border-bottom: 1px solid var(--c-border-strong);
}

.grafica__barra { fill: var(--c-accent); }
.grafica__barra:hover { fill: var(--c-primary); }

/* `non-scaling-stroke` mantiene la línea en 1px: sin él, el estirado vertical
   del viewBox la engordaría hasta parecer una banda. */
.grafica__rejilla {
  stroke: var(--c-border);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}

.grafica__valores {
  position: absolute;
  inset: 0;
  pointer-events: none;   /* no tapan el hover de la barra que hay debajo */
}

.grafica__valor {
  position: absolute;
  text-align: center;
  padding-bottom: 2px;
  font-size: var(--t-xs);
  color: var(--c-ink-soft);
  font-variant-numeric: tabular-nums;
}

.grafica__eje {
  display: flex;
  justify-content: space-between;
  gap: var(--s-3);
  font-size: var(--t-sm);
  color: var(--c-ink-faint);
  margin-top: var(--s-2);
  padding-left: 2.75rem;   /* alineado con el dibujo, no con las cifras */
}

.grafica__datos { margin-top: var(--s-3); }

.grafica__ver-datos {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-size: var(--t-sm);
  color: var(--c-primary);
  cursor: pointer;
}

.grafica__vacia {
  font-size: var(--t-sm);
  color: var(--c-ink-faint);
  padding: var(--s-4) 0;
}

/* --- Medida: la barrita de proporción de una fila --------------------- */

.medida {
  display: block;
  width: 100%;
  max-width: 12rem;
  height: 6px;
  border-radius: var(--r-full);
  background: var(--c-border);
  overflow: hidden;
}

.medida__relleno {
  display: block;
  height: 100%;
  background: var(--c-accent);
}

/* --- Permisos por módulo --------------------------------------------- */

.permisos {
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  padding: var(--s-4);
  display: grid;
  gap: var(--s-3);
}

.permisos + .permisos { margin-top: var(--s-3); }

.permisos__modulo {
  font-size: var(--t-sm);
  font-weight: var(--fw-medium);
  color: var(--c-ink-soft);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding-inline: var(--s-2);
}

/* --- Redactar un correo: el cuerpo y sus campos, juntos (#233) --------- */

/* La lista de campos solo sirve mientras se escribe, así que va al lado y no
   debajo. En estrecho se apilan y la lista sube: se lee antes de escribir, no
   después. */
.redaccion {
  display: grid;
  gap: var(--s-5);
  align-items: start;
}

@media (min-width: 60rem) {
  .redaccion { grid-template-columns: minmax(0, 2fr) minmax(16rem, 1fr); }
  /* Se queda a la vista mientras el cuerpo se desplaza, que es todo el
     objetivo: la ayuda no puede irse arriba justo cuando se escribe. */
  .redaccion__campos {
    position: sticky;
    top: var(--s-4);
    max-height: calc(100vh - var(--s-5) * 2);
    overflow-y: auto;
  }
}

@media (max-width: 59.99rem) {
  .redaccion__campos { order: -1; }
}

.campos { display: grid; gap: var(--s-2); margin: 0; }
.campos dt { margin-top: var(--s-3); }
.campos dt:first-child { margin-top: 0; }
.campos dd {
  margin: 0;
  font-size: var(--t-sm);
  color: var(--c-ink-soft);
}

.campos__ejemplo {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  color: var(--c-ink-soft);
  opacity: 0.85;
}

/* Solo cuando el script ha convertido el `<code>` en botón: sin él no se puede
   pulsar y no debe parecer que sí. */
.insertable {
  cursor: pointer;
  border: 1px solid var(--c-border);
  border-radius: var(--r-sm);
  padding: var(--s-1) var(--s-2);
}

.insertable:hover,
.insertable:focus-visible {
  border-color: var(--c-primary);
  color: var(--c-primary);
}

/* --- Móvil: legibilidad y objetivos táctiles -------------------------- */

/* Los 14px de cuerpo vienen de la 2.x y en escritorio se quedan. En el móvil
   estorban dos veces:

   1. Safari en iPhone **hace zoom al enfocar cualquier campo por debajo de
      16px**, y al salir deja la página desplazada. No es una preferencia
      estética: es un salto de la interfaz en cada formulario, y el reinicio de
      arriba —`input, button, textarea, select { font: inherit }`— hace que los
      campos hereden esos 14px.
   2. La aplicación se lee en el huerto, a pleno sol y con una mano.
   Los metadatos siguen en --t-sm: lo que sube es lo que se lee y lo que se
   toca. */
@media (max-width: 859px) {
  .page { font-size: var(--t-md); }

  .input, .textarea, .select, .btn { font-size: var(--t-md); }

  /* Los campos y los botones ya tenían 44px. Estos no. */
  .tabs__item,
  .paginacion__enlace,
  .vistas__opcion {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  .paginacion__enlace { min-width: 44px; }
}

/* --- Cajón de filtros del índice -------------------------------------- */

/* En el móvil, buscador y dos desplegables apilados se comían la pantalla
   antes de la primera semilla. Los desplegables se guardan en un `<details>`
   nativo: abre y cierra sin JavaScript, y **sus controles se envían con el
   formulario aunque esté cerrado**, que es lo que hace innecesario duplicar
   nada en campos ocultos. */

/* El cajón de filtros de #88 se retiró en #101: quedaban dos controles y dos
   no son un cajón. Con él se van sus reglas — y con ellas un fallo que llevaba
   tiempo: Chromium moderno colapsa el contenido de un `<details>` cerrado con
   `content-visibility` sobre `::details-content`, así que la regla de #88 que
   en escritorio sobrescribía el `display` del hijo ya no lo mostraba. El cuerpo
   salía con anchura 0. Si algún día hace falta otro cajón, esto es lo que hay
   que saber antes de escribirlo. */

/* El calendario de tres filas (#108): siembra, floración y cosecha. */

.calendario { display: grid; gap: var(--s-5); }

/* La frase va antes de la rejilla y es lo que de verdad publica el dato (#96):
   la rejilla solo lo colorea. */
.calendario__frase {
  margin-bottom: var(--s-2);
  color: var(--c-ink);
}
.calendario__frase strong { color: var(--c-primary); }

/* Cada época con su color. El color no distingue por sí solo —la frase de
   arriba ya dice cuál es cuál y la celda marcada cambia de peso—, así que esto
   es ayuda visual, no el portador del dato. Los dos tokens son nuevos y llevan
   su contraste calculado sobre `--c-on-primary`, que es el texto que va encima
   en los dos temas. */
.months--floracion .months__cell--on { background: var(--c-floracion); }
.months--cosecha   .months__cell--on { background: var(--c-cosecha); }

/* ============================================================
   Las páginas de mes (#102)
   ============================================================ */

.mes__entradilla {
  font-family: var(--font-ui);
  font-size: var(--t-md);
  line-height: var(--lh-prose);
  color: var(--c-ink);
  max-width: var(--w-prose);
  margin-top: var(--s-3);
}

/* La cinta es la navegación de esta página, no un adorno: se salta de un mes a
   otro sin volver al índice. En el móvil se desplaza dentro de sí misma, igual
   que la fila A–Z. */
/* ============================================================
   La banda del mes (#284)
   ------------------------------------------------------------
   Salvia muy oscura a todo el ancho de la página, con el
   titular, el recuento, la entradilla y los doce meses dentro.

   A sangre de la página y no de la ventana, igual que la portada
   de la ficha (#282): `100vw` con márgenes negativos cuenta la
   barra de scroll y saca scroll horizontal.
   ============================================================ */

.mes-banda {
  margin-inline: calc(-1 * var(--s-4));
  margin-bottom: var(--s-6);
  padding: var(--s-7) var(--s-6) var(--s-5);
  background: var(--c-nav);
  border-radius: var(--r-xl);
  color: var(--c-ink-on-dark);
}

.mes-banda h1 {
  margin: 0;
  font-size: var(--t-4xl);
  color: var(--c-ink-on-dark);   /* 11.8:1 sobre la banda */
}

/* El recuento es la respuesta, así que va delante de la entradilla y con más
   voz que ella. */
/* Mismo caso que los enlaces del pie: el wash de salvia se da la vuelta con el
   tema y aquí hace falta el token que significa «texto sobre oscuro».
   11.8:1 en claro, 15.7:1 en oscuro. */
.mes-banda__recuento {
  margin: var(--s-3) 0 0;
  font-size: var(--t-md);
  color: var(--c-ink-on-dark);
}

.mes-banda__entradilla {
  margin: var(--s-3) 0 0;
  max-width: var(--w-prose);
  color: var(--c-ink-on-dark);
  opacity: 0.88;
}

.cinta-meses {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  margin-top: var(--s-5);
}

/* Píldoras de salvia oscura sobre la banda. Su texto da 9.1:1 —el ratio que el
   paquete de diseño no llegó a calcular para este par—, y el relleno se queda
   en 1.4:1 contra la banda: no llega al 3:1 de WCAG 1.4.11 y **no hace falta**,
   porque lo que identifica cada control es su propio texto, con nueve de
   contraste, dentro de un `<nav>` con nombre. Ninguno de los peldaños de salvia
   llega a 3:1 sobre una banda tan oscura; el que más aclara es el que menos
   contraste le deja al texto. */
.cinta-meses__mes {
  padding: var(--s-2) var(--s-4);
  border: 1px solid transparent;
  border-radius: var(--r-full);
  white-space: nowrap;
  color: var(--c-accent-2-wash);
  background: var(--c-accent-2-deep);
}

.cinta-meses__mes:hover { text-decoration: none; filter: brightness(1.25); }

/* El mes de la página, con relleno **y** peso: el color no puede ser la única
   señal de dónde está uno.

   `--c-primary` y no la terracota media de las maquetas: con la crema encima,
   aquella se queda en 3.03:1 y esta da 5.7:1. */
.cinta-meses__mes--activo {
  background: var(--c-primary);
  border-color: var(--c-primary);
  color: var(--c-on-primary);
  font-weight: var(--fw-bold);
}

/* Y el mes de hoy, cuando no es el que se está mirando. */
.cinta-meses__mes--hoy {
  border-color: var(--c-ink-on-dark);
  font-weight: var(--fw-medium);
}

@media (max-width: 720px) {
  .mes-banda { padding: var(--s-5) var(--s-4) var(--s-4); }
  .mes-banda h1 { font-size: var(--t-2xl); }
}

.mes__familia { margin-top: var(--s-5); }

.mes__familia-nombre {
  font-family: var(--font-ui);
  font-size: var(--t-md);
  font-weight: var(--fw-medium);
  padding-left: var(--s-3);
  border-left: 3px solid var(--c-accent-2);
  margin-bottom: var(--s-3);
}

.mes__familia-nombre a { color: var(--c-ink); }
.mes__familia-nombre a:hover { color: var(--c-primary); }

.mes__lista {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: var(--s-3);
  list-style: none;
  padding: 0;
  padding-left: var(--s-4);
}

/* `align-content: start`: la rejilla estira sus filas para llenar el alto de la
   más alta de la línea, y una semilla sin germinación anotada se quedaba con el
   nombre científico a media caja. */
.mes__ficha { display: grid; gap: 2px; align-content: start; }

.mes__linea { max-width: var(--w-prose); line-height: var(--lh-prose); }

/* Los dos meses contiguos, para recorrer el año de uno en uno. */
.mes__vecinos {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--s-3);
  margin-top: var(--s-7);
  padding-top: var(--s-4);
  border-top: 1px solid var(--c-border);
}

/* El orden vive en la fila del recuento desde #102: es un control suelto, y
   una barra de herramientas para él solo era una caja alrededor de nada. */
.orden {
  display: flex;
  align-items: center;
  gap: var(--s-2);
}
.orden .select { width: auto; }

/* ============================================================
   El cajón de filtros del índice (#280)
   ------------------------------------------------------------
   La maqueta lo pinta como una píldora de arena con todo dentro:
   buscador, los desplegables y el conmutador de vista.

   Aquí dentro **no va el buscador**. Vive en la barra superior
   desde #98 y en todas las páginas; traerlo también aquí es la
   duplicación que aquella issue quitó, y obligaba a elegir cuál
   de los dos era el bueno. Lo que entra es lo que ya había.

   Es un modificador y no un cambio de `.cluster`: esa clase la
   usan 58 plantillas y aquí solo se quiere vestir una fila.
   ============================================================ */
.cluster--filtros {
  background: var(--c-surface-raised);
  border-radius: var(--r-full);
  padding: var(--s-3) var(--s-4);
  gap: var(--s-3);
  row-gap: var(--s-2);
}

/* Los campos de dentro van sobre la crema de la página, para despegarse de la
   arena del cajón — al revés que en el resto del sitio, donde el campo es lo
   claro sobre lo oscuro. */
.cluster--filtros .select,
.cluster--filtros .input { background: var(--c-surface); }

/* Los desplegables del cajón sí van en píldora: son cortos, van dentro de una
   píldora mayor y ahí la forma no compite con ningún botón de al lado. */
.cluster--filtros .select { border-radius: var(--r-full); }

/* Un `select` mide por su opción más larga —«Nombre científico (A–Z)»— y en un
   móvil eso sacaba el formulario 22 px fuera de la pantalla. */
.cluster--filtros .orden { flex-wrap: wrap; max-width: 100%; }
.cluster--filtros .orden .select { min-width: 0; max-width: 100%; }

/* A esta anchura la píldora deja de tener sentido: las esquinas de 999px
   alrededor de cinco filas apiladas dibujan un óvalo. */
@media (max-width: 720px) {
  .cluster--filtros {
    border-radius: var(--r-lg);
    padding: var(--s-3);
  }
}

/* ============================================================
   El taller (#103)
   ------------------------------------------------------------
   Un solo armazón para leer y para trabajar: misma barra, mismo
   papel, mismos colores. **Lo único que separa trabajar de leer
   es la densidad.** Aquí no hay familia botánica, así que no hay
   croma de acento: el color que queda es semántico.
   ============================================================ */

.taller {
  /* Un punto por debajo de la interfaz: 13px. En una pantalla que se opera
     —tablas, cifras, listas de perfiles— cabe más sin apretar la lectura,
     porque no se lee seguido, se busca. */
  font-size: 0.8125rem;

  /* Numerales tabulares en todo. Solo afecta a las cifras, y en el taller casi
     todas están en columna: sin esto, un 111 ocupa menos que un 999 y las
     columnas de números dejan de alinearse. */
  font-variant-numeric: tabular-nums;
}

/* El titular baja un peldaño: en una pantalla de trabajo, 36px de serif es un
   cartel. Se queda en serif — el cromo no cambia, solo la escala. */
.taller h1 { font-size: var(--t-2xl); }
.taller h2 { font-size: var(--t-lg); }

/* Filas más apretadas. */
.taller .panel { padding: var(--s-4); }
.taller .table th, .taller .table td { padding: var(--s-2) var(--s-3); }
.taller .datos { gap: var(--s-2); }
.taller .metrica { padding: var(--s-3) var(--s-4); }

/* La cola pendiente, con franja. El borde de color no bastaba: en escala de
   grises un ámbar y un gris claro se parecen demasiado, y entonces la señal
   volvía a ser solo cromática. Una franja de 4px es un cambio de **forma**, y
   además el ámbar es oscuro, así que en gris se lee como una barra negra.
   La cifra sigue estando: el color subraya, no informa solo. */
.metrica--atencion {
  border-color: var(--c-warning);
  border-left: 4px solid var(--c-warning);
}
.metrica--atencion .metrica__numero { color: var(--c-warning); }

/* --- Las pantallas de sesión ---------------------------------------- */

/* Estrechas y centradas. Un campo de contraseña de mil píxeles de ancho no lo
   pide nadie, y estas pantallas son nivel 1 (#95): un fallo aquí no degrada la
   experiencia, deja a alguien fuera de su cuenta. No llevan la densidad del
   taller — un formulario de dos campos no gana nada a 13px. */
/* ============================================================
   Las pantallas de sesión (#285)
   ------------------------------------------------------------
   Entrar, registro, recuperar, el código de acceso y el de
   respaldo: once pantallas que comparten superficie, así que se
   visten una vez.

   Son **nivel 1**: el HTML del servidor las lleva enteras y no
   hay JavaScript. Aquí un fallo de script no degrada nada, deja
   a alguien fuera de su cuenta.
   ============================================================ */

.sesion {
  max-width: 28rem;
  margin-inline: auto;
  padding: var(--s-6);
  background: var(--c-surface-raised);
  border-radius: var(--r-xl);
}

.sesion h1 {
  font-size: var(--t-2xl);
  margin-bottom: var(--s-4);
}

/* Los campos van sobre la crema de la página, para despegarse de la arena de la
   tarjeta — al revés que en el resto del sitio, igual que en el cajón de
   filtros del índice. */
.sesion .input,
.sesion .select,
.sesion .textarea { background: var(--c-surface); }

/* La fila de abajo: el botón primero y los enlaces detrás, que es el orden en
   que se usan. */
.sesion .cluster { margin-top: var(--s-5); }

@media (max-width: 480px) {
  .sesion { padding: var(--s-4); border-radius: var(--r-lg); }
}

/* --- La galería de un nodo del árbol (#122) ------------------------ */

/* Una foto por semilla de toda la rama. Es navegación además de adorno, así
   que el pie con el nombre no es opcional: una rejilla de fotos mudas obliga a
   pulsarlas una a una para saber qué son.

   Se llama `galeria-rama` y no `galeria` porque `.galeria` ya es la de la
   ficha, con `.galeria__foto` sobre el <img>. Dos cosas distintas con el mismo
   nombre de clase es exactamente lo que se arregló en #94. */
.galeria-rama {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: var(--s-4);
}

.galeria-rama__foto {
  display: grid;
  gap: var(--s-2);
  text-decoration: none;
  color: inherit;
}

.galeria-rama__marco {
  display: block;
  border-radius: var(--r-md);
  overflow: hidden;
  /* El hueco reservado antes de que llegue la imagen. Un salto de maquetación
     es CLS, y el CLS cuenta para el posicionamiento (#95). */
  aspect-ratio: 1;
  background: var(--c-surface-alt);
}

.galeria-rama__marco img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--e-base);
}

.galeria-rama__foto:hover .galeria-rama__marco img { transform: scale(1.04); }

@media (prefers-reduced-motion: reduce) {
  .galeria-rama__foto:hover .galeria-rama__marco img { transform: none; }
}

.galeria-rama__pie {
  font-size: var(--t-sm);
  color: var(--c-ink-soft);
  line-height: 1.3;
}

.galeria-rama__foto:hover .galeria-rama__pie { color: var(--c-ink); }

/* --- El árbol de taxonomía del formulario (#144) ------------------- */

.ars { display: grid; gap: var(--s-2); }

/* --- En reposo: lo que hay, y un botón (#151) ---------------------- */

/* La clasificación se propone y se confirma, así que el caso normal es no
   tocar nada. `<details>` da el abierto/cerrado sin JavaScript. */
.ars__reposo {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s-3);
  padding: var(--s-3);
  border: 1px solid var(--c-border-strong);
  border-radius: var(--r-md);
  background: var(--c-surface-raised);
  cursor: pointer;
}

.ars__reposo:hover { border-color: var(--c-primary); }

/* El linaje entero, con lo deducido apartado del ojo (#152). Se lee de una
   pasada porque el gris dice «esto no lo has decidido tú»; en tinta plana,
   dieciséis nombres latinos son un muro. */
.ars__ruta { color: var(--c-ink); line-height: var(--lh-snug); }
.ars__ruta--vacia { color: var(--c-ink-soft); font-style: italic; }
.ars__sep { color: var(--c-ink-faint); margin: 0 0.15em; }

.ars__paso--deducido {
  color: var(--c-ink-faint);
  font-size: var(--t-sm);
}

/* El rango va en el `title`, así que el puntero lo anuncia. */
.ars__paso[title] { cursor: help; }

/* El botón de cambiar no es un `<button>`: el que abre es el `<summary>`, y
   meter un botón dentro sería un control dentro de otro. Se pinta como tal. */
.ars__cambiar {
  margin-left: auto;
  font-family: var(--font-ui);
  font-size: var(--t-sm);
  color: var(--c-primary);
  text-decoration: underline;
}

.ars__abierto { display: grid; gap: var(--s-2); margin-top: var(--s-3); }



/* Altura fija y scroll propio. Es lo que permite que la caja no crezca al
   desplegar una rama de 400 especies: sin esto, abrir Asteraceae empuja el
   resto del formulario media pantalla hacia abajo cada vez. */
.ars__caja {
  max-height: 22rem;
  overflow-y: auto;
  border: 1px solid var(--c-border-strong);
  border-radius: var(--r-md);
  padding: var(--s-2);
  background: var(--c-surface-raised);
}

/* El aviso tiene su altura hecha aunque esté vacío: lo escribe un script y lo
   que pinta un script no puede empujar lo que ya estaba (#95, condición 2). */
.ars__aviso {
  min-height: 1.2em;
  font-size: var(--t-sm);
  color: var(--c-ink-soft);
}

.ars__ramas { list-style: none; margin: 0; padding: 0; }

/* La sangría cuelga de la lista y no del nodo, que es lo que hace que la
   recursión no tenga que saber a qué profundidad está. */
.ars__ramas .ars__ramas { padding-left: var(--s-4); }

.ars__nodo {
  display: flex;
  align-items: baseline;
  gap: var(--s-2);
  padding: 2px var(--s-1);
  border-radius: var(--r-sm);
  cursor: pointer;
}

.ars__nodo:hover { background: var(--c-surface-alt); }

/* Dentro de un `<summary>` el rótulo es solo el nombre: el nombre elige y el
   resto de la fila despliega. Se marca como pulsable para que se note. */
.ars summary .ars__nombre { cursor: pointer; }
.ars summary .ars__nombre:hover { text-decoration: underline; }

/* Una hoja no lleva triángulo, así que se alinea con el nombre de sus
   hermanos con triángulo en vez de quedarse un escalón a la izquierda. */
.ars__nodo--hoja { padding-left: calc(var(--s-4) + 2px); }

.ars__nombre { color: var(--c-ink); }

.ars__rango {
  font-size: var(--t-sm);
  color: var(--c-ink-faint);
  text-transform: lowercase;
}

.ars__cuenta {
  font-size: var(--t-sm);
  color: var(--c-ink-soft);
  margin-left: auto;
}

/* El linaje del resultado de una búsqueda: «Solanum» a secas puede ser dos
   ramas distintas, así que el camino es parte de la respuesta. */
.ars__linaje {
  font-size: var(--t-sm);
  color: var(--c-ink-faint);
  flex-basis: 100%;
}

.ars__vacio {
  padding: var(--s-2);
  font-size: var(--t-sm);
  color: var(--c-ink-soft);
}

/* Lo que acaban de proponer las fuentes. Se señala además de marcarse: en una
   caja con scroll, un radio marcado en el sitio correcto sigue siendo un radio
   más entre cincuenta. */
.ars__nodo--propuesto {
  background: var(--c-primary-wash);
  outline: 2px solid var(--c-primary);
}

.ars summary { cursor: pointer; }
.ars summary::marker { color: var(--c-ink-faint); }

/* --- La propuesta de las fuentes taxonómicas (#124) ---------------- */

.propuesta {
  display: grid;
  gap: var(--s-3);
  margin-top: var(--s-3);
}

/* El panel existe antes de tener nada dentro y reserva su altura: la respuesta
   tarda lo que tarde GBIF, y un panel que aparece de golpe empuja el resto del
   formulario hacia abajo. Un salto de maquetación es CLS (#95). */
.propuesta__panel {
  min-height: 3.5rem;
  padding: var(--s-3);
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  background: var(--c-surface-alt);
  display: grid;
  gap: var(--s-2);
  align-content: start;
}

.propuesta__cadena {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--s-2);
}

.propuesta__paso {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s-2);
}

.propuesta__nombre { font-weight: 600; }

.propuesta__rango,
.propuesta__nota,
.propuesta__conflicto {
  font-size: var(--t-sm);
  color: var(--c-ink-soft);
  margin: 0;
}

/* Tres marcas y ningún color solo: cada una lleva su palabra, porque «se
   crearía» y «ya está» no se distinguen por el tono para quien no ve el tono. */
.propuesta__marca {
  font-size: var(--t-sm);
  padding: 0 var(--s-2);
  border-radius: var(--r-sm);
  border: 1px solid var(--c-border);
}

.propuesta__marca--nuevo { border-color: var(--c-primary); color: var(--c-primary); }
.propuesta__marca--sin-contraste { border-style: dashed; }

/* --- El editor visual de artículo (#130) --------------------------- */

/* Solo el encaje: el aspecto del editor lo pone su propia hoja, copiada en
   `css/vendor/`. Lo que hace falta aquí es que no se salga de la caja del
   campo y que la reserva de altura no cambie al conmutar entre el modo visual
   y el Markdown crudo — el conmutador está para usarse, y una página que salta
   al pulsarlo invita a no volver a pulsarlo. */
.editor-articulo {
  border-radius: var(--r-md);
  overflow: hidden;
}

.editor-articulo .toastui-editor-defaultUI {
  border-color: var(--c-border-strong);
  border-radius: var(--r-md);
}

/* La tipografía de dentro es la de la prosa del sitio, no la del paquete: lo
   que se escribe aquí se lee después en `.prose`, y ver una letra al escribir
   y otra al publicar es la forma más tonta de que un texto quede corto. */
.editor-articulo .toastui-editor-contents {
  font-family: var(--font-ui);
  font-size: 1rem;
  /* Declarada a propósito, y no solo por estética: `editor-articulo.js` la lee
     para saber cuánto mide una línea y dejar la caja en cinco (#146). Sin ella,
     el editor de Markdown calculaba 16 px y el visual otra cosa, y las cinco
     líneas pedidas salían tres. */
  line-height: var(--lh-prose);
}

/* --- El área de escritura, y su barra de desplazamiento (#154) ----- */

/* Cinco líneas, fijadas **aquí** y no con el `setHeight()` del paquete: aquel
   fija la caja entera y reparte restando lo que mide la barra de formato, y con
   la barra encogida por `zoom` el reparto salía mal — su área interna quedaba
   en 200 px dentro de un hueco de 134, y lo que pasara de cinco líneas se
   recortaba sin barra: 373 px inalcanzables en un campo de once párrafos.

   `--alto-escritura` lo publica `editor-articulo.js` midiendo una línea de
   verdad. Sin el script no hay editor, así que tampoco hay nada que dimensionar
   y el respaldo no llega a usarse; se declara igual para que esto no dependa de
   que el otro fichero llegue. */
.editor-articulo .toastui-editor-defaultUI { height: auto; }

.editor-articulo .toastui-editor-ww-container,
.editor-articulo .toastui-editor-md-container {
  height: var(--alto-escritura, 8.4rem);
  overflow-y: auto;
  /* El carril, siempre. Con `auto` a secas el navegador usa una barra de
     superposición que no se ve, y lo que se pidió es justamente verla. Reservar
     el hueco tiene además la ventaja de que el texto no se recoloca al cruzar
     la quinta línea. */
  scrollbar-gutter: stable;
  scrollbar-width: thin;
}

/* Y que el contenido deje de heredar el alto viejo: quien desplaza es el
   contenedor, no él. Con los dos desplazando, ninguno llegaba al final. */
.editor-articulo .toastui-editor-ww-container .toastui-editor-contents {
  height: auto;
  overflow: visible;
}

/* --- La barra de formato, más baja (#146) -------------------------- */

/* Con quince editores en una página, la barra por defecto —46 px— son casi
   setecientos píxeles de cromo. Baja a 33.

   Lo que mida no hay que repetirlo en ninguna parte: `editor-articulo.js` la
   mide ya pintada para calcular su caja, precisamente para que tocar esto no
   obligue a tocar aquello.

   El sprite manda cómo se encoge. Los iconos son un PNG posicionado por clase,
   así que estrechar el botón los recortaría: primero se quita lo que no toca al
   sprite —márgenes y relleno— y el resto lo hace `zoom`, que a diferencia de
   `transform` sí encoge la caja y no deja hueco a la derecha. Donde `zoom` no
   exista la barra se queda como estaba: más alta, nunca rota. */
.editor-articulo .toastui-editor-toolbar { height: auto; }

.editor-articulo .toastui-editor-defaultUI-toolbar {
  height: auto;
  padding: 0 var(--s-2);
  zoom: 0.85;
}

.editor-articulo .toastui-editor-defaultUI-toolbar button {
  margin: 3px 2px;
}

.editor-articulo .toastui-editor-toolbar-divider {
  margin: 9px 6px;
  height: 14px;
}

/* El conmutador de Markdown va en la misma barra y con el mismo `zoom`, así
   que solo hay que bajarle el alto propio para que no la vuelva a estirar. */
.editor-articulo .toastui-editor-mode-switch {
  height: auto;
  padding: 2px 0;
}

/* --- El crédito de una foto (#46) ---------------------------------- */

/* Solo aparece cuando la licencia pide atribución. Va debajo y en pequeño,
   pero **va**: publicar una CC BY sin atribuir incumple su única condición, y
   un crédito que estorbe al diseño se acaba quitando. */
.galeria__pieza { margin: 0; }

.galeria__credito {
  font-size: var(--t-sm);
  color: var(--c-ink-soft);
  margin-top: var(--s-2);
  line-height: 1.3;
}

/* El crédito de la portada va sobre la propia foto, no debajo: una línea suelta
   ahí abajo separaría el nombre de la imagen a la que pertenece.

   **Arriba a la derecha desde #282**, y no en una banda a lo ancho del borde de
   abajo. Con la cabecera a sangre, abajo es donde están el chip, el nombre y el
   científico: la banda los pisaba y además salía cortada. La atribución de una
   CC BY tiene que poder leerse (#46), así que no puede compartir esquina con el
   titular.

   Lleva su propio velo porque va sobre la foto sin tocar, donde el degradado
   de la cabecera todavía no ha empezado a fundir. */
.credito-encima {
  position: absolute;
  top: var(--s-3);
  right: var(--s-3);
  left: auto;
  max-width: min(24rem, 60%);
  padding: var(--s-1) var(--s-3);
  font-size: var(--t-xs);
  line-height: 1.3;
  color: #fff;
  background: rgb(0 0 0 / 0.55);
  border-radius: var(--r-full);
  text-align: right;
}

.credito-encima a { color: inherit; }

/* --- La cola de triaje de fotos (#46) ------------------------------ */

.procedencia__indicio {
  color: var(--c-ink-soft);
  font-size: var(--t-sm);
  margin-bottom: var(--s-4);
}

/* La foto a la izquierda y su declaración a la derecha. Se apila por debajo
   de 40rem, donde 200px de imagen dejarían el desplegable en dos palabras. */
.procedencia {
  display: grid;
  grid-template-columns: 200px 1fr;
  gap: var(--s-4);
  align-items: start;
  margin-bottom: var(--s-3);
}

@media (max-width: 40rem) {
  .procedencia { grid-template-columns: 1fr; }
}

.procedencia__foto img {
  width: 100%;
  border-radius: var(--r-md);
  border: 1px solid var(--c-border);
}

.procedencia__sin-imagen {
  color: var(--c-ink-faint);
  font-size: var(--t-sm);
  padding: var(--s-4);
  border: 1px dashed var(--c-border);
  border-radius: var(--r-md);
  text-align: center;
}

.procedencia__ficha { font-weight: 600; }

/* El nombre del fichero es el indicio, así que se lee tal cual, en monoespacio
   y sin desbordar el panel cuando la URL es larga. */
.procedencia__fichero {
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  color: var(--c-ink-faint);
  overflow-wrap: anywhere;
  margin-bottom: var(--s-3);
}

/* Lo que propuso quien subió la foto (#187). En el color del texto normal y no
   en el apagado del nombre de fichero: esto no es un indicio leído de una
   cadena, lo ha escrito una persona mirando la imagen. */
.procedencia__propuesta {
  font-size: var(--t-sm);
  margin-bottom: var(--s-3);
}

/* Declarar la procedencia son tres decisiones seguidas, así que se separan como
   en el resto de formularios del sitio: con `.stack`. Sin eso, la ayuda de la
   licencia quedaba pegada al rótulo de la autoría y las tres se leían como un
   párrafo (#265).

   Y con una medida máxima: el panel ocupa el ancho de la página, pero un nombre
   de autor no necesita mil píxeles para escribirse. */
.procedencia__declarar {
  max-width: 34rem;
  margin-top: var(--s-4);
}

/* Las acciones son otra cosa que declarar la procedencia, y hasta ahora se
   apilaban a continuación sin nada que las separase. */
.procedencia__acciones {
  margin-top: var(--s-5);
  padding-top: var(--s-4);
  border-top: 1px solid var(--c-border);
}

/* El desplegable de tipo, del ancho de lo que dice. `.select` lo pone al 100 %,
   que dentro de un formulario flexible significa «toda la fila»: el desplegable
   se comía la línea y el botón de clasificar caía debajo, con el de retirar
   centrado al lado como si fuera de otro sitio (#265). */
.procedencia__acciones .select {
  width: auto;
  max-width: 100%;
}

/* La confirmación de retirar una foto (#188). Es un `<details>`: el aviso de
   que el borrado no tiene vuelta atrás tiene que seguir estando con el script
   apagado, así que lo abre el navegador y el botón de verdad vive dentro. */
.retirar > summary {
  display: inline-flex;
  align-items: center;
  cursor: pointer;
  list-style: none;
}

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

.retirar[open] > summary { margin-bottom: var(--s-2); }

.retirar p {
  font-size: var(--t-sm);
  margin-bottom: var(--s-2);
}

/* --- El árbol de la clasificación (#133) --------------------------- */

/* Anidado con `<details>`, que es HTML y no un script: expandir y contraer
   funcionan con el JavaScript apagado. */

/* Lo que mide el triángulo de desplegar. Vive en la rama y no suelto en los
   tokens porque no es una medida del sistema: es el tamaño de este dibujo, y lo
   leen dos reglas —el triángulo y el hueco que le reserva la hoja— que tienen
   que seguir midiendo lo mismo (#194). */
.arbol { --triangulo: 0.45rem; }

.arbol, .rama__hijos {
  list-style: none;
  margin: 0;
  padding: 0;
}

.rama__hijos {
  /* La sangría y el filete que la acompaña son lo que deja seguir una rama de
     dieciséis escalones sin contar con el dedo. */
  margin-left: var(--s-3);
  padding-left: var(--s-4);
  border-left: 1px solid var(--c-border);
}

.rama summary,
.rama__hoja {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s-2);
  padding: var(--s-1) 0;
  /* Un elemento flex no baja de su ancho mínimo de contenido salvo que se le
     diga, y «Eudicotiledóneas superrosídeas» no tiene dónde partirse. Con
     dieciséis escalones de sangría delante, eso sacaba el árbol de la pantalla
     en un móvil (#288). */
  min-width: 0;
}

.rama summary > *,
.rama__hoja > * {
  min-width: 0;
  overflow-wrap: anywhere;
}

.rama summary { cursor: pointer; }

/* El triángulo que dice que ahí hay algo debajo (#194).

   Dibujado y no el del navegador, porque el del navegador aquí no existe: se lo
   llevan por delante dos reglas y cada una bastaría sola. `list-style` **se
   hereda**, así que el `none` que hay arriba para los `<li>` llega también al
   `<summary>`, que es `display: list-item`; y en cuanto el `summary` pasa a
   `flex` deja de serlo, y un elemento que no es `list-item` no tiene caja de
   marcador que pintar.

   Se dibuja igual que el chevron del menú de sesión: dos bordes y un giro, sin
   imagen ni icono que cargar. Siendo el `summary` una caja flex, el `::before`
   es un hijo más y se coloca solo.

   La transición la apaga el bloque de `prefers-reduced-motion` del principio de
   la hoja, que alcanza a `*::before`. */
.rama summary::-webkit-details-marker { display: none; }

.rama summary::before {
  content: "";
  flex: none;
  width: var(--triangulo);
  height: var(--triangulo);
  border-right: 2px solid var(--c-ink-faint);
  border-bottom: 2px solid var(--c-ink-faint);
  /* Centrado en su línea y no en la base: una caja vacía no tiene línea base
     propia, así que el `align-items: baseline` de la fila la alinearía por su
     borde inferior y el triángulo quedaría bajo el texto. */
  align-self: center;
  /* Cerrado apunta a la derecha: hacia donde está lo que no se ve. */
  transform: rotate(-45deg);
  transition: transform var(--e-fast);
}

.rama details[open] > summary::before {
  transform: rotate(45deg);
}

/* La hoja no tiene triángulo, así que se le reserva su hueco para que los
   nombres queden alineados con los de las ramas que sí lo tienen. Medido y no
   a ojo: lo que ocupa el triángulo más el hueco que la caja flex pone detrás. */
.rama__hoja { padding-left: calc(var(--triangulo) + var(--s-2)); }

.rama__rango {
  font-size: var(--t-sm);
  color: var(--c-ink-soft);
  text-transform: lowercase;
}

.rama__cuenta {
  font-size: var(--t-sm);
  color: var(--c-ink-soft);
}

/* Un nodo sin publicar se enlaza igual desde #142 —su página existe, solo que
   enseña el nombre y su rama— pero no compite con los que sí tienen detalle. */
.rama--sin-detalle > details > summary > .rama__nombre,
.rama--sin-detalle > .rama__hoja > .rama__nombre {
  color: var(--c-ink-soft);
}

/* La franja de un texto legal que ha cambiado (#203). Informa mientras corre el
   plazo, así que ni tapa la página ni se puede cerrar: cerrarla sería esconder
   algo que sigue pendiente. */
.aviso-legal {
  background: var(--c-info-wash);
  border-bottom: 1px solid var(--c-border);
  font-size: var(--t-sm);
}

.aviso-legal .page { padding-block: var(--s-2); }

.aviso-legal a { color: var(--c-info); text-decoration: underline; }

/* --- Lo que cambió dentro del texto (#79) -------------------------- */

/* Un campo de párrafo puede ser largo: la celda se desplaza en vez de estirar
   la tabla hasta que la fila de al lado deje de leerse. */
.cambios__texto {
  max-height: 18rem;
  overflow-y: auto;
  white-space: pre-wrap;
}

/* `<ins>` y `<del>` son las etiquetas que HTML tiene para esto, así que un
   lector de pantalla las anuncia como inserción y eliminación sin depender del
   color. El color es la ayuda, no el mensaje. */
.cambios ins {
  background: var(--c-success-wash);
  color: var(--c-ink);
  text-decoration: none;
}

.cambios del {
  background: var(--c-danger-wash);
  color: var(--c-ink);
}

/* --- Buscar una rama sin recorrer el árbol (#192) ------------------ */

/* Un formulario de verdad, no una lista que aparece al teclear: esta página es
   nivel 1 y el servidor entrega el contenido entero (#95). El campo se lleva el
   sitio que sobra; los botones, el suyo. */
.buscador-arbol {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  margin-bottom: var(--s-4);
}

.buscador-arbol .input { flex: 1 1 16rem; }

.resultados-arbol {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Rango, nombre y cuenta en una línea; el linaje debajo. Las mismas clases que
   una rama del árbol —`.rama__rango`, `.rama__nombre`, `.rama__cuenta`—, que es
   lo que hace que un resultado se lea como lo que se ha buscado. */
.resultado-arbol {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s-2);
  padding-block: var(--s-3);
  border-bottom: 1px solid var(--c-border);
}

.resultado-arbol:last-child { border-bottom: 0; }

/* El linaje ocupa su propia línea entera, debajo del nombre: es contexto, y
   leído en la misma línea competiría con lo que sitúa. */
.resultado-arbol__linaje {
  flex-basis: 100%;
  font-size: var(--t-sm);
  color: var(--c-ink-faint);
}

/* --- La licencia, en el pie (#16) ---------------------------------- */

/* En pequeño y apagado, pero **en todas las páginas**: CC BY-SA obliga a
   identificar la licencia donde se publica el contenido, y un aviso legal
   aparte es un sitio donde nadie mira. */
/* El `max-width` es para que dos líneas seguidas no se lean a 1080px de ancho.
   El `margin-inline` es lo que centra **la caja**: sin él se queda pegada a la
   izquierda y el `text-align: center` del pie centra el texto dentro de ella,
   que a 1280px son 272 píxeles fuera de sitio (#161). La primera línea lo
   disimula porque llena la caja; la segunda, corta, lo enseña. */
/* Los textos legales del pie (#201). En línea y separados por puntos: son dos
   o tres enlaces, y una lista apilada pesaría más que lo que dice. */
.site-footer__legal {
  margin-top: var(--s-2);
  font-size: var(--t-sm);
}

.site-footer__legal a { text-decoration: underline; }

.site-footer__licencia {
  margin-top: var(--s-2);
  margin-inline: auto;
  font-size: var(--t-sm);
  color: var(--c-ink-soft);
  max-width: var(--w-prose);
}

.site-footer__licencia a { text-decoration: underline; }

/* Y en la barra de guardar, para quien escribe. Ocupa la línea entera debajo
   de los botones: el aviso tiene que leerse antes de pulsar, no después. */
.acciones__licencia {
  flex-basis: 100%;
  margin: 0;
  font-size: var(--t-sm);
  color: var(--c-ink-soft);
}

.acciones__licencia a { text-decoration: underline; }

/* --- Los doce meses, en una tira (#150) ---------------------------- */

/* Rejilla flexible: doce en una fila donde caben, seis y seis donde no. Cada
   tira pasa de 252 px a unos 34, que era casi una pantalla del formulario
   repartida entre siembra, floración y cosecha. */
.meses {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(3.4rem, 1fr));
  gap: var(--s-1);
}

.mes { cursor: pointer; }

/* La casilla nativa no se quita, se tapa: sigue recibiendo el foco, marcándose
   con la barra espaciadora y viajando en el POST. Lo que se ve es la ficha.

   `clip` y 1px y no `display: none`, que la sacaría del orden de tabulación. */
.mes__casilla {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* La marca que se ve en lugar de la casilla, en el formulario de edición.
   Se llamaba `.mes__ficha` hasta #284, igual que **una semilla de la lista de la
   página de mes**, y como esta regla va después ganaba por orden: la página de
   mes pintaba cada semilla como una casilla centrada con borde. */
.mes__marca {
  display: block;
  padding: var(--s-2) 0;
  text-align: center;
  font-family: var(--font-ui);
  font-size: var(--t-sm);
  border: 1px solid var(--c-border-strong);
  border-radius: var(--r-md);
  background: var(--c-surface-raised);
  color: var(--c-ink-soft);
  transition: background var(--e-fast), border-color var(--e-fast);
}

.mes:hover .mes__marca { border-color: var(--c-primary); color: var(--c-ink); }

/* Marcado. No solo por color: el borde engorda y la letra pasa a negrita, que
   es lo que lo distingue para quien no separa este verde del gris. */
.mes__casilla:checked + .mes__marca {
  background: var(--c-primary-wash);
  border-color: var(--c-primary);
  color: var(--c-ink);
  font-weight: var(--fw-bold);
  box-shadow: inset 0 0 0 1px var(--c-primary);
}

/* El foco se ve, porque la casilla que lo recibe está tapada. */
.mes__casilla:focus-visible + .mes__marca {
  outline: 2px solid var(--c-primary);
  outline-offset: 2px;
}

/* --- La escala de polinización (#179) ------------------------------ */

/* Una tira, como la de los meses. «Desconocido» ocupa lo que necesita su
   palabra y los cinco números se reparten el resto por igual. */
/* `justify-content: start` para que la tira mida lo que ocupa y no lo que le
   den: sin él, la rejilla se estira al ancho del formulario y «Desconocido» se
   queda con todo el sobrante, que son varios centímetros de botón. */
.polinizacion {
  display: grid;
  grid-template-columns: auto repeat(5, 3rem);
  justify-content: start;
  /* Por abajo, que es donde están los números: solo el 1 y el 5 llevan encima
     el nombre de su extremo (#195), y alineando por arriba los otros cuatro
     quedarían una línea más altos que ellos. */
  align-items: end;
  gap: var(--s-1);
}

.polinizacion__paso {
  cursor: pointer;
  display: grid;
  justify-items: center;
  gap: 2px;
}

/* El nombre del extremo, encima de su número. Se sale de sus 3rem a propósito:
   la columna la miden los números, no las palabras, y encima solo hay hueco
   vacío. Ensanchar las cinco columnas para que «Exógama» cupiera dentro habría
   estirado la tira que #180 vino a encoger. */
.polinizacion__extremo {
  width: max-content;
  font-size: var(--t-xs);
  color: var(--c-ink-soft);
}

/* El radio nativo no se quita, se tapa: sigue recibiendo el foco, eligiéndose
   con las flechas y viajando en el POST. Igual que la casilla de los meses.

   `clip-path` y 1px y no `display: none`, que lo sacaría del orden de
   tabulación. */
.polinizacion__radio {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.polinizacion__marca {
  display: block;
  padding: var(--s-2) var(--s-3);
  text-align: center;
  font-family: var(--font-ui);
  font-size: var(--t-sm);
  border: 1px solid var(--c-border-strong);
  border-radius: var(--r-md);
  background: var(--c-surface-raised);
  color: var(--c-ink-soft);
  transition: background var(--e-fast), border-color var(--e-fast);
}

/* «Desconocido» no es un sexto nivel, es la ausencia del dato: borde
   discontinuo para que no se lea como el escalón de abajo del 1. */
.polinizacion__paso--sin .polinizacion__marca { border-style: dashed; }

.polinizacion__paso:hover .polinizacion__marca {
  border-color: var(--c-primary);
  color: var(--c-ink);
}

/* Elegido. No solo por color: el borde engorda y la cifra pasa a negrita, que
   es lo que lo distingue para quien no separe este azul del gris.

   `~` y no `+` (#196). `+` es el hermano **inmediatamente** siguiente, y desde
   #195 el 1 y el 5 llevan entre el radio y su cifra el `<span>` con el nombre
   de su extremo. Con `+`, esos dos y solo esos dos dejaban de pintarse al
   marcarlos: el clic llegaba, el valor se guardaba y no cambiaba nada, que se
   lee como una casilla que no acepta el clic. El estado del control no puede
   depender de quién se siente en medio. */
.polinizacion__radio:checked ~ .polinizacion__marca {
  background: var(--c-primary-wash);
  border-color: var(--c-primary);
  border-style: solid;
  color: var(--c-ink);
  font-weight: var(--fw-bold);
  box-shadow: inset 0 0 0 1px var(--c-primary);
}

/* El foco se ve, porque el radio que lo recibe está tapado. Mismo `~` y por el
   mismo motivo: con `+` se perdía justo en los dos extremos, que es donde
   empieza y acaba el recorrido con el teclado. */
.polinizacion__radio:focus-visible ~ .polinizacion__marca {
  outline: 2px solid var(--c-primary);
  outline-offset: 2px;
}

/* --- El formulario con índice al lado (#148) ----------------------- */

.con-indice {
  display: grid;
  grid-template-columns: 13rem minmax(0, 1fr);
  gap: var(--s-6);
  align-items: start;
}

/* El índice se queda quieto mientras se baja por el formulario. `sticky` y no
   `fixed`: así respeta el ancho de su columna y no se sale por arriba cuando
   la página está al principio.

   `align-self: stretch` en el `<nav>` no es decorativo, es lo que hace que el
   pegado funcione (#183). Un elemento `sticky` se desplaza dentro de su
   contenedor, y el `<nav>` medía exactamente lo mismo que la caja —352 px— por
   el `align-items: start` de la rejilla: cero píxeles de recorrido, así que se
   iba con la página como si fuera estático. Estirado, su contenedor mide lo que
   la columna del formulario. */
.indice { align-self: stretch; }

.indice__caja {
  position: sticky;
  /* Despejando la cabecera, que también es pegajosa: con los 16 px de antes
     el índice se quedaba **debajo** de la barra. */
  top: calc(var(--h-cabecera) + var(--s-4));
  max-height: calc(100vh - var(--h-cabecera) - var(--s-8));
  overflow-y: auto;
}

.indice__abrir {
  font-family: var(--font-ui);
  font-size: var(--t-sm);
  text-transform: uppercase;
  letter-spacing: var(--ls-rotulo);
  font-weight: var(--fw-bold);
  color: var(--c-ink-faint);
  margin-bottom: var(--s-3);
}

.indice__lista { list-style: none; margin: 0; padding: 0; }

.indice__enlace {
  display: block;
  padding: var(--s-1) var(--s-2);
  border-left: 2px solid var(--c-border);
  color: var(--c-ink-soft);
  font-size: var(--t-sm);
  line-height: var(--lh-snug);
}

.indice__enlace:hover { color: var(--c-ink); background: var(--c-surface-alt); }

/* Por dónde vas. Lo pone el script; sin él el índice sigue llevando a su
   sitio, que es lo que tiene que hacer. */
.indice__enlace--aqui {
  color: var(--c-ink);
  border-left-color: var(--c-primary);
  font-weight: var(--fw-bold);
}

/* En estrecho el índice no cabe al lado: pasa a ir arriba y cerrado, porque
   ahí ocuparía más que el primer campo del formulario. */
@media (max-width: 900px) {
  .con-indice { grid-template-columns: 1fr; gap: var(--s-4); }
  .indice__caja { position: static; max-height: none; }
  .indice__lista { display: flex; flex-wrap: wrap; gap: var(--s-1); }
  .indice__enlace { border-left: 0; border-bottom: 2px solid var(--c-border); }
}

/* --- Guardar, siempre a la vista (#148) ---------------------------- */

/* `sticky` al fondo: el navegador lo mantiene abajo mientras el formulario
   siga en pantalla, y lo suelta al llegar a su sitio. Sin una línea de
   JavaScript.

   El fondo es opaco a propósito: encima pasa texto, y una barra translúcida
   sobre prosa no se lee. */
.acciones {
  position: sticky;
  bottom: 0;
  /* El escalón del cromo, el mismo que la barra de arriba (#190). Sin él, el
     área de escritura del editor —que el paquete deja en 20— le pasa por
     encima, y el fondo opaco no sirve de nada si lo que hay que tapar se pinta
     después. */
  z-index: 30;
  margin: 0 calc(-1 * var(--s-5)) calc(-1 * var(--s-5));
  padding: var(--s-4) var(--s-5);
  background: var(--c-surface-raised);
  border-top: 1px solid var(--c-border);
  border-radius: 0 0 var(--r-lg) var(--r-lg);
}

/* --- Lo que ha fallado (#148) -------------------------------------- */

.errores__lista {
  margin-top: var(--s-2);
  padding-left: var(--s-5);
  list-style: disc;
}

.errores__lista a { text-decoration: underline; }

/* El campo que falla se distingue de un vistazo, además de por su mensaje:
   quien llega desde el resumen tiene que ver dónde ha aterrizado. */
.field--falla {
  border-left: 3px solid var(--c-danger);
  padding-left: var(--s-3);
  margin-left: calc(-1 * var(--s-3) - 3px);
}

/* Al saltar a una sección desde el índice, que no quede pegada al borde de
   arriba: `scroll-margin` es lo que separa el ancla del filo. */
.grupo, .field { scroll-margin-top: var(--s-6); }

/* --- El formulario por secciones (#141) --------------------------- */

/* Un bloque por sección, con filete arriba: es el mismo recurso que separa las
   secciones de la ficha publicada, y a propósito. Quien escribe está viendo la
   misma división que verá quien lea.

   El primero no lleva filete: sería una raya justo debajo del aviso de qué pasa
   al guardar, y ahí no separa nada. */
.grupo { display: grid; gap: var(--s-4); }

.grupo:not(:first-child) {
  padding-top: var(--s-5);
  border-top: 1px solid var(--c-border);
}

.grupo__titulo {
  font-family: var(--font-ui);
  font-size: var(--t-lg);
  font-weight: var(--fw-bold);
  color: var(--c-ink);
  margin: 0;
}

/* El rótulo de un campo dentro de una sección de varios: por debajo del `h2`
   de la sección y por encima del texto, sin versalitas —cinco rótulos
   espaciados seguidos se leen como un índice, no como un artículo—. */
.rotulo--menor {
  text-transform: none;
  letter-spacing: 0;
  font-size: var(--t-base);
  color: var(--c-ink);
  margin-top: var(--s-4);
  margin-bottom: var(--s-1);
}

/* Los códigos de respaldo del segundo factor (#211). Se copian a mano de la
   pantalla a un papel, así que van en la tipografía monoespaciada y sueltos:
   una lista apretada es una lista que se copia mal. En dos columnas cuando hay
   sitio, porque diez códigos en fila única obligan a bajar la vista. */
.respaldo {
  list-style: none;
  margin: var(--s-4) 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: var(--s-2);
}

.respaldo__codigo {
  background: var(--c-surface-raised);
  border: 1px solid var(--c-border);
  border-radius: var(--r-sm);
  padding: var(--s-2) var(--s-3);
  text-align: center;
}

.respaldo__codigo code {
  font-family: var(--font-mono);
  font-size: var(--t-lg);
  /* Separadas: una `l` pegada a una `1` se copia mal, y aunque el alfabeto
     evita las parejas peores, el espaciado sigue ayudando. */
  letter-spacing: 0.08em;
  color: var(--c-ink);
}

/* La favorita de una foto (#47). Debajo de la imagen y del crédito, en la
   misma columna: es una acción sobre esa foto, no sobre la galería.

   Reserva su alto siempre —también sin sesión, donde solo hay recuento o
   nada— para que entrar y salir de la cuenta no mueva la rejilla. Un salto de
   maquetación es CLS, y el CLS es señal de posicionamiento (#95). */
.favorita {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  min-height: 2rem;
  margin-top: var(--s-1);
}

.favorita__boton {
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
  background: none;
  border: 1px solid var(--c-border);
  border-radius: var(--r-sm);
  padding: var(--s-1) var(--s-2);
  font-family: var(--font-ui);
  font-size: var(--t-sm);
  color: var(--c-ink-soft);
  cursor: pointer;
}

.favorita__boton:hover {
  border-color: var(--c-border-strong);
  color: var(--c-ink);
}

/* La marcada se distingue por el borde y el color, no solo por la estrella:
   una diferencia que solo existe en un carácter se pierde a tamaño pequeño y
   no la ve quien no distingue ★ de ☆ de un vistazo. El texto lo dice además. */
.favorita__boton--mia {
  border-color: var(--c-primary);
  color: var(--c-primary);
}

.favorita__cuenta {
  font-family: var(--font-ui);
  font-size: var(--t-sm);
  color: var(--c-ink-soft);
}

/* El QR del segundo factor (#214). El SVG llega sin tamaño propio —solo con
   `viewBox`—, así que el hueco lo decide aquí la maqueta y no un número de
   píxeles escrito en el servidor.

   **Fondo claro fijo, en los dos temas.** No es un descuido del modo oscuro: un
   código de barras necesita contraste oscuro-sobre-claro para que lo lea una
   cámara, y el trazo que dibuja `segno` es negro. Sin este fondo, en oscuro
   quedaba negro sobre `#12150F` y no se leía tuviera el tamaño que tuviera.

   El relleno es la **zona de silencio**: el borde claro alrededor no es
   decoración, es parte de lo que el lector busca para encontrar el código.

   `aspect-ratio` y no `height`: reserva su sitio antes de pintarse, que es la
   condición 2 del nivel de JavaScript (#95) y vale igual sin script. */
.qr {
  width: min(15rem, 100%);
  aspect-ratio: 1;
  background: #fff;
  padding: var(--s-3);
  border-radius: var(--r-sm);
  /* Con el fondo blanco fijo, el borde de siempre desaparecería contra el
     papel claro; este se ve en los dos temas sin tocar el contraste del QR. */
  border: 1px solid var(--c-border);
}

.qr svg {
  display: block;
  width: 100%;
  height: 100%;
}

/* Las dos listas de cuentas de un perfil (#91). Cada fila es un panel con los
   datos a la izquierda y su botón a la derecha; `.cluster` ya reparte, así que
   aquí solo hace falta que el botón no se pegue al texto cuando la fila es
   estrecha y que el nombre no empuje al botón fuera de la caja. */
.miembro {
  justify-content: space-between;
  align-items: center;
  gap: var(--s-3);
}

.miembro > div:first-child {
  /* Sin esto, un correo largo ensancha la fila en vez de partirse. */
  min-width: 0;
  overflow-wrap: anywhere;
}

/* Separación entre la lista de los que lo tienen y la de los que no: son dos
   cosas distintas y sin aire se leen como una sola con un rótulo por medio. */
.miembros > .stack + .stack {
  margin-top: var(--s-6);
}

/* Los mensajes de la discusión de una ficha (#76). */
.mensaje__cabecera {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-2);
  margin-bottom: var(--s-2);
}

/* Escondido y visto por quien modera: tiene que leerse como apartado sin
   volverse ilegible, porque el motivo para volver a mostrarlo está dentro.
   Opacidad y no `text-decoration: line-through`: un párrafo entero tachado no
   se lee, y aquí hay que poder leerlo para decidir. */
.mensaje--escondido {
  opacity: 0.6;
  border-left: 3px solid var(--c-border-strong);
}

/* El botón de una acción ya hecha —«la tengo», y lo que venga (#219)—. Se
   distingue por el borde y el color además de por el texto: una diferencia que
   solo existe en la palabra se pierde de un vistazo en una fila de botones. */
.btn--marcado {
  border-color: var(--c-primary);
  color: var(--c-primary);
}

.inventario__linea {
  justify-content: space-between;
  align-items: center;
  gap: var(--s-3);
}

/* El sobre que se acabó (#257). Apagado y no oculto: sigue estando para no
   perder de dónde vino ni cuándo caducaba, y tiene que leerse como lo que es
   —memoria— sin competir con lo que sí se tiene. El dato no lo lleva el color:
   al lado va el distintivo «agotado», que es el que se lee y el que se oye. */
.inventario__linea--agotada { color: var(--c-ink-soft); }

/* La celda que agrupa las líneas de una semilla en el inventario (#222). Va
   arriba y no centrada verticalmente: con tres sobres, un nombre centrado
   queda a la altura del segundo y parece que solo describe a ese. */
.inventario__semilla {
  vertical-align: top;
  white-space: normal;
}

.inventario__semilla .card__meta {
  display: block;
  margin-top: var(--s-1);
}

/* Un grupo de secciones dentro de la barra (#223). Reaprovecha `.menu` del
   menú de la cuenta; lo que cambia es el disparador, que aquí tiene que
   parecerse a los enlaces de al lado y no a un botón. */
.menu--barra > summary {
  cursor: pointer;
  list-style: none;
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
}

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

/* El triángulo, con el mismo dibujo que el del menú de la cuenta. */
.menu--barra > summary::after {
  content: "";
  width: 0.35em;
  height: 0.35em;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: translateY(-0.15em) rotate(45deg);
  transition: transform var(--e-fast);
}

.menu--barra[open] > summary::after {
  transform: translateY(0.1em) rotate(-135deg);
}

/* El panel de la cuenta se ancla a la derecha porque vive en el extremo; este
   está a la izquierda de la barra y anclarlo igual lo sacaría de la pantalla. */
.menu__panel--izquierda { right: auto; left: 0; }
