/* =============================================================================
   MyPlants · layout y componentes
   La paleta, la escala y el motion viven en css/tokens.css y aquí solo se
   componen: en este fichero no hay ni un color, ni un tamaño de fuente, ni un
   espaciado escrito literal. Solo var(--…).

   El orden de capas se declara una vez y decide toda la especificidad. Con esto
   bien puesto no hace falta subir selectores ni usar !important en ningún sitio.
   ============================================================================= */

@layer reset, base, layout, componentes, diagramas, movimiento, utilidades;


/* ══ reset ═══════════════════════════════════════════════════════════════════ */

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

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

  body, h1, h2, h3, h4, h5, h6, p, figure, dl, dd, ol, ul {
    margin: var(--space-0);
    padding: var(--space-0);
  }

  ul, ol { list-style: none; }

  img { display: block; max-width: 100%; height: auto; }

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

  button { background: none; border: var(--space-0); cursor: pointer; }

  /* El marcador por defecto del <details> no encaja con nada de esta página. Se
     quita el triángulo, pero NO el comportamiento: sigue siendo <summary>, así
     que Enter, Espacio, el foco y el anuncio de estado son los del navegador. */
  summary { list-style: none; cursor: pointer; display: block; }
  summary::-webkit-details-marker { display: none; }
  summary::marker { content: ""; }

  /* Foco visible SIEMPRE, y diseñado. El anillo es doble porque ningún color
     contrasta a la vez contra el campo oscuro y contra el papel claro. */
  :focus-visible {
    outline: var(--borde-foco);
    outline-offset: var(--foco-separacion);
    box-shadow: var(--anillo-foco);
    border-radius: var(--radio-s);
  }

  /* Dentro del papel el anillo se invierte: el ácido sobre papel da 1,18. */
  .cuaderno :focus-visible {
    outline: var(--borde-foco-papel);
    box-shadow: var(--anillo-foco-papel);
  }
}


/* ══ base ════════════════════════════════════════════════════════════════════ */

@layer base {
  body {
    background-color: var(--fondo-pagina);
    /* El halo cálido detrás del contenido: es fondo de PÁGINA, no un filtro
       sobre ninguna foto. Fijo, para que no viaje con el scroll y se lea como
       la luz de la habitación y no como una mancha que persigue. */
    background-image: var(--halo-campo);
    background-repeat: no-repeat;
    background-attachment: fixed;

    color: var(--texto-principal);
    font-family: var(--fuente-cuerpo);
    font-size: var(--texto-m);
    line-height: var(--interlinea-base);
    min-height: 100vh;
  }

  h1, h2, h3, h4, h5, h6 {
    line-height: var(--interlinea-titulo);
    font-weight: var(--peso-fuerte);
  }

  em { font-style: italic; }

  /* Los enlaces son ácido en todo el campo oscuro… */
  a { color: var(--texto-enlace); }

  /* …y azul de bolígrafo dentro del papel, porque el ácido sobre el papel da
     1,18:1 y es el par prohibido del sistema. Está aquí y no en el componente
     para que la excepción viva al lado de la regla que excepciona. */
  .cuaderno a { color: var(--texto-enlace-personal); }

  ::selection {
    background: var(--color-acido);
    color: var(--color-campo);
  }
}


/* ══ layout ══════════════════════════════════════════════════════════════════ */

@layer layout {
  /* Una banda es una tira a lo ancho de la ventana; el marco es la columna de
     contenido dentro de ella. Separarlos es lo que permite que un fondo llegue a
     sangre mientras el texto respeta la medida. */
  .marco {
    width: 100%;
    max-width: var(--ancho-pagina);
    margin-inline: auto;
    padding-inline: var(--canal-pagina);
  }

  .cabecera__fila {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-4);
    padding-block: var(--space-6) var(--space-5);
    border-block-end: var(--trazo-fino) solid var(--color-separador);
  }

  .parte { padding-block: var(--aire-banda) var(--space-6); }

  .filtros { padding-block: var(--space-2) var(--space-5); }

  .contenido { padding-block: var(--space-2) var(--space-9); }

  .grupo { padding-block-end: var(--aire-banda); }

  /* LA REJILLA. `auto-fill` con `min()` y no columnas fijas: el `min()` es
     obligatorio, porque a 320 px el canal lateral deja menos hueco que el mínimo
     de columna y sin él la rejilla fuerza scroll horizontal.

     Las dos bandas tienen densidades distintas y eso es información: las que
     piden mirada van más grandes —foto mayor y sitio para el titular del
     diagnóstico—, y las sanas van más pequeñas. Siguen siendo fotos de verdad;
     simplemente no compiten con lo urgente. */
  .rejilla {
    display: grid;
    gap: var(--hueco-rejilla);
    align-items: stretch;
  }

  .rejilla--mirada {
    grid-template-columns: repeat(auto-fill, minmax(min(var(--ancho-minimo-mirada), 100%), 1fr));
  }

  .rejilla--bien {
    grid-template-columns: repeat(auto-fill, minmax(min(var(--ancho-minimo), 100%), 1fr));
  }

  .rejilla__celda { display: grid; min-width: 0; }

  /* AL ABRIR UNA FICHA SE ENSANCHA ESA, Y SOLO ESA.
     La celda abierta ocupa la fila entera —el expediente necesita las dos
     columnas semánticas— y **el resto de la rejilla se queda como está**.

     Esto retira la decisión anterior de `ux-lead` («mientras hay una ficha
     desplegada, la rejilla colapsa a una columna»), que era coherente cuando las
     tarjetas eran pegatinas de texto y deja de serlo con fotos: colapsarlo todo
     convertía siete fotos en siete bandas a ancho completo y el ojo perdía la
     rejilla que estaba leyendo. Lo pidió Carlos mirándolo: *«debería abrirse la
     clickada y el resto mantenerse en el grid de columnas que tienen»*.

     Lo que SÍ se conserva de aquella decisión es la exclusividad, y no cuesta
     CSS: las fichas son `<details name="planta">`, o sea un acordeón exclusivo
     NATIVO. Abrir una cierra la otra sin una línea de JS. */
  .rejilla__celda:has(.despegue[open]) {
    grid-column: 1 / -1;
    z-index: var(--z-ficha);
  }

  /* Al colapsar, la ficha que acabas de tocar cambia de sitio: el margen evita
     que la cabecera pegajosa del móvil la tape cuando el JS la trae a la vista. */
  .planta__cara { scroll-margin-block-start: var(--space-5); }

  .pie__fila {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
    justify-content: space-between;
    align-items: baseline;
    padding-block: var(--space-6) var(--space-8);
    border-block-start: var(--trazo-fino) solid var(--color-separador);
  }
}


/* ══ componentes ═════════════════════════════════════════════════════════════ */

@layer componentes {

  /* ── voces tipográficas ─────────────────────────────────────────────────── */

  /* El display: condensada, caja alta, apretada. Es la voz de la etiquetadora. */
  .display {
    font-family: var(--fuente-etiqueta);
    font-weight: var(--peso-fuerte);
    line-height: var(--interlinea-apretada);
    letter-spacing: var(--tracking-display);
    text-transform: uppercase;
    text-wrap: balance;
  }

  /* El rótulo de campo: mono en versalita ancha. Solo para DATO, nunca para voz. */
  .rotulo {
    font-family: var(--fuente-dato);
    font-size: var(--texto-2xs);
    font-weight: var(--peso-medio);
    letter-spacing: var(--tracking-micro);
    text-transform: uppercase;
    color: var(--texto-meta);
  }

  /* Las cifras en la voz mecánica del proyecto — la de báscula de vivero. Es la
     regla general del sistema: ml, °C, cm, €, EAN, fechas. */
  .cifra {
    font-family: var(--fuente-dato);
    font-weight: var(--peso-medio);
    font-variant-numeric: tabular-nums;
    color: inherit;
  }

  /* ── cabecera ───────────────────────────────────────────────────────────── */

  /* El h1 se pinta como antetítulo y SIGUE SIENDO EL h1. La tesis del día manda
     visualmente, pero el nivel semántico no se toca: el tamaño es jerarquía
     visual y el nivel es estructura del documento, y cambiar el segundo para
     conseguir el primero rompe el esquema de encabezados. */
  .cabecera__titulo {
    font-family: var(--fuente-etiqueta);
    font-size: var(--texto-m);
    letter-spacing: var(--tracking-micro);
    line-height: var(--interlinea-titulo);
    text-transform: uppercase;
    color: var(--texto-principal);
  }

  .cabecera__punto { color: var(--color-acido); }

  .cabecera__bajada {
    font-family: var(--fuente-dato);
    font-size: var(--texto-xs);
    letter-spacing: var(--tracking-dato);
    color: var(--texto-meta);
  }

  /* ── el parte del día ───────────────────────────────────────────────────── */

  .parte__marco {
    display: grid;
    gap: var(--space-5);
    justify-items: start;
  }

  .parte__cabeza {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-2) var(--space-4);
  }

  .parte__titulo,
  .parte__fecha {
    font-family: var(--fuente-dato);
    font-size: var(--texto-2xs);
    font-weight: var(--peso-medio);
    letter-spacing: var(--tracking-micro);
    text-transform: uppercase;
    color: var(--texto-meta);
  }

  .parte__cuerpo { display: grid; gap: var(--space-3); }

  /* EL VEREDICTO DEL DÍA, y es lo más grande de la web a propósito. `--texto-
     veredicto` va en `vw` y no en `cqi`: la franja no tiene ancestro con
     `container-type`, así que con `cqi` el valor caería al viewport pequeño sin
     dar error. */
  .parte__veredicto {
    font-family: var(--fuente-etiqueta);
    font-weight: var(--peso-fuerte);
    font-size: var(--texto-veredicto);
    line-height: var(--interlinea-apretada);
    letter-spacing: var(--tracking-display);
    text-transform: uppercase;
    color: var(--texto-principal);
    text-wrap: balance;
    /* 22ch: lo justo para que «3 DE 7 PIDEN MIRADA» quepa en un renglón a 1280 y
       para que «LAS 7 ESTÁN BIEN» —el día bueno— se componga igual de ancho. Si
       rompe en dos líneas, rompe por donde `balance` decida, no por el tope. */
    max-width: 22ch;

    /* La cifra del veredicto es lo único de la portada que va en acento: «3 DE 7»
       en ácido y «PIDEN MIRADA» en tinta. El acento entra por el dato, no por el
       adorno. */
    & .cifra {
      font-family: inherit;
      font-weight: inherit;
      color: var(--color-acido);
    }
  }

  .parte__resumen {
    font-family: var(--fuente-dato);
    font-size: var(--texto-xs);
    letter-spacing: var(--tracking-dato);
    text-transform: uppercase;
    color: var(--texto-meta);
  }

  /* ── las entradas del parte ─────────────────────────────────────────────── */

  .parte__chips {
    display: flex;
    flex-direction: column;
    align-items: start;
    gap: var(--space-2);
    width: 100%;
  }

  .chip__enlace {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-2) var(--space-3);
    background: var(--fondo-ficha);
    border: var(--trazo-fino) solid var(--color-borde-control);
    border-radius: var(--radio-chip);
    padding: var(--space-2) var(--space-4);
    min-block-size: var(--diana-min);
    text-decoration: none;
    color: var(--texto-principal);
    box-shadow: var(--sombra-1), var(--filo-luz);
    transition:
      background-color var(--dur-corta) var(--ease-estandar),
      border-color var(--dur-corta) var(--ease-estandar),
      transform var(--dur-corta) var(--ease-estandar);

    &:hover {
      background: var(--fondo-hundido);
      border-color: var(--color-acido);
      transform: translateY(-2px);
    }
  }

  .chip__nombre {
    font-family: var(--fuente-etiqueta);
    text-transform: uppercase;
    letter-spacing: var(--tracking-caja-alta);
  }

  .chip__que {
    color: var(--texto-secundario);
    font-size: var(--texto-s);
  }

  /* ── la marca de severidad: color Y palabra, nunca una sin la otra ──────── */

  .marca {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-family: var(--fuente-dato);
    font-size: var(--texto-2xs);
    font-weight: var(--peso-medio);
    letter-spacing: var(--tracking-micro);
    text-transform: uppercase;
    white-space: nowrap;

    &[data-severidad="critica"] { color: var(--texto-alerta); }
    &[data-severidad="atencion"] { color: var(--texto-aviso); }
    &[data-severidad="sana"] { color: var(--texto-sana); }
  }

  /* El punto es un PSEUDO-ELEMENTO y no un `<span>`, y el motivo lo levantó
     `tests/estructura.js`: siete nodos pequeños con fondo y sin texto son
     indistinguibles, para un auditor, de un punto de color que codifica un
     estado — que es justo lo que este proyecto no hace. Y tenía razón aunque
     aquí la palabra vaya al lado: **la forma de que un nodo no parezca eso no es
     explicárselo al test, es que deje de ser un nodo.** El punto es redundancia
     de la palabra; si se borrara, la palabra seguiría diciendo lo mismo. */
  .marca::before {
    content: "";
    inline-size: var(--space-2);
    block-size: var(--space-2);
    border-radius: var(--radio-punto);
    background: currentColor;
    flex: none;
  }

  /* ── las tareas de la franja ────────────────────────────────────────────── */

  /* Tres columnas —rótulo · planta · lo que le toca— compartidas por todas las
     filas vía `subgrid`. Sin esto cada fila calcula sus propias columnas, los
     nombres no se alinean y la lista se lee como un párrafo picado en vez de
     como un parte.

     `minmax(0, …)` en las TRES: la tercera ya lo tenía, y las dos primeras iban
     en `auto`, que es contenido mínimo sin tope. Con un título largo —y los de
     `botanist` llegan a 85 caracteres— la fila empujaba la rejilla y sacaba 68 px
     de scroll horizontal a 1280. Medido el 12 de agosto: el desborde no lo
     provocaba el título, lo provocaba que la columna no tuviera permiso para
     encogerse. Un título que envuelve se lee; uno truncado miente, así que la
     salida es dejarle envolver, no recortarlo. */
  .parte__tareas {
    display: grid;
    grid-template-columns: minmax(0, auto) minmax(0, auto) minmax(0, 1fr);
    gap: var(--space-3);
    width: 100%;
  }

  .tarea-hoy {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: subgrid;
    align-items: baseline;
    font-size: var(--texto-s);
    padding-block-end: var(--space-3);
    border-block-end: var(--trazo-fino) solid var(--color-separador);
  }

  .tarea-hoy:last-child { border-block-end: 0; padding-block-end: 0; }

  /* En pantalla estrecha el `subgrid` se retira y la fila se apila. La alineación
     en columnas es lo que hace que la lista se lea como un parte y no como un
     párrafo picado, pero eso solo vale mientras las tres columnas caben: a 320 px
     el «debería haberse hecho hace 58 días» empujaba la tercera columna y sacaba
     47 px de scroll horizontal. Cero desborde no se negocia, y la alineación sí. */
  @media (max-width: 40rem) {
    .parte__tareas { grid-template-columns: minmax(0, 1fr); }

    .tarea-hoy {
      display: flex;
      flex-wrap: wrap;
      align-items: baseline;
      gap: var(--space-1) var(--space-2);
    }

    .tarea-hoy__cosas { flex-basis: 100%; }
  }

  /* El nombre de la planta es el ancla de lectura: se busca primero. */
  .tarea-hoy__planta {
    font-family: var(--fuente-etiqueta);
    font-size: var(--texto-2xs);
    letter-spacing: var(--tracking-caja-alta);
    text-transform: uppercase;
    color: var(--texto-principal);
    text-decoration: none;
    /* Diana sin tocar el cuerpo tipográfico, que es una decisión de diseño y no
       de ergonomía. */
    min-block-size: var(--diana-min);
    display: inline-flex;
    align-items: center;
    min-width: 0;

    &:hover { color: var(--color-acido); }
  }

  .tarea-hoy__faena {
    font-family: var(--fuente-etiqueta);
    font-size: var(--texto-2xs);
    letter-spacing: var(--tracking-caja-alta);
    text-transform: uppercase;
    color: var(--texto-principal);
  }

  /* Las cosas que le tocan a esta planta, en el mismo renglón. Se separan con un
     punto medio entre hermanas: si un día una planta tiene tres tareas, la línea
     sigue leyéndose como una línea y no como tres. */
  .tarea-hoy__cosas {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-1) var(--space-2);
    min-width: 0;
  }

  .tarea-hoy__cosa {
    display: inline flow-root;
    min-width: 0;

    & + &::before {
      content: "·";
      color: var(--texto-meta);
      margin-inline-end: var(--space-2);
    }
  }

  .tarea-hoy__titulo {
    text-wrap: pretty;
    color: var(--texto-secundario);
  }

  .tarea-hoy__cuando {
    font-family: var(--fuente-dato);
    font-size: var(--texto-xs);
    color: var(--texto-meta);
    margin-inline-start: var(--space-2);
  }

  /* `VA TARDE` en aviso, NUNCA en la severidad crítica: son dos ejes
     independientes. Una planta que necesita trasplante no está en el mismo apuro
     que una que se secó entera, y si las dos gritan igual, ninguna grita. */
  .tarea-hoy__rotulo,
  .tarea__rotulo {
    font-family: var(--fuente-dato);
    font-size: var(--texto-3xs);
    font-weight: var(--peso-medio);
    letter-spacing: var(--tracking-micro);
    text-transform: uppercase;
    border: var(--trazo-fino) solid currentColor;
    border-radius: var(--radio-chip);
    padding: var(--space-1) var(--space-2);
    color: var(--texto-aviso);
    white-space: nowrap;
    justify-self: start;
  }

  /* Vacío ocupa su columna del `subgrid` y no se ve: sin marco, sin relleno y
     sin borde. Es lo que mantiene alineados los nombres de todas las filas. */
  .tarea-hoy__rotulo:empty {
    border: 0;
    padding: 0;
  }

  /* Las de fecha cumplida no compiten con la vencida: mismo sitio, sin el ocre
     del aviso. Es la misma economía que deja a las sanas sin insignia. */
  .tarea-hoy[data-tono="hoy"] .tarea-hoy__rotulo,
  .tarea[data-tono="hoy"] .tarea__rotulo {
    color: var(--texto-meta);
  }

  /* ── buscador ───────────────────────────────────────────────────────────── */

  .buscador {
    display: grid;
    gap: var(--space-2);
    width: 100%;
    max-width: var(--medida-corta);
  }

  .buscador__label {
    font-family: var(--fuente-dato);
    font-size: var(--texto-2xs);
    letter-spacing: var(--tracking-micro);
    text-transform: uppercase;
    color: var(--texto-meta);
  }

  .buscador__input {
    background: var(--fondo-hundido);
    color: var(--texto-principal);
    border: var(--trazo-fino) solid var(--color-borde-control);
    border-radius: var(--radio-s);
    padding: var(--space-3) var(--space-4);
    font-size: var(--texto-m);
    width: 100%;

    &::placeholder { color: var(--texto-meta); }
    &:hover { border-color: var(--color-acido); }
  }

  /* ── filtros ────────────────────────────────────────────────────────────── */

  .filtros__form {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3) var(--space-5);
  }

  .filtros__facetas {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3) var(--space-5);
  }

  .faceta {
    border: 0;
    padding: var(--space-0);
    margin: var(--space-0);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
  }

  .faceta__legend {
    float: left;   /* un <legend> no participa en el flex del <fieldset> */
    width: 100%;
    font-family: var(--fuente-dato);
    font-size: var(--texto-3xs);
    letter-spacing: var(--tracking-micro);
    text-transform: uppercase;
    color: var(--texto-meta);
    padding: var(--space-0);
    margin-block-end: var(--space-2);
  }

  .faceta__opciones {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
  }

  /* Casilla real debajo de un chip: se conserva la semántica de checkbox (el
     lector la anuncia como tal, Espacio la marca) y se gana el aspecto de chip. */
  .opcion { display: contents; }

  .opcion__input {
    position: absolute;
    width: var(--trazo-fino);
    height: var(--trazo-fino);
    opacity: 0;

    /* El foco del teclado se dibuja en la etiqueta, que es lo que se ve. */
    &:focus-visible + .opcion__label {
      outline: var(--borde-foco);
      outline-offset: var(--foco-separacion);
      box-shadow: var(--anillo-foco);
    }

    &:checked + .opcion__label {
      background: var(--color-acido);
      color: var(--color-campo);
      border-color: var(--color-acido);
    }
  }

  .opcion__label {
    display: inline-flex;
    align-items: baseline;
    gap: var(--space-2);
    background: var(--fondo-ficha);
    color: var(--texto-principal);
    border: var(--trazo-fino) solid var(--color-borde-control);
    border-radius: var(--radio-chip);
    padding: var(--space-2) var(--space-4);
    min-block-size: var(--diana-min);
    font-size: var(--texto-s);
    cursor: pointer;
    transition: background-color var(--dur-corta) var(--ease-estandar),
                border-color var(--dur-corta) var(--ease-estandar);

    &:hover { border-color: var(--color-acido); }
  }

  .opcion__cuenta {
    font-family: var(--fuente-dato);
    font-size: var(--texto-2xs);
    opacity: 0.75;
  }

  .boton--limpiar {
    color: var(--texto-principal);
    border: var(--trazo-fino) solid var(--color-borde-control);
    border-radius: var(--radio-chip);
    padding: var(--space-2) var(--space-4);
    min-block-size: var(--diana-min);
    font-size: var(--texto-s);

    &:hover { border-color: var(--color-acido); }
  }

  /* ── avisos y recuento ──────────────────────────────────────────────────── */

  .resultado {
    font-family: var(--fuente-dato);
    font-size: var(--texto-xs);
    letter-spacing: var(--tracking-dato);
    color: var(--texto-meta);
    margin-block-end: var(--space-5);
  }

  .aviso {
    background: var(--fondo-ficha);
    color: var(--texto-principal);
    border-inline-start: var(--filete-severidad) solid var(--color-alerta);
    border-radius: var(--radio-panel);
    padding: var(--relleno-panel);
    font-size: var(--texto-s);
    max-width: var(--medida);
    margin-block-end: var(--space-5);
  }

  /* ── los rótulos de banda ───────────────────────────────────────────────── */

  .grupo__titulo {
    display: flex;
    align-items: baseline;
    gap: var(--space-4);
    font-family: var(--fuente-etiqueta);
    font-size: var(--texto-banda);
    line-height: var(--interlinea-apretada);
    letter-spacing: var(--tracking-display);
    text-transform: uppercase;
    color: var(--texto-principal);
    margin-block-end: var(--space-5);
    padding-block-end: var(--space-3);
    border-block-end: var(--trazo-fino) solid var(--color-separador);
  }

  /* El canto de la banda urgente se marca, y no solo por color: el rótulo dice
     «piden mirada» con todas sus letras. */
  #grupo-mirada .grupo__titulo { border-block-end-color: var(--color-borde-control); }

  .grupo__cuenta {
    margin-inline-start: auto;
    font-family: var(--fuente-dato);
    font-size: var(--texto-2xs);
    font-weight: var(--peso-medio);
    letter-spacing: var(--tracking-micro);
    text-transform: uppercase;
    color: var(--texto-meta);
    white-space: nowrap;
  }

  /* ══ LA TARJETA DE PLANTA ═══════════════════════════════════════════════════
     La foto arriba y los datos debajo, sobre superficie elevada. La foto es la
     vuelta grande de esta piel: el sujeto estaba ausente de su propia portada, y
     las siete fotos traen el color real de sus plantas sin añadir un solo token
     de paleta. El color entra por donde tiene procedencia —el sujeto— en vez de
     por la paleta. */

  .planta {
    /* Container query: la misma tarjeta sirve en la rejilla de tres, en la de
       cuatro y abierta a ancho completo. No pregunta cuánto mide la ventana. */
    container-type: inline-size;
    container-name: planta;

    display: flex;
    min-width: 0;
    background: var(--fondo-ficha);
    border: var(--trazo-fino) solid var(--color-separador);
    border-radius: var(--radio-tarjeta);
    box-shadow: var(--sombra-1), var(--filo-luz);
    /* `clip` Y NO `hidden`, y la diferencia es toda la columna sticky.
       `overflow: hidden` crea un CONTENEDOR DE SCROLL, y `position: sticky` se
       posiciona respecto al contenedor de scroll más cercano, así que la columna
       de acción no tendría recorrido y se iría con la página. Medido scrolleando
       0/400/900 px: `hidden` → 16 · −384 · −884 (no pega) · `clip` → 16 · 16 · 16.
       `clip` recorta igual y no crea contenedor de scroll. El síntoma estaba a
       400 líneas de la causa: nadie mira `overflow` cuando el bug parece de
       `position: sticky`. */
    overflow: clip;
    transition:
      box-shadow var(--dur-media) var(--ease-salida),
      border-color var(--dur-media) var(--ease-salida),
      transform var(--dur-media) var(--ease-salida);

    &:hover {
      box-shadow: var(--sombra-3), var(--filo-luz);
      transform: translateY(-3px);
    }

    &:has(.despegue[open]) {
      box-shadow: var(--sombra-3), var(--filo-luz);
      border-color: var(--color-borde-control);
      transform: none;
    }
  }

  .despegue { display: flex; flex-direction: column; flex: 1; min-width: 0; }

  /* El canto superior: la severidad se lee ya en la rejilla, antes de abrir nada.
     Nunca va sola — la tarjeta lleva además punto y palabra — y **el grosor la
     codifica igual que el tono**, así que la escala sobrevive a la escala de
     grises y al daltonismo. Ver el porqué medido en `tokens.css`. */
  .planta[data-severidad="critica"] { border-block-start: var(--filete-critica) solid var(--color-alerta); }
  .planta[data-severidad="atencion"] { border-block-start: var(--filete-atencion) solid var(--color-aviso); }
  .planta[data-severidad="sana"] { border-block-start: var(--filete-sana) solid var(--color-sana); }

  /* La cara entera es el `<summary>`: la tarjeta es la diana. */
  .planta__cara {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-width: 0;
  }

  /* LA FOTO NO LLEVA TEXTO ENCIMA Y NO LLEVA NINGÚN FILTRO. Son fotos de
     diagnóstico: se recortan y se agrandan; no se tocan. Ni duotono, ni grado,
     ni viñeta — en la única planta que se muere, embellecer la foto corrompe la
     prueba. Y el texto sobre fotografía es contraste no medible, así que todo el
     texto vive debajo, sobre superficie sólida. */
  .planta__foto {
    position: relative;
    overflow: hidden;
    background: var(--fondo-hundido);
    flex: none;
    aspect-ratio: var(--aspecto-tarjeta);
  }

  .rejilla--mirada .planta__foto { aspect-ratio: var(--aspecto-tarjeta-mirada); }

  .planta__img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center 45%;
    transition: transform var(--dur-larga) var(--ease-salida);
  }

  .planta:hover .planta__img { transform: scale(1.03); }

  .planta__cuerpo {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    padding: var(--relleno-ficha);
    flex: 1;
    min-width: 0;
  }

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

  .planta__familia {
    font-family: var(--fuente-dato);
    font-size: var(--texto-2xs);
    letter-spacing: var(--tracking-dato);
    color: var(--texto-meta);
  }

  /* El nombre a sangre de caja: dimensionado contra el CONTENEDOR y no contra la
     ventana, con `hyphens: auto` y `lang="es"` como red para que un nombre largo
     no rompa la rejilla mañana. */
  .planta__nombre {
    font-family: var(--fuente-etiqueta);
    font-size: var(--texto-nombre);
    line-height: var(--interlinea-apretada);
    letter-spacing: var(--tracking-display);
    text-transform: uppercase;
    text-wrap: balance;
    hyphens: auto;
  }

  .planta__binomio {
    font-style: italic;
    font-size: var(--texto-s);
    color: var(--texto-secundario);

    /* Aquí la especie SÍ es un dato desconocido, así que aquí sí manda el gris
       de «sin dato». Es el mismo renglón que en las otras dice qué es. */
    &[data-sin-identificar="si"] {
      font-family: var(--fuente-dato);
      font-style: normal;
      font-size: var(--texto-xs);
      color: var(--texto-sin-dato);

      & em { font-style: normal; }
    }
  }

  .planta__titular {
    color: var(--texto-secundario);
    text-wrap: pretty;
    max-width: 46ch;
  }

  .rejilla--bien .planta__titular { font-size: var(--texto-s); }

  /* Las pastillas de dato: cifra en mono + rótulo en versalita. */
  .planta__datos {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-block-start: var(--space-1);
  }

  .pastilla {
    display: inline-flex;
    align-items: baseline;
    gap: var(--space-2);
    background: var(--fondo-hundido);
    border: var(--trazo-fino) solid var(--color-separador);
    border-radius: var(--radio-s);
    padding: var(--space-1) var(--space-2);
  }

  .pastilla__valor {
    font-family: var(--fuente-dato);
    font-weight: var(--peso-medio);
    font-size: var(--texto-2xs);
    color: var(--texto-dato);
    white-space: nowrap;
  }

  .pastilla__clave {
    font-family: var(--fuente-dato);
    font-size: var(--texto-3xs);
    letter-spacing: var(--tracking-micro);
    text-transform: uppercase;
    color: var(--texto-meta);
  }

  /* El tirador. Va al fondo de la tarjeta con `margin-top: auto`, así que todas
     las de una fila lo tienen a la misma altura aunque su texto mida distinto. */
  .planta__abrir {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    margin-block-start: auto;
    padding-block-start: var(--space-3);
    align-self: start;
    font-family: var(--fuente-dato);
    font-size: var(--texto-2xs);
    font-weight: var(--peso-medio);
    letter-spacing: var(--tracking-micro);
    text-transform: uppercase;
    color: var(--color-acido);
  }

  /* La flecha es geometría y no un glifo: un carácter «▾» se lee en voz alta en
     algunos lectores y aquí no dice nada que el texto no diga. */
  .planta__abrir-flecha {
    inline-size: var(--space-2);
    block-size: var(--space-2);
    flex: none;
    border-inline-end: var(--trazo-grueso) solid currentColor;
    border-block-end: var(--trazo-grueso) solid currentColor;
    rotate: 45deg;
    translate: 0 -15%;
    transition: rotate var(--dur-media) var(--ease-salida);
  }

  .despegue[open] .planta__abrir-flecha { rotate: 225deg; }

  .despegue[open] .planta__abrir-texto::after { content: " (abierta)"; }

  /* ── el expediente ──────────────────────────────────────────────────────── */

  .despegada {
    border-block-start: var(--trazo-fino) solid var(--color-separador);
    padding: var(--relleno-ficha);
  }

  /* Por debajo del ancho de dos columnas se apila y ACCIÓN queda arriba, que es
     lo que ya hace el orden del DOM sin ayuda de nadie. */
  .expediente {
    display: grid;
    gap: var(--space-6);
  }

  .expediente__accion,
  .expediente__base {
    display: grid;
    gap: var(--space-6);
    align-content: start;
    /* `min-width: 0` contra el `auto` implícito de los hijos de grid: sin esto un
       diagrama o un código largo empujan la columna y desbordan a 320 px. */
    min-width: 0;
  }

  /* Los dos rótulos de columna son el encabezado del expediente, y tienen que
     leerse como rótulos de archivador. */
  .expediente__rotulo {
    font-family: var(--fuente-etiqueta);
    font-size: var(--texto-xs);
    letter-spacing: var(--tracking-caja-alta);
    text-transform: uppercase;
    color: var(--color-acido);
    padding-block-end: var(--space-2);
    border-block-end: var(--trazo-fino) solid var(--color-separador);
  }

  /* Los títulos de sección del expediente */
  .cuidados__titulo,
  .calendario__titulo,
  .indice__rotulo,
  .estado__titulo,
  .mas-datos__titulo,
  .prueba__rotulo,
  .identificacion__rotulo,
  .cuaderno__rotulo,
  .estado__sub {
    font-family: var(--fuente-dato);
    font-size: var(--texto-2xs);
    font-weight: var(--peso-medio);
    letter-spacing: var(--tracking-micro);
    text-transform: uppercase;
    color: var(--texto-meta);
  }

  /* ── capa 1 · estado ────────────────────────────────────────────────────── */

  .estado {
    display: grid;
    gap: var(--space-3);
    border-radius: var(--radio-panel);
    padding: var(--relleno-panel);
    background: var(--fondo-hundido);
    box-shadow: var(--filo-luz);

    /* El BLOQUE va en relleno teñido con tinta normal encima. La inversión es
       para el DISTINTIVO, nunca para un contenedor de texto: sobre un color
       sólido el único token legible sería uno, y eso obliga a enumerar cada
       descendiente a mano — el día que alguien añada un párrafo, desaparece.
       Ya pasó una vez, en la única planta que se está muriendo. */
    &[data-severidad="critica"] {
      background: var(--fondo-alerta);
      border-inline-start: var(--filete-severidad) solid var(--color-alerta);
    }
    &[data-severidad="atencion"] {
      background: var(--fondo-aviso);
      border-inline-start: var(--filete-severidad) solid var(--color-aviso);
    }
    &[data-severidad="sana"] {
      background: var(--fondo-sana);
      border-inline-start: var(--filete-severidad) solid var(--color-sana);
    }
  }

  .estado__cintillo {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-2) var(--space-4);
  }

  .estado__fecha {
    font-family: var(--fuente-dato);
    font-size: var(--texto-xs);
    color: var(--texto-meta);
    letter-spacing: var(--tracking-dato);
  }

  /* El titular del diagnóstico: lo primero que se lee de la columna de consulta.
     Sigue siendo un `<p>` por grande que se pinte. */
  .estado__cabecera {
    font-family: var(--fuente-etiqueta);
    font-size: var(--texto-xl);
    line-height: var(--interlinea-titulo);
    letter-spacing: var(--tracking-display);
    color: var(--texto-principal);
    text-wrap: balance;
    max-width: var(--medida);
  }

  .estado__bloque { display: grid; gap: var(--space-3); }

  .estado__lista {
    display: grid;
    gap: var(--space-3);
    color: var(--texto-principal);
    max-width: var(--medida);
  }

  .estado__item {
    font-size: var(--texto-s);
    padding-inline-start: var(--space-4);
    border-inline-start: var(--trazo-fino) solid var(--color-borde-control);
    text-wrap: pretty;
    color: var(--texto-secundario);
  }

  /* Los límites del diagnóstico se leen distinto del diagnóstico: no son
     hallazgos, son la frontera de lo que la foto permite afirmar. Marco
     discontinuo, que es la gramática de «hasta aquí sabemos». */
  .estado__bloque--limites .estado__lista {
    border: var(--trazo-fino) dashed var(--color-borde-control);
    border-radius: var(--radio-panel);
    padding: var(--relleno-panel);
  }

  .estado__bloque--limites .estado__item {
    border-inline-start: 0;
    padding-inline-start: var(--space-4);
    position: relative;

    &::before {
      content: "?";
      position: absolute;
      inset-inline-start: 0;
      font-family: var(--fuente-dato);
      font-weight: var(--peso-medio);
      color: var(--texto-meta);
    }
  }

  /* Las causas: cada una en su caja, con su CLASE escrita. El rótulo no lo
     adivina el contenedor — lo dice el `tipo` del dato. */
  .causa {
    display: grid;
    gap: var(--space-1);
    padding: var(--space-3) var(--space-4);
    background: var(--fondo-ficha);
    border: var(--trazo-fino) solid var(--color-separador);
    border-inline-start-width: var(--trazo-fino);
    border-radius: var(--radio-panel);
    color: var(--texto-principal);

    /* Una aclaración no es un hallazgo: se dibuja con el marco roto, que es la
       misma gramática que «lo que la foto no dice». */
    &[data-tipo="aclaracion"] {
      background: transparent;
      border-style: dashed;
    }
  }

  .causa__clase {
    font-family: var(--fuente-dato);
    font-size: var(--texto-3xs);
    letter-spacing: var(--tracking-micro);
    text-transform: uppercase;
    color: var(--texto-meta);
  }

  .causa__resumen {
    font-weight: var(--peso-fuerte);
    font-size: var(--texto-l);
    line-height: var(--interlinea-titulo);
    color: var(--texto-principal);
    text-wrap: pretty;
  }

  .causa__detalle {
    font-size: var(--texto-s);
    color: var(--texto-secundario);
    margin-block-start: var(--space-1);
    text-wrap: pretty;
  }

  /* El patrón no es una afirmación más: es una instrucción para mirar la planta,
     y es lo que hace usable un listado de causas delante del tiesto. Sin color —
     es método, no alarma. */
  .causa__patron {
    display: grid;
    gap: var(--space-1);
    margin-block-start: var(--space-2);
    padding-inline-start: var(--space-3);
    border-inline-start: var(--trazo-grueso) solid var(--color-acido-hondo);
    font-size: var(--texto-s);
    color: var(--texto-secundario);
    text-wrap: pretty;
  }

  .causa__patron-rotulo {
    font-family: var(--fuente-dato);
    font-size: var(--texto-3xs);
    letter-spacing: var(--tracking-micro);
    text-transform: uppercase;
    color: var(--texto-meta);
  }

  /* ── el tratamiento ─────────────────────────────────────────────────────── */

  .estado__tratamiento { display: grid; gap: var(--space-3); }

  .estado__pasos {
    display: grid;
    gap: var(--space-4);
    counter-reset: paso;
    max-width: var(--medida);
  }

  .paso {
    counter-increment: paso;
    display: grid;
    gap: var(--space-1);
    padding-inline-start: var(--space-7);
    position: relative;
    font-size: var(--texto-s);

    &::before {
      content: counter(paso);
      position: absolute;
      inset-inline-start: 0;
      inset-block-start: 0;
      inline-size: var(--space-6);
      block-size: var(--space-6);
      display: grid;
      place-items: center;
      border-radius: var(--radio-punto);
      background: var(--color-acido);
      color: var(--color-campo);
      font-family: var(--fuente-dato);
      font-weight: var(--peso-medio);
      font-size: var(--texto-xs);
    }
  }

  .paso__plazo {
    font-family: var(--fuente-dato);
    font-size: var(--texto-3xs);
    text-transform: uppercase;
    letter-spacing: var(--tracking-micro);
    color: var(--texto-meta);
  }

  .paso__accion { color: var(--texto-principal); text-wrap: pretty; }

  .paso__senal {
    font-size: var(--texto-xs);
    color: var(--texto-secundario);
    padding-inline-start: var(--space-3);
    border-inline-start: var(--trazo-grueso) solid var(--color-acido-hondo);
    margin-block-start: var(--space-1);

    &::before { content: "Va bien si: "; font-family: var(--fuente-dato); text-transform: uppercase; font-size: var(--texto-3xs); letter-spacing: var(--tracking-micro); }
  }

  .estado__revisar {
    font-size: var(--texto-s);
    color: var(--texto-secundario);
    max-width: var(--medida);
    border-inline-start: var(--trazo-grueso) solid var(--color-borde-control);
    padding-inline-start: var(--space-3);
    text-wrap: pretty;
  }

  .estado__revisar-rotulo {
    font-family: var(--fuente-dato);
    text-transform: uppercase;
    letter-spacing: var(--tracking-micro);
    font-size: var(--texto-3xs);
    color: var(--texto-meta);

    &::after { content: " "; }
  }

  /* ── foto del diagnóstico ───────────────────────────────────────────────── */

  .foto { display: grid; }

  .foto__img {
    aspect-ratio: var(--aspecto-foto);
    object-fit: cover;
    width: 100%;
    height: auto;
    border-start-start-radius: var(--radio-panel);
    border-start-end-radius: var(--radio-panel);
    border: var(--trazo-fino) solid var(--color-separador);
    border-block-end: 0;
  }

  /* LA BANDA DE LA FOTO. Pegada al borde inferior de la imagen y compartiendo su
     ancho, en superficie sólida propia. Nunca sobre los píxeles: texto sobre
     fotografía es contraste NO MEDIBLE, y sobre la foto nocturna del helecho
     sería ilegible. Con fondo propio se mide como cualquier otro texto. */
  .foto__pie {
    display: grid;
    gap: var(--space-1);
    background: var(--fondo-hundido);
    border: var(--trazo-fino) solid var(--color-separador);
    border-block-start: 0;
    border-end-start-radius: var(--radio-panel);
    border-end-end-radius: var(--radio-panel);
    padding: var(--space-3);
    font-family: var(--fuente-dato);
    font-size: var(--texto-xs);
    color: var(--texto-meta);
  }

  /* La limitación no es un pie de foto más: es lo que la foto NO permite
     afirmar, así que va en cuerpo de texto y no en mono de metadato. */
  .foto__limite {
    font-family: var(--fuente-cuerpo);
    font-size: var(--texto-s);
    color: var(--texto-secundario);
    text-wrap: pretty;
  }

  /* ── la prueba: la pegatina reconstruida y la fotografiada ──────────────── */

  .prueba {
    display: grid;
    gap: var(--space-3);
    justify-items: start;
  }

  /* LA SIGNATURE: la etiqueta térmica de Viveros Projardín, reconstruida en HTML
     y CSS. Sin una sola imagen — el código de barras es un gradiente repetido.
     Es el único sitio de la web, junto al cuaderno, donde el fondo se aclara, y
     aquí tiene un motivo distinto: una pegatina de vivero es blanca. */
  .pegatina {
    display: grid;
    gap: var(--space-2);
    inline-size: 100%;
    max-inline-size: var(--medida-corta);
    background: var(--color-papel);
    background-image: var(--papel-degradado);
    color: var(--color-tinta-papel);
    border-radius: var(--radio-s);
    padding: var(--relleno-panel);
    box-shadow: var(--sombra-2);
  }

  .pegatina__vivero {
    display: grid;
    gap: var(--space-1);
    font-family: var(--fuente-dato);
    font-size: var(--texto-3xs);
    letter-spacing: var(--tracking-micro);
    line-height: var(--interlinea-titulo);
    text-transform: uppercase;
    border-block-end: var(--trazo-fino) solid var(--color-papel-linea);
    padding-block-end: var(--space-2);
  }

  .pegatina__vivero-nombre { font-weight: var(--peso-medio); }

  .pegatina__nombre {
    font-family: var(--fuente-etiqueta);
    font-size: var(--texto-xl);
    line-height: var(--interlinea-apretada);
    letter-spacing: var(--tracking-display);
    text-transform: uppercase;
  }

  .pegatina__maceta,
  .pegatina__fito {
    font-family: var(--fuente-dato);
    font-size: var(--texto-3xs);
    letter-spacing: var(--tracking-micro);
    text-transform: uppercase;
  }

  .pegatina__linea {
    display: flex;
    align-items: end;
    justify-content: space-between;
    gap: var(--space-4);
  }

  .pegatina__codigo { display: grid; gap: var(--space-1); }

  /* El EAN: repeating-linear-gradient, cero imágenes y cero peso. Un EAN real
     mide lo que mide: estirado deja de leerse como código de barras y pasa a ser
     una cebra decorativa, así que tiene ancho propio. */
  .pegatina__barras {
    display: block;
    inline-size: 9rem;
    block-size: var(--space-7);
    background-image: var(--barras-codigo);
    background-repeat: repeat-x;
  }

  .pegatina__digitos,
  .pegatina__precio {
    font-family: var(--fuente-dato);
    font-size: var(--texto-2xs);
    letter-spacing: var(--tracking-dato);
  }

  .pegatina__precio {
    font-weight: var(--peso-fuerte);
    font-size: var(--texto-precio);
    line-height: var(--interlinea-apretada);
    white-space: nowrap;
  }

  /* Cada segmento de un código de trazabilidad es indivisible: partido por la
     mitad deja de ser un código. El salto ocurre ENTRE segmentos. */
  .segmento { white-space: nowrap; }

  /* Sin duotono, sin recorte artístico, sin sombra: una prueba retocada no
     prueba nada. Solo se acota el tamaño, que no es estilizar. */
  .prueba__img {
    width: var(--ancho-prueba);
    aspect-ratio: var(--aspecto-foto);
    object-fit: cover;
    height: auto;
    border: var(--trazo-fino) solid var(--color-separador);
    border-radius: var(--radio-s);
  }

  /* La frase de «sin etiqueta» NO va en gris de sin-dato: en estas dos plantas la
     ausencia de pegatina es antigüedad, y eso es contenido, no un hueco. */
  .prueba__sin {
    font-size: var(--texto-s);
    color: var(--texto-secundario);
    max-width: var(--medida-corta);
    text-wrap: pretty;
  }

  .prueba__nota,
  .prueba__aclimatacion {
    font-family: var(--fuente-dato);
    font-size: var(--texto-xs);
    color: var(--texto-meta);
    max-width: var(--medida-corta);
  }

  /* ── el rasgo de la hoja ────────────────────────────────────────────────── */

  .identificacion { display: grid; gap: var(--space-3); }

  .identificacion__cuerpo {
    display: flex;
    align-items: start;
    gap: var(--space-4);
  }

  .identificacion__texto {
    font-size: var(--texto-s);
    color: var(--texto-secundario);
    max-width: var(--medida);
    text-wrap: pretty;
  }

  /* La silueta de hoja: la forma es la clave de identificación botánica, así que
     aquí es información. NO se anima: algo que se mueve no ancla nada. */
  .silueta {
    width: var(--silueta-tam);
    height: var(--silueta-tam);
    display: block;
    flex: none;
    fill: none;
    stroke: currentColor;
    stroke-width: var(--trazo);
    stroke-linecap: round;
    stroke-linejoin: round;
    color: var(--texto-secundario);
  }

  .silueta--grande { width: var(--silueta-tam-l); height: var(--silueta-tam-l); }

  .silueta__nervio,
  .silueta__pinna { stroke-width: var(--trazo-fino); opacity: 0.75; }

  .silueta__raquis { stroke-width: var(--trazo); }

  /* Aquí la trama SÍ corresponde: la especie es un dato desconocido de verdad, y
     va dentro del contorno para marcar dónde está la duda exactamente. */
  .silueta__trama { stroke: none; }
  .silueta__trama-linea { stroke: var(--color-sin-dato-trama); stroke-width: var(--trazo-fino); }

  /* ── capa 2 · campos con diagrama ───────────────────────────────────────── */

  .cuidados { display: grid; gap: var(--space-3); }

  .campos-diagrama { display: grid; gap: var(--space-4); }

  .campo {
    display: grid;
    gap: var(--space-2);
    background: var(--fondo-hundido);
    border: var(--trazo-fino) solid var(--color-separador);
    border-radius: var(--radio-panel);
    padding: var(--relleno-panel);
    box-shadow: var(--filo-luz);
    min-width: 0;
  }

  /* Los iconos de campo: un trazo, sin relleno, y siempre junto a su palabra. */
  .icono {
    width: var(--icono-tam);
    height: var(--icono-tam);
    flex: 0 0 auto;
    fill: none;
    stroke: currentColor;
    stroke-width: var(--trazo);
    stroke-linecap: round;
    stroke-linejoin: round;
    vertical-align: text-bottom;
  }

  /* El de dificultad codifica un valor con puntos rellenos, no con trazo. */
  .icono--dificultad .icono__punto { fill: none; stroke: currentColor; }
  .icono--dificultad .icono__punto--lleno { fill: currentColor; }

  .campo__clave,
  .dato__clave {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-family: var(--fuente-dato);
    font-size: var(--texto-2xs);
    font-weight: var(--peso-medio);
    letter-spacing: var(--tracking-micro);
    text-transform: uppercase;
    color: var(--texto-meta);
  }

  .campo__resumen {
    font-size: var(--texto-s);
    color: var(--texto-principal);
    text-wrap: pretty;
  }

  /* WCAG 2.2 · 2.5.8: área pulsable de 24×24 como mínimo, y aquí van a 28.
     Crece el PADDING, no el `font-size`: la microtipografía de la cita es
     pequeña a propósito, y el tamaño de diana es una decisión de ergonomía. Las
     dos cosas son independientes. */
  .campo__mas-tirador,
  .dato__mas-tirador,
  .causa__mas-tirador,
  .fuentes-resto__tirador,
  .fuente {
    min-block-size: var(--diana-min);
    display: inline-flex;
    align-items: center;
    padding-block: var(--space-1);
  }

  /* Separación vertical entre dianas contiguas, que es la otra mitad del
     criterio: sin aire, dos enlaces de 28 px siguen siendo fáciles de fallar. */
  .campo__fuente,
  .dato__fuente { display: block; margin-block-start: var(--espacio-diana); }

  .campo__mas-tirador,
  .dato__mas-tirador,
  .causa__mas-tirador,
  .fuentes-resto__tirador {
    font-family: var(--fuente-dato);
    font-size: var(--texto-2xs);
    font-weight: var(--peso-medio);
    letter-spacing: var(--tracking-micro);
    text-transform: uppercase;
    color: var(--color-acido);
    gap: var(--space-2);
    padding-inline: var(--space-2);
    margin-inline-start: calc(var(--space-2) * -1);
    border-radius: var(--radio-s);
    transition: background-color var(--dur-corta) var(--ease-estandar);

    &:hover { background: var(--fondo-acento); }

    &::after { content: "+"; font-weight: var(--peso-normal); }
  }

  details[open] > .campo__mas-tirador::after,
  details[open] > .dato__mas-tirador::after,
  details[open] > .causa__mas-tirador::after,
  details[open] > .fuentes-resto__tirador::after { content: "–"; }

  .campo__detalle,
  .dato__detalle {
    white-space: pre-line;   /* una plaga por línea en el detalle */
    font-size: var(--texto-s);
    color: var(--texto-secundario);
    max-width: var(--medida);
    margin-block-start: var(--space-2);
    padding: var(--relleno-panel);
    background: var(--fondo-ficha);
    border-radius: var(--radio-panel);
    text-wrap: pretty;
  }

  /* ── capa 2 · el resto de datos ─────────────────────────────────────────── */

  .mas-datos { display: grid; gap: var(--space-3); }

  .mas-datos__lista { display: grid; gap: var(--space-4); }

  .dato {
    display: grid;
    gap: var(--space-2);
    padding-block-end: var(--space-4);
    border-block-end: var(--trazo-fino) solid var(--color-separador);
    min-width: 0;
  }

  .dato__valor { font-size: var(--texto-s); color: var(--texto-principal); }

  /* Toxicidad: tres estados que se distinguen por BORDE e ICONO además de por
     color, así que en escala de grises siguen siendo tres cosas distintas.

     Sin el color de la alarma, y es deliberado: en esta casa no hay mascotas, así
     que la toxicidad es informativa y no urgente. El color de severidad queda
     EXCLUSIVAMENTE para la crítica. En este sistema el color significa «haz algo
     hoy», y una planta tóxica en una casa sin gato no pide nada hoy. */
  .dato--toxicidad {
    background: var(--fondo-hundido);
    border: var(--trazo-fino) solid var(--color-separador);
    border-radius: var(--radio-panel);
    padding: var(--relleno-panel);

    & .dato__texto::before {
      font-family: var(--fuente-dato);
      font-weight: var(--peso-medio);
    }
  }

  .dato[data-toxicidad="toxica"] {
    border-inline-start: var(--trazo-grueso) solid var(--color-borde-control);
    & .dato__texto::before { content: "▲ "; }
  }

  /* Discontinuo a propósito: el borde roto dice «esto está sin comprobar». */
  .dato[data-toxicidad="sin_datos"],
  .dato[data-toxicidad="sin_datos_aspca"],
  .dato[data-toxicidad="sin_identificar"] {
    border-inline-start: var(--trazo-grueso) dashed var(--color-sin-dato-trama);
    & .dato__texto { color: var(--texto-sin-dato); }
    & .dato__texto::before { content: "? "; }
  }

  .dato[data-toxicidad="segura"] .dato__texto::before { content: "· "; }

  /* La trampa del casi-homónimo va visible y entera. Sin recortar: si no cabe,
     crece la caja. */
  .aviso-homonimo {
    display: block;
    margin-block-start: var(--space-2);
    padding-inline-start: var(--space-3);
    border-inline-start: var(--trazo-fino) solid var(--color-sin-dato-trama);
    font-size: var(--texto-xs);
    color: var(--texto-secundario);
    text-wrap: pretty;
  }

  /* ── fuentes: contenido, no letra pequeña ───────────────────────────────── */

  .fuente {
    gap: var(--space-1);
    font-family: var(--fuente-dato);
    font-size: var(--texto-xs);
    color: var(--texto-enlace);
    text-decoration-thickness: var(--trazo-fino);
    text-underline-offset: var(--space-1);
  }

  .fuente--sin-url { color: var(--texto-meta); text-decoration: none; }

  /* El bloque del resto de fuentes son ~24 líneas por ficha: una rejilla de dos
     o tres columnas, no una columna de veinticuatro renglones.

     `grid-column: 1 / -1` no es cosmético: sin él el bloque cae en UNA celda de
     `.mas-datos__lista`, su rejilla interior colapsa a una columna y las 24 citas
     se apilan — 1.255 px de alto medidos, más de lo que costaba la ficha entera. */
  .dato--fuentes { grid-column: 1 / -1; }

  .fuentes-resto__lista {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
    gap: var(--espacio-diana) var(--space-4);
    margin-block-start: var(--space-3);
  }

  .dato--fuentes .dato__fuente {
    margin-block-start: 0;
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-1) var(--space-2);
  }

  /* El campo que la cita respalda. En mono y en versalitas: es una clave, no
     prosa, y así la columna se escanea por el campo. */
  .dato__fuente-campo {
    font-family: var(--fuente-dato);
    font-size: var(--texto-3xs);
    letter-spacing: var(--tracking-micro);
    text-transform: uppercase;
    color: var(--texto-meta);

    &::after { content: " ·"; }
  }

  /* ── el calendario de la ficha ──────────────────────────────────────────── */

  .calendario { display: grid; gap: var(--space-3); }

  .calendario__lista { display: grid; gap: var(--space-3); }

  .tarea {
    display: grid;
    gap: var(--space-1);
    justify-items: start;
    padding-inline-start: var(--space-3);
    border-inline-start: var(--trazo-grueso) solid var(--color-separador);
  }

  /* La única vencida lleva filete de aviso. Sin invertir nada: la inversión es
     solo para un distintivo, nunca para un contenedor de texto. */
  .tarea[data-tono="tarde"] {
    border-inline-start-color: var(--color-aviso);
  }

  .tarea__titulo { font-size: var(--texto-s); text-wrap: pretty; }

  .tarea__cuando {
    font-family: var(--fuente-dato);
    font-size: var(--texto-xs);
    color: var(--texto-meta);
  }

  /* «sin registrar» va en el gris de ausencia de dato, igual que un campo
     botánico sin verificar. El estándar de honestidad no cambia porque el dato
     sea de uso en vez de de fuente. */
  .tarea__cuando--sin-dato { color: var(--texto-sin-dato); }

  .tarea__nota {
    font-size: var(--texto-s);
    color: var(--texto-secundario);
    text-wrap: pretty;
  }

  /* El rótulo distingue una condición («solo si») de una comprobación
     («comprobar»), que no son lo mismo y ocupan la misma línea. */
  .tarea__nota-rotulo {
    font-family: var(--fuente-dato);
    font-size: var(--texto-3xs);
    letter-spacing: var(--tracking-micro);
    text-transform: uppercase;
    color: var(--texto-meta);

    &::after { content: ": "; }
  }

  /* ── el índice con recuento ─────────────────────────────────────────────── */

  .indice {
    display: grid;
    gap: var(--space-2);
    padding-block-start: var(--space-3);
    border-block-start: var(--trazo-fino) solid var(--color-separador);
  }

  .indice__lista { display: grid; gap: var(--espacio-diana); }

  /* La línea de puntos entre rótulo y número es de índice de expediente, y se
     hace con un `border-block-end` sobre un hueco flexible: cero pseudo-elemento
     con doscientos puntos escritos a mano. */
  .indice__enlace {
    display: flex;
    align-items: end;
    gap: var(--space-2);
    min-block-size: var(--diana-min);
    font-size: var(--texto-s);
    color: var(--texto-principal);
    text-decoration: none;

    &::after {
      content: "";
      flex: 1 1 auto;
      border-block-end: var(--trazo-fino) dotted var(--color-borde-control);
      margin-block-end: var(--space-1);
      order: 1;
    }

    &:hover { color: var(--color-acido); }
  }

  .indice__texto { text-wrap: pretty; }

  /* El número en mono y con peso: es un dato, y es la mitad del mensaje. */
  .indice__cuenta {
    order: 2;
    font-family: var(--fuente-dato);
    font-weight: var(--peso-medio);
    font-variant-numeric: tabular-nums;
    color: var(--color-acido);
  }

  /* ── capa 3 · la voz de la casa ─────────────────────────────────────────── */

  /* El ÚNICO sitio de la ficha donde el fondo se aclara para leer texto largo, y
     por eso se lee como material distinto del dato verificado. La separación usa
     cuatro señales a la vez —superficie, itálica, tinta azul y el nombre de quien
     habla—, no solo el color: ninguna información depende de distinguir tonos. */
  .cuaderno {
    background-color: var(--fondo-personal);
    background-image: var(--trama-cuaderno);
    border-inline-start: var(--filete-personal) solid var(--color-boli);
    border-radius: var(--radio-panel);
    padding: var(--space-5);
    display: grid;
    gap: var(--space-3);
    max-width: var(--medida);
    box-shadow: var(--sombra-2);
    color: var(--texto-personal);
  }

  .cuaderno__rotulo { color: var(--color-boli); }

  /* La itálica es la voz de la casa, un escalón por encima del cuerpo. */
  .cuaderno__historia,
  .cuaderno__notas {
    font-style: italic;
    font-size: var(--texto-voz);
    line-height: var(--interlinea-suelta);
    color: var(--texto-personal);
    text-wrap: pretty;
  }

  .cuaderno__firma {
    font-size: var(--texto-xs);
    font-style: italic;
    color: var(--color-tinta-papel);
    border-block-start: var(--trazo-fino) solid var(--color-papel-linea);
    padding-block-start: var(--space-3);
    opacity: 0.85;
  }

  /* ── pie ────────────────────────────────────────────────────────────────── */

  .pie__texto {
    font-size: var(--texto-s);
    color: var(--texto-secundario);
    max-width: var(--medida);
    text-wrap: pretty;
  }

  .pie__cuenta {
    font-family: var(--fuente-dato);
    font-size: var(--texto-xs);
    letter-spacing: var(--tracking-dato);
    color: var(--texto-meta);
  }

  /* ── la cronología ──────────────────────────────────────────────────────── */

  .cronologia {
    display: grid;
    gap: var(--space-3);
    background: var(--fondo-ficha);
    border: var(--trazo-fino) solid var(--color-separador);
    border-radius: var(--radio-panel);
    box-shadow: var(--sombra-1), var(--filo-luz);
    padding: var(--relleno-ficha);
  }

  .cronologia__titulo {
    font-family: var(--fuente-dato);
    font-size: var(--texto-2xs);
    font-weight: var(--peso-medio);
    letter-spacing: var(--tracking-micro);
    text-transform: uppercase;
    color: var(--texto-meta);
  }

  /* La nota no es letra pequeña de descargo: explica cómo se lee el eje, y sin
     ella el gráfico invita a leer las distancias como si fueran lineales. */
  .cronologia__nota {
    font-size: var(--texto-s);
    color: var(--texto-secundario);
    max-width: var(--medida);
    text-wrap: pretty;
  }

  /* LA REJILLA DEL GRÁFICO, y `subgrid` es lo que la hace posible sin JS. Las
     tres columnas se declaran UNA vez aquí; la lista, cada fila, cada botón y el
     eje las heredan. Sin subgrid cada fila calcula sus propias columnas y el eje
     de abajo rotula una posición que en la mitad de las filas no es esa. */
  .cronologia__grafico {
    display: grid;
    grid-template-columns: minmax(6rem, auto) minmax(0, 1fr) minmax(5rem, auto);
    column-gap: var(--space-3);
  }

  .cronologia__lista,
  .cronologia__fila,
  .cronologia__marca {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: subgrid;
  }

  /* Una fila por planta: así los cuatro marcadores del día 0 no se apilan unos
     encima de otros en el origen del eje. */
  .cronologia__marca {
    align-items: center;
    width: 100%;
    min-block-size: var(--diana-min);
    padding-block: var(--space-1);
    background: none;
    border: 0;
    text-align: start;
    color: inherit;
    cursor: pointer;
    font: inherit;

    &:hover .cronologia__nombre { color: var(--color-acido); }
  }

  .cronologia__nombre {
    font-family: var(--fuente-etiqueta);
    font-size: var(--texto-2xs);
    letter-spacing: var(--tracking-caja-alta);
    text-transform: uppercase;
  }

  /* La pista es el eje: una línea de borde de control, porque sin ella no se
     entiende el gráfico y 1.4.11 habla de «graphical objects required to
     understand the content», no solo de controles. */
  .cronologia__pista {
    position: relative;
    display: block;
    block-size: var(--diana-min);
    border-block-end: var(--trazo-fino) solid var(--color-borde-control);
  }

  /* El punto es un pseudo-elemento a propósito: es la posición del dato, no el
     dato — que va en texto al lado. Así no hay ningún nodo pequeño con fondo y
     sin texto que pueda leerse como un «punto de color» que codifica un estado. */
  .cronologia__pista[style]::before {
    content: "";
    position: absolute;
    inset-block-end: 0;
    /* --x lo calcula js/cronologia.js. El translate centra el punto en su
       coordenada en vez de colgarlo a su derecha, que en «10 años» se nota. */
    inset-inline-start: var(--x);
    translate: -50% 50%;
    inline-size: var(--space-3);
    block-size: var(--space-3);
    border-radius: var(--radio-punto);
    background: var(--color-acido);
  }

  /* El mínimo no es una medida: el poto lleva «más de 20 años» y eso es un suelo.
     Se dibuja abierto hacia la derecha, igual que el rango térmico sin máximo
     publicado — la misma gramática para el mismo tipo de incertidumbre. */
  .cronologia__fila[data-certeza="minimo"] .cronologia__pista::after {
    content: "";
    position: absolute;
    inset-inline-start: var(--x);
    inset-block-end: 0;
    inline-size: var(--space-5);
    border-block-start: var(--trazo-grueso) solid var(--color-acido);
    translate: 0 50%;
  }

  /* Sin dato de llegada: la planta NO se omite del censo —faltar en un censo de
     siete es información falsa— y su pista va en la trama de ausencia. */
  .cronologia__fila[data-certeza="sin"] .cronologia__pista {
    background: var(--trama-sin-dato);
    border-block-end-style: dashed;
  }

  .cronologia__valor {
    font-family: var(--fuente-dato);
    font-size: var(--texto-xs);
    color: var(--texto-meta);
    text-align: end;
  }

  .cronologia__fila[data-certeza="sin"] .cronologia__valor { color: var(--texto-sin-dato); }

  /* El eje ocupa exactamente la columna de las pistas: si no cae debajo de lo que
     rotula, no rotula nada. */
  .cronologia__eje { grid-column: 2; }

  /* La pista del eje es el contenedor de posicionamiento de los rótulos. Hace
     falta de verdad: sin `position: relative` aquí, los tics absolutos se
     resuelven contra el bloque contenedor inicial y aparecen pegados al borde de
     arriba de la PÁGINA, encima de la cabecera. */
  .cronologia__eje-pista {
    position: relative;
    display: block;
    min-block-size: var(--space-6);
  }

  .cronologia__tic {
    position: absolute;
    inset-block-start: 0;
    inset-inline-start: var(--x);
    translate: -50% 0;
    /* Lo que impide que el eje mienta: el rótulo, que es texto de verdad. */
    font-family: var(--fuente-dato);
    font-size: var(--texto-3xs);
    letter-spacing: var(--tracking-micro);
    text-transform: uppercase;
    color: var(--texto-meta);
    white-space: nowrap;
    padding-block-start: var(--space-2);

    /* …salvo el primero y el último, que se anclan por su extremo. Un rótulo
       centrado en el 0 % o en el 100 % se sale del eje por la mitad de su ancho
       —y «10 años» desbordaba la página a 1.280 px—. La marca en sí sigue en su
       coordenada exacta: la compensa el `::before`. */
    &:first-child { translate: 0 0; }
    &:last-child { translate: -100% 0; }

    &::before {
      content: "";
      position: absolute;
      inset-block-start: 0;
      inset-inline-start: 50%;
      inline-size: var(--trazo-fino);
      block-size: var(--space-2);
      background: var(--color-borde-control);
    }

    &:first-child::before { inset-inline-start: 0; }
    &:last-child::before { inset-inline-start: 100%; }
  }

  /* ── container queries: el componente reacciona a SU hueco ──────────────── */

  /* Container query y no media query: la tarjeta reacciona al hueco que le dan,
     no al ancho de la ventana. Así funciona igual en la rejilla de dos columnas,
     en la de cuatro y abierta a ancho completo, sin tocar nada. */
  @container planta (min-width: 34rem) {
    /* Abierta, la foto deja de ser ventana de mosaico y pasa a banda: a ancho
       completo un recorte 4:5 mediría más de mil píxeles de alto. */
    .despegue[open] .planta__foto {
      aspect-ratio: auto;
      block-size: var(--alto-foto-abierta);
    }
  }

  @container planta (min-width: 52rem) {
    /* ── EL EXPEDIENTE EN DOS COLUMNAS SEMÁNTICAS ─────────────────────────
       2fr / 3fr. Y el reparto no es estético: la columna de acción lleva los
       diagramas, que son gráficos con ancho propio, y la de consulta lleva la
       prosa, que necesita su medida de lectura entera. Bajó el hueco vacío del
       expediente del 53–65 % al 0–7 %. */
    .expediente {
      grid-template-columns: 2fr 3fr;
      gap: var(--space-5) var(--space-7);
      align-items: start;
    }

    /* La columna de acción se queda a la vista mientras se lee el porqué. El
       tope de alto y el `overflow` no son opcionales: sin ellos, en cuanto la
       columna es más alta que la pantalla, `sticky` deja de pegar y además se
       come el viewport entero. */
    .expediente__accion {
      position: sticky;
      inset-block-start: var(--space-4);
      max-block-size: calc(100dvh - var(--space-7));
      overflow: auto;
      /* Un panel con scroll propio necesita aire interior, o el texto queda
         pegado a su propia barra. */
      padding-inline-end: var(--space-3);
    }

    /* En la columna estrecha caben dos diagramas por fila. Apilados de uno en uno
       la columna se iba a mil y pico píxeles y desequilibraba el reparto. */
    .campos-diagrama { grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); }

    .mas-datos__lista { grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); }

    /* LAS DOS PRUEBAS, EN PARALELO. La foto del diagnóstico y la pegatina son las
       dos piezas documentales de esta columna, y apiladas sumaban 650 px de alto
       con media columna vacía al lado de cada una. */
    .expediente__base { grid-template-columns: 2fr 3fr; }

    .expediente__rotulo,
    .estado,
    .identificacion,
    .mas-datos,
    .cuaderno { grid-column: 1 / -1; }

    .foto { grid-column: 1; }
    .prueba { grid-column: 2; }
  }
}


/* ══ diagramas ═══════════════════════════════════════════════════════════════
   Los colores salen de tokens; la geometría (coordenadas, radios, cuerpo del
   texto en unidades de viewBox) vive en js/svg.js, que es donde se dibuja. */

@layer diagramas {
  .diagrama {
    width: 100%;
    height: auto;
    /* Tope deliberado: dentro de un viewBox el cuerpo del texto escala con el
       dibujo, así que un diagrama estirado a 1000 px rotula a 50 px. Acotando el
       ancho se acota el factor de escala, y el rótulo se queda donde debe. */
    max-width: var(--medida-corta);
    background: var(--fondo-ficha);
    border: var(--trazo-fino) solid var(--color-separador);
    border-radius: var(--radio-s);
  }

  .diagrama text {
    font-family: var(--fuente-dato);
    fill: var(--texto-meta);
  }

  /* Cuando no hay dato no se dibuja un eje bonito fingiendo precisión: se dice. */
  .diagrama-sin-dato {
    font-family: var(--fuente-dato);
    font-size: var(--texto-xs);
    color: var(--texto-sin-dato);
    background: var(--fondo-ficha);
    border: var(--trazo-fino) dashed var(--color-borde-control);
    border-radius: var(--radio-s);
    padding: var(--space-3);
  }

  /* ── 1 · el reloj de riego ──────────────────────────────────────────────── */

  .reloj__pista { fill: none; stroke: var(--escala-2); stroke-width: var(--trazo-grueso); stroke-linecap: round; }
  .reloj__marca { stroke: var(--color-borde-control); stroke-width: var(--trazo-fino); }
  .reloj__marca--mayor { stroke: var(--escala-4); stroke-width: var(--trazo); }
  .reloj__eje { fill: var(--escala-4); }

  .reloj__aguja { stroke-width: var(--trazo-grueso); stroke-linecap: round; }
  .reloj__aguja--verano { stroke: var(--color-acido); }
  .reloj__aguja--invierno { stroke: var(--escala-3); stroke-dasharray: 3 2; }

  .reloj__punta { stroke: none; }
  circle.reloj__aguja--verano { fill: var(--color-acido); }
  circle.reloj__aguja--invierno { fill: var(--escala-3); }

  .reloj__cifra { fill: var(--texto-dato); font-weight: var(--peso-fuerte); }
  .reloj__unidad, .reloj__rotulo, .reloj__ml { fill: var(--texto-meta); }

  /* ── 2 · lo que quiere y lo que tiene ──────────────────────────────────── */

  /* El :not() es imprescindible: una regla CSS de `fill` pisa el atributo de
     presentación del SVG, así que sin esto el hachurado no se vería nunca. */
  .escala__paso:not(.escala__paso--incierto) { fill: var(--escala-2); }
  .escala__paso--hueco { fill: var(--escala-3); }
  /* Exceso y déficit no son el mismo problema y no se pintan igual: al que le
     sobra sol hay que moverlo, al que le falta también, pero al revés. */
  .escala__paso--sobra { fill: var(--color-aviso); }
  .escala__paso--falta { fill: var(--escala-3); }
  .escala__marca--quiere { fill: var(--color-acido); }
  .escala__marca--tiene { fill: var(--color-aviso); }
  .escala__rotulo { fill: var(--texto-meta); }

  /* El hachurado es el portador NO cromático de «no hay dato»: tiene que verse. */
  .hachurado__fondo { fill: var(--color-sin-dato-relleno); }
  .hachurado__linea { stroke: var(--color-sin-dato-trama); stroke-width: var(--trazo); }

  /* El equivalente en texto del diagrama. No es un pie decorativo: el SVG va
     aria-hidden, así que esta frase es la única versión que llega a un lector. */
  .diagrama__equivalente {
    font-size: var(--texto-s);
    color: var(--texto-principal);
    margin-block-start: var(--space-2);
    text-wrap: pretty;
  }

  /* ── 3 · rango térmico ──────────────────────────────────────────────────── */

  .temp__eje { fill: var(--escala-1); }
  .temp__tolerado { fill: var(--escala-2); }
  .temp__optimo { fill: var(--escala-4); }
  .temp__letal { stroke: var(--color-alerta); stroke-width: var(--trazo-grueso); }
  .temp__letal-texto { fill: var(--color-alerta); }
  .temp__casa { fill: var(--color-acido); }
  .temp__abierto { fill: var(--escala-3); }
  .temp__casa-texto { fill: var(--texto-dato); }
  .temp__escala { fill: var(--texto-meta); }
}


/* ══ movimiento ══════════════════════════════════════════════════════════════
   Nada arranca solo y nada va en bucle. Cada animación tiene su versión
   reducida, y es OTRA VERSIÓN y no la misma más corta: una animación de 1 ms
   parpadea, que es peor que no animar. */

@layer movimiento {

  /* LA ENTRADA ESCALONADA de la rejilla. Un disparo, al cargar. El escalonado va
     sobre la TARJETA y no sobre la carga de la imagen: con `loading=lazy` el
     gesto se rompería distinto en cada visita. */
  .revela {
    animation: revelar var(--dur-larga) var(--ease-salida) both;
    animation-delay: calc(var(--i, 0) * var(--retardo-paso));
  }

  @keyframes revelar {
    from { opacity: 0; transform: translateY(18px) scale(0.99); }
    to { opacity: 1; transform: none; }
  }

  /* EL VEREDICTO se revela como se imprime una etiqueta térmica: una banda que
     resuelve DE ARRIBA ABAJO. No un cursor que teclea letra a letra —ése es el
     tic que delata lo generado y además no es como imprime una térmica—.
     Cinco condiciones, y si alguna se rompe el gesto se cae:
       · un disparo, al cargar; no lo repite ningún filtro
       · sobre texto que YA está en el DOM: es una máscara, no contenido tardío
       · cero desplazamiento de layout: `clip-path` no reserva ni libera espacio
       · con `reduce` la banda aparece entera
       · duración `--dur-media` */
  .parte__veredicto {
    animation: imprimir-termica var(--dur-media) var(--ease-salida) both;
  }

  @keyframes imprimir-termica {
    from { clip-path: inset(0 0 100% 0); }
    to { clip-path: inset(0 0 0 0); }
  }

  .parte__chips {
    animation: subir var(--dur-media) var(--ease-salida) var(--retardo-3) both;
  }

  @keyframes subir {
    from { opacity: 0; transform: translateY(12px); }
    to { opacity: 1; transform: none; }
  }

  /* El expediente se DESCUBRE por debajo: no entra desde fuera, se revela. Una
     máscara de arriba abajo, sin desplazamiento — misma gramática que el
     revelado del veredicto, y por el mismo motivo: cero salto de layout. */
  .despegue[open] > .despegada {
    animation: descubrir var(--dur-media) var(--ease-salida) both;
  }

  @keyframes descubrir {
    from { clip-path: inset(0 0 100% 0); }
    to { clip-path: inset(0 0 0 0); }
  }

  /* Los diagramas entran al abrir la ficha, una sola vez. */
  .despegue[open] .reloj__aguja,
  .despegue[open] .reloj__punta,
  .despegue[open] .escala__paso--hueco,
  .despegue[open] .temp__casa {
    animation: aparecer var(--dur-media) var(--ease-salida) both;
  }

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

  /* ── movimiento reducido: no se apaga, se cambia de versión ─────────────── */

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

    /* Escalonado → presencia directa. Las tarjetas están, sin retardo y sin
       desplazamiento. Y no es `animation: none` a secas: el estado final se fija
       explícitamente, porque `none` sobre un `@keyframes` que empieza en
       `opacity: 0` deja el elemento invisible y sin un error en consola. */
    .revela {
      animation: none;
      opacity: 1;
      transform: none;
    }

    /* El veredicto aparece ENTERO, sin banda: un `clip-path` de 1 ms parpadea. */
    .parte__veredicto { animation: none; clip-path: none; }

    .parte__chips { animation: none; opacity: 1; transform: none; }

    /* El expediente aparece entero, sin máscara. Del despegue se conserva solo la
       opacidad, que orienta sin desplazar y va por debajo del tope de latencia. */
    .despegue[open] > .despegada {
      animation: aparecer var(--dur-corta) linear both;
      clip-path: none;
      transform: none;
    }

    /* Las de un solo disparo de los diagramas pintan su estado final. */
    .despegue[open] .reloj__aguja,
    .despegue[open] .reloj__punta,
    .despegue[open] .escala__paso--hueco,
    .despegue[open] .temp__casa {
      animation: none;
      opacity: 1;
      transform: none;
    }

    /* El hover deja de mover la tarjeta y pasa a marcar el borde, que es una
       señal equivalente sin desplazamiento. El zoom de la foto se elimina.

       Y no basta con `transform: none` en el `:hover`: hay que sacar `transform`
       de la LISTA de propiedades que transicionan. `tests/movimiento.js` mira la
       `transition-property` declarada, y tiene razón en mirarla — una transición
       de `transform` declarada bajo `reduce` es una promesa de movimiento aunque
       hoy el valor de destino coincida con el de origen. Basta con que alguien
       añada un `translate` mañana. */
    .planta,
    .chip__enlace {
      transition-property: box-shadow, border-color, background-color;
    }

    .planta:hover,
    .chip__enlace:hover {
      transform: none;
    }

    .planta:hover { border-color: var(--color-acido); }

    .planta__img,
    .planta:hover .planta__img { transition: none; transform: none; }

    .planta__abrir-flecha { transition: none; }
  }
}


/* ══ utilidades ══════════════════════════════════════════════════════════════ */

@layer utilidades {
  /* Visible para un lector de pantalla, invisible en pantalla. */
  .oculto-visual:not(:focus):not(:active) {
    clip-path: inset(50%);
    height: var(--trazo-fino);
    width: var(--trazo-fino);
    overflow: hidden;
    position: absolute;
    white-space: nowrap;
  }

  /* Un dato que no se ha podido verificar se dice, no se esconde. */
  .sin-dato {
    font-family: var(--fuente-dato);
    font-size: var(--texto-xs);
    text-transform: uppercase;
    letter-spacing: var(--tracking-micro);
    color: var(--texto-sin-dato);
  }

  .salto-contenido {
    position: absolute;
    left: var(--space-4);
    top: var(--space-4);
    z-index: var(--z-salto);
    background: var(--color-acido);
    color: var(--color-campo);
    padding: var(--space-3) var(--space-5);
    border-radius: var(--radio-s);
    font-family: var(--fuente-etiqueta);
    text-transform: uppercase;
    letter-spacing: var(--tracking-caja-alta);
    text-decoration: none;

    &:not(:focus) {
      clip-path: inset(50%);
      height: var(--trazo-fino);
      width: var(--trazo-fino);
      overflow: hidden;
      white-space: nowrap;
    }
  }

  /* El `main` es enfocable por el skip link y no debe pintar anillo por ello:
     el foco programático no es foco de teclado. */
  .contenido:focus { outline: none; }
}


/* ══ decisiones de página (media queries, no de componente) ══════════════════ */

@media (max-width: 40rem) {
  /* En móvil el veredicto se queda a la vista: es el motivo de abrir esto. */
  .cabecera {
    position: sticky;
    top: var(--space-0);
    z-index: var(--z-franja);
    background: var(--fondo-pagina);
  }
}
