/* kelco-design 0.9.1 — components.css. Generado por scripts/build.js desde src/: no editar. */
@layer base, components;

@layer components {
  /* Botón: la acción principal es una píldora (kelco-button), una alternativa
     al lado de ella es la misma píldora con contorno (kelco-button-outline) y
     la secundaria tiene forma de enlace subrayado (kelco-button-secondary).
     Markup y modificadores: README, "Botón".

     Sirve igual en un <button> y en un <a>: el componente fija su tipografía
     entera y borra lo que el navegador le pone a un <button> (borde, fondo,
     fuente, cursor), así los dos se ven igual.

     El texto da 4,5:1 o más, en reposo y al pasar el mouse, sobre marfil o
     blanco, y con kelco-button-dark sobre tinta, ink-raised, petróleo o
     petrol-deep. Los casos más justos: bronze-dark sobre marfil (4,76:1)
     y bronze-light sobre petróleo (4,89:1). Deshabilitado queda por debajo,
     como permite WCAG para un control inactivo. El contorno de
     kelco-button-outline da 3:1 o más sobre las mismas superficies, en reposo
     y al pasar el mouse: el más justo, bronze-light al 70 % sobre petróleo
     (3,2:1); sobre marfil, bronce da 3,78:1 y bronze-dark 4,76:1.

     El anillo de foco es el de base.css; como la píldora fija su radio en una
     capa posterior, el anillo sigue su forma. */
  .kelco-button,
  .kelco-button-outline,
  .kelco-button-secondary {
    appearance: none;
    box-sizing: border-box;
    display: inline-block;
    font-family: var(--font-sans);
    font-size: 13px;
    font-weight: 500;
    line-height: 1.5;
    letter-spacing: normal;
    text-align: center;
    text-transform: none;
    white-space: nowrap;
    cursor: pointer;
  }

  /* La píldora, llena o con contorno: la misma caja, así una al lado de la
     otra miden lo mismo. El borde transparente de la llena no se ve, pero en
     colores forzados el navegador lo pinta y borra el fondo: la píldora
     conserva su contorno. El padding le descuenta ese pixel: por fuera mide
     9 × 18 px (15 × 30 px con kelco-button-lg). */
  .kelco-button,
  .kelco-button-outline {
    padding: 8px 17px;
    border: 1px solid transparent;
    border-radius: 999px;
    text-decoration: none;
  }

  .kelco-button {
    background-color: var(--color-ink);
    color: var(--color-ivory);
    transition: background-color 0.25s;
  }

  .kelco-button:hover:not(:disabled) {
    background-color: var(--color-petrol);
  }

  /* Con contorno: sin fondo, el texto en tinta y el borde en bronce, la
     madera de la marca. Al pasar el mouse el borde pasa al bronce de los
     controles, más oscuro. */
  .kelco-button-outline {
    border-color: var(--color-bronze);
    background-color: transparent;
    color: var(--color-ink);
    transition: border-color 0.25s;
  }

  .kelco-button-outline:hover:not(:disabled) {
    border-color: var(--color-bronze-dark);
  }

  /* El bronce para controles, subrayado en bronce tenue. Al pasar el mouse
     toma el color del texto. */
  .kelco-button-secondary {
    padding: 0;
    border: 0;
    background-color: transparent;
    color: var(--color-bronze-dark);
    text-decoration-line: underline;
    text-decoration-color: color-mix(in oklab, var(--color-bronze) 40%, transparent);
    text-underline-offset: 4px;
    transition: color 0.25s;
  }

  .kelco-button-secondary:hover:not(:disabled) {
    color: var(--color-ink);
  }

  /* Sólo un <button> se deshabilita: un <a> que no lleva a ningún lado no es
     un enlace. */
  .kelco-button:disabled,
  .kelco-button-outline:disabled,
  .kelco-button-secondary:disabled {
    cursor: not-allowed;
    opacity: 0.45;
  }

  /* Los modificadores van siempre junto a una de las variantes, en el mismo
     selector: solos no hacen nada, y así le ganan a la variante sin depender
     del orden. */

  /* kelco-button-lg: el tamaño de una acción de página (el CTA de un hero o de
     un 404). Sin él, el de una barra o una lista. */
  .kelco-button.kelco-button-lg,
  .kelco-button-outline.kelco-button-lg,
  .kelco-button-secondary.kelco-button-lg {
    font-size: 15px;
  }

  .kelco-button.kelco-button-lg,
  .kelco-button-outline.kelco-button-lg {
    padding: 14px 29px;
  }

  /* kelco-button-dark: sobre tinta o petróleo. La píldora se invierte (marfil,
     y bronze-light al pasar el mouse), la de contorno pasa a texto marfil y
     borde bronze-light (tenue en reposo, pleno al pasar el mouse: pleno sobre
     tinta daría 8:1, mucho más fuerte que el de fondo claro) y el secundario
     al bronce claro (y a marfil al pasar el mouse). */
  .kelco-button.kelco-button-dark {
    background-color: var(--color-ivory);
    color: var(--color-ink);
  }

  .kelco-button.kelco-button-dark:hover:not(:disabled) {
    background-color: var(--color-bronze-light);
  }

  .kelco-button-outline.kelco-button-dark {
    border-color: color-mix(in oklab, var(--color-bronze-light) 70%, transparent);
    color: var(--color-ivory);
  }

  .kelco-button-outline.kelco-button-dark:hover:not(:disabled) {
    border-color: var(--color-bronze-light);
  }

  .kelco-button-secondary.kelco-button-dark {
    color: var(--color-bronze-light);
    text-decoration-color: color-mix(in oklab, var(--color-bronze-light) 40%, transparent);
  }

  .kelco-button-secondary.kelco-button-dark:hover:not(:disabled) {
    color: var(--color-ivory);
  }

  /* Casilla (checkbox() y checkboxGroup() en kelco-design/html): el <input
     type="checkbox"> nativo dentro de su <label>, así el texto entero se puede
     tocar y el teclado y el foco son los del navegador.

     Todo sale del color del texto, que pone el sitio: el borde va al 70%, el
     relleno al 100%, y el tilde es un hueco en el relleno por el que se ve la
     superficie. Así sirve igual sobre fondo claro y oscuro. El borde da 3:1 o
     más contra la superficie con tinta o texto sobre marfil o blanco, y con
     marfil, text-on-dark o text-on-petrol sobre tinta o petróleo; con un gris
     tenue como color del texto no alcanza.

     Borde y relleno son bordes, no sombra ni fondo: en colores forzados el
     navegador los conserva con el color del sistema y borra los otros dos. */
  .kelco-checkbox {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    font-size: 15px;
    line-height: 1.5;
    cursor: pointer;
  }

  .kelco-checkbox > input {
    appearance: none;
    box-sizing: border-box;
    position: relative;
    flex: none;
    width: 18px;
    height: 18px;
    /* Centrada en la primera línea del texto. */
    margin: calc((1lh - 18px) / 2) 0 0;
    padding: 0;
    border: 1.5px solid color-mix(in oklab, currentColor 70%, transparent);
    border-radius: 4px;
    background-color: transparent;
    font: inherit;
    color: inherit;
    cursor: inherit;
    transition: border-color 0.25s;
  }

  .kelco-checkbox:hover > input:enabled {
    border-color: currentColor;
  }

  /* El relleno: un borde tan grueso que cubre la caja entera, borde incluido.
     Entra con una transición (opacidad 0,2 s, escala 0,3 s): una captura
     tomada apenas después de marcar varias las muestra a medio camino, más
     claras cuanto más recientes. En reposo son todas iguales. */
  .kelco-checkbox > input::before {
    content: "";
    box-sizing: border-box;
    position: absolute;
    inset: -1.5px;
    border: 9px solid currentColor;
    border-radius: inherit;
    /* El cuadro menos el tilde (evenodd). */
    clip-path: polygon(evenodd, 0 0, 100% 0, 100% 100%, 0 100%, 0 0, 30.2% 45.8%, 42% 57.5%, 70.8% 28.8%, 79.2% 37.2%, 42% 74.5%, 21.8% 54.2%, 30.2% 45.8%, 0 0);
    opacity: 0;
    transform: scale(0.6);
    transition:
      opacity 0.2s,
      transform 0.3s var(--ease-entrance);
  }

  .kelco-checkbox > input:checked::before,
  .kelco-checkbox > input:indeterminate::before {
    opacity: 1;
    transform: none;
  }

  /* Indeterminada (sólo por script, input.indeterminate): el cuadro menos una
     raya. */
  .kelco-checkbox > input:indeterminate::before {
    clip-path: polygon(evenodd, 0 0, 100% 0, 100% 100%, 0 100%, 0 0, 26% 44%, 74% 44%, 74% 56%, 26% 56%, 26% 44%, 0 0);
  }

  .kelco-checkbox:has(> input:disabled) {
    cursor: not-allowed;
    opacity: 0.45;
  }

  /* Grupo con título: un <fieldset> sin la caja del navegador, la leyenda en
     la serif de las etiquetas. */
  .kelco-checkbox-group {
    display: grid;
    gap: 10px;
    min-inline-size: 0;
    margin: 0;
    padding: 0;
    border: 0;
  }

  .kelco-checkbox-group > legend {
    margin-bottom: 12px;
    padding: 0;
    font-family: var(--font-serif);
    font-size: var(--text-label-sm);
    font-weight: 500;
    line-height: 1.5;
  }

  /* Campo para copiar: un campo relleno, sin borde, con un valor (una URL) y,
     adentro a la derecha, un botón redondo de ícono que lo copia. Sólo el
     estilo: copiar al portapapeles, poner data-state en el campo y escribir el
     mensaje en el status es del sitio. Markup, estados y el script del sitio:
     README, "Campo para copiar".

     Al copiar (data-state="copied"), las dos hojas del ícono se pliegan en un
     check, un disco del color del texto llena el botón desde el centro y suelta
     un anillo de bronce, y el campo se tiñe de bronce. Al sacar el atributo,
     todo vuelve con transiciones.

     Sin demoras (transition-delay ni una segunda duración en el shorthand): con
     prefers-reduced-motion, base.css acorta las duraciones pero no las demoras,
     y una demora dejaría el cambio a medias durante ese tiempo. Lo que tiene
     que pasar "de golpe, un poco después" va con step-end, que con duraciones
     acortadas pasa enseguida. Las animaciones (kelco-pop, kelco-ring) terminan
     en el estilo del elemento: con menos movimiento queda el estado final, sin
     el apretón ni el anillo.

     Los bordes del campo y del botón son transparentes: en colores forzados el
     navegador los pinta y el campo y el botón conservan su contorno. Ahí el
     disco (un fondo de gradiente) y el anillo (una sombra) no se ven; el ícono
     y el check son bordes, y los pinta el navegador. */
  .kelco-copy-field {
    box-sizing: border-box;
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: start;
    column-gap: 8px;
    padding: 3px 3px 3px 15px;
    border: 1px solid transparent;
    border-radius: var(--radius-card);
    background-color: var(--color-border);
    font-family: var(--font-sans);
    font-size: 13px;
    font-weight: 400;
    line-height: 1.5;
    letter-spacing: normal;
    text-align: start;
    text-transform: none;
    color: var(--color-ink);
    transition: background-color 0.45s var(--ease-entrance);
  }

  /* El valor: un <code>, <output> o <span>; se ven igual, porque el
     componente le fija la letra (un <code> trae monoespaciada del navegador).
     El padding centra su primera línea con el botón de 32 px: un valor de
     varias líneas crece hacia abajo y el botón queda arriba.

     Cómo corta un valor largo: overflow-wrap: anywhere. Corta primero donde la
     línea ya admite un corte (un espacio, un guion; en Chrome 156, también
     después de "?") y sólo si un tramo no entra en la línea lo parte entre dos
     letras: las palabras de un texto común quedan enteras. word-break:
     break-all, en cambio, parte entre dos letras aunque haya un corte natural
     cerca, también en un texto común. Después de "/", ",", "=" o "&" el
     navegador no corta: para que una URL corte ahí, el sitio pone un <wbr>
     después de cada uno (README).

     Se puede seleccionar aunque un contenedor del sitio lo impida. */
  .kelco-copy-field-value {
    margin: 0;
    padding: calc((32px - 1lh) / 2) 0;
    font: inherit;
    color: var(--color-text);
    white-space: normal;
    word-break: normal;
    overflow-wrap: anywhere;
    -webkit-user-select: text;
    user-select: text;
  }

  /* El botón. Vacío (el markup del README) es un círculo de 32 px con el
     ícono; con texto adentro (el markup hasta la 0.7) es una píldora de la
     misma altura con su texto, sin ícono, así una página que todavía no se
     actualizó sigue mostrando "Copiar". Vacío es sin nada adentro, tampoco
     espacios: Chrome (156) los cuenta como contenido para :empty.

     El disco es un fondo radial del color del texto, de tamaño 0 en reposo:
     al copiar crece desde el centro y cubre primero al ícono. Como sale de
     currentColor, con kelco-copy-field-dark es marfil. Fuera de la selección:
     arrastrar sobre el valor no se lleva el texto del botón. El anillo de foco
     es el de base.css y sigue el radio del botón. */
  .kelco-copy-field-button {
    appearance: none;
    box-sizing: border-box;
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 32px;
    height: 32px;
    margin: 0;
    padding: 0 12px;
    border: 1px solid transparent;
    border-radius: 999px;
    background-color: transparent;
    background-image: radial-gradient(circle closest-side, currentColor calc(100% - 0.5px), transparent);
    background-origin: border-box;
    background-position: center;
    background-repeat: no-repeat;
    background-size: 0% 0%;
    font: inherit;
    font-weight: 500;
    color: inherit;
    white-space: nowrap;
    cursor: pointer;
    -webkit-user-select: none;
    user-select: none;
    transition:
      background-color 0.25s,
      background-size 0.45s var(--ease-entrance);
  }

  .kelco-copy-field-button:empty {
    width: 32px;
    padding: 0;
  }

  .kelco-copy-field-button:hover:not(:disabled) {
    background-color: color-mix(in oklab, currentColor 8%, transparent);
  }

  .kelco-copy-field-button:disabled {
    cursor: not-allowed;
    opacity: 0.45;
  }

  /* El ícono son dos hojas dibujadas con bordes: la de atrás sólo con su borde
     de arriba y el de la izquierda; la de adelante, entera. Al copiar, la de
     atrás se mete debajo de la de adelante y se apaga, y la de adelante pierde
     dos bordes, se angosta y gira: lo que queda es el check. Su color cambia
     de golpe (step-end) a los 50 ms, cuando el disco mide más o menos lo que
     el ícono, al copiar y al volver: un fundido de los dos colores lo dejaría
     gris sobre gris a mitad de camino. */
  .kelco-copy-field-button:empty::before,
  .kelco-copy-field-button:empty::after {
    content: "";
    box-sizing: border-box;
    position: absolute;
    top: 50%;
    left: 50%;
    width: 11px;
    height: 11px;
    border: 1.5px solid currentColor;
    transition:
      width 0.45s var(--ease-entrance),
      height 0.45s var(--ease-entrance),
      transform 0.45s var(--ease-entrance),
      border-width 0.3s var(--ease-entrance),
      border-radius 0.45s var(--ease-entrance),
      opacity 0.3s var(--ease-entrance),
      color 0.05s step-end;
  }

  .kelco-copy-field-button:empty::before {
    border-width: 1.5px 0 0 1.5px;
    border-radius: 2.5px 0 0 0;
    transform: translate(-50%, -50%) translate(-2.5px, -2.5px) scale(1);
  }

  .kelco-copy-field-button:empty::after {
    border-radius: 2.5px;
    transform: translate(-50%, -50%) translate(2px, 2px) rotate(0deg);
  }

  /* Copiado. El anillo es kelco-ring, que arranca en la sombra del botón: acá
     va su color, con extensión 0, que no se ve. */
  .kelco-copy-field[data-state="copied"] {
    background-color: color-mix(in oklab, var(--color-bronze) 16%, var(--color-ivory));
  }

  .kelco-copy-field[data-state="copied"] > .kelco-copy-field-button:empty {
    background-size: 100% 100%;
    box-shadow: 0 0 0 0 color-mix(in oklab, var(--color-bronze) 55%, transparent);
    animation:
      kelco-pop 0.5s var(--ease-entrance),
      kelco-ring 0.8s var(--ease-entrance);
  }

  .kelco-copy-field[data-state="copied"] > .kelco-copy-field-button:empty::before,
  .kelco-copy-field[data-state="copied"] > .kelco-copy-field-button:empty::after {
    color: var(--color-ivory);
  }

  .kelco-copy-field[data-state="copied"] > .kelco-copy-field-button:empty::before {
    opacity: 0;
    transform: translate(-50%, -50%) translate(2px, 2px) scale(0.5);
  }

  /* Los dos bordes que pierde se afinan hasta 0 en vez de pasar a
     transparente: en colores forzados el navegador pinta un borde
     transparente, y el check sería un rombo. */
  .kelco-copy-field[data-state="copied"] > .kelco-copy-field-button:empty::after {
    width: 6px;
    height: 11px;
    border-top-width: 0;
    border-left-width: 0;
    border-radius: 0 0 1px 0;
    transform: translate(-50%, -50%) translate(0, -1.5px) rotate(45deg);
  }

  /* El mensaje: oculto a la vista (el check lo dice), lo leen los lectores de
     pantalla. Con error, aparece debajo del valor, que sigue seleccionable
     para copiarlo a mano. */
  .kelco-copy-field-status {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    font-size: 12px;
    color: var(--color-text);
  }

  .kelco-copy-field[data-state="error"] > .kelco-copy-field-status {
    position: static;
    grid-column: 1 / -1;
    width: auto;
    height: auto;
    margin: 0;
    padding: 0 0 6px;
    overflow: visible;
    clip-path: none;
    white-space: normal;
  }

  /* kelco-copy-field-dark: sobre tinta o petróleo. El relleno es marfil
     translúcido y el tinte de copiado bronze-light, así el campo sirve sobre
     cualquiera de los dos; el ícono y el disco pasan a marfil (del color del
     texto), el check a tinta y el anillo a bronze-light. El valor y el mensaje
     van en marfil al 75 %: 5,2:1 o más sobre el campo en reposo y teñido,
     sobre tinta, ink-raised, petróleo o petrol-deep (text-on-dark
     bajaría a 4:1 sobre petróleo). Sin él, sobre marfil o blanco, el valor en
     texto da 7:1 o más, también teñido. */
  .kelco-copy-field.kelco-copy-field-dark {
    background-color: color-mix(in oklab, var(--color-ivory) 8%, transparent);
    color: var(--color-ivory);
  }

  .kelco-copy-field.kelco-copy-field-dark[data-state="copied"] {
    background-color: color-mix(in oklab, var(--color-bronze-light) 16%, transparent);
  }

  .kelco-copy-field.kelco-copy-field-dark > .kelco-copy-field-value,
  .kelco-copy-field.kelco-copy-field-dark > .kelco-copy-field-status {
    color: color-mix(in oklab, var(--color-ivory) 75%, transparent);
  }

  .kelco-copy-field.kelco-copy-field-dark[data-state="copied"] > .kelco-copy-field-button:empty {
    box-shadow: 0 0 0 0 color-mix(in oklab, var(--color-bronze-light) 55%, transparent);
  }

  .kelco-copy-field.kelco-copy-field-dark[data-state="copied"] > .kelco-copy-field-button:empty::before,
  .kelco-copy-field.kelco-copy-field-dark[data-state="copied"] > .kelco-copy-field-button:empty::after {
    color: var(--color-ink);
  }

  /* Diálogo modal sobre el <dialog> nativo. Markup, apertura sin script y qué
     pasa donde falta: README, "Diálogo". El ancho es del sitio, con una clase
     propia junto a kelco-dialog.

     La caja es una columna: la cabecera y el pie quedan fijos y, si la caja no
     entra en alto, sólo el cuerpo se desplaza. El cuerpo y el pie son
     opcionales (no los dos). El margen interior va en cada parte y no en la
     caja: así el cuerpo se desplaza de borde a borde y al anillo de foco de lo
     que está contra su borde le queda lugar dentro del área que recorta.

     Entra con kelco-fade-in-up-sm. Sale con transiciones: display y overlay,
     discretas, lo dejan visible (y en columna) y en la capa superior mientras
     se desvanece. Donde overlay no existe (en 2026, Firefox y Safari) deja la
     capa superior al cerrarse: el fondo se va de golpe y la caja se desvanece
     en su lugar.

     Las animaciones de entrada van sin fill-mode: si retienen opacity y
     transform al terminar, Chrome no arranca las transiciones de salida. Sin
     demora, terminan en el mismo valor que el estilo abierto. */
  .kelco-dialog {
    /* Centrado y con tope, como el modal del navegador (:modal), pero
       declarado acá para que la caja no se mueva ni cambie de tamaño mientras
       sale. border-box: el tope y el ancho que ponga el sitio cuentan el
       borde. El tope se mide dentro del área segura: con viewport-fit=cover,
       en un iPhone la caja queda a 16 px de la isla, de las esquinas y de la
       barra de inicio; sin él, env() vale 0. */
    box-sizing: border-box;
    position: fixed;
    inset: env(safe-area-inset-top, 0px) env(safe-area-inset-right, 0px) env(safe-area-inset-bottom, 0px) env(safe-area-inset-left, 0px);
    max-width: calc(100% - 32px - env(safe-area-inset-left, 0px) - env(safe-area-inset-right, 0px));
    max-height: calc(100% - 32px - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px));
    margin: auto;
    flex-direction: column;
    /* Sólo si ni la cabecera y el pie entran en alto se desplaza la caja
       entera; si no, el cuerpo se achica y se desplaza él. */
    overflow: auto;
    overscroll-behavior: contain;
    padding: 0;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-card);
    background-color: var(--color-ivory);
    color: var(--color-ink);
    box-shadow: var(--shadow-card);
    /* La cabecera y el pie se enteran de cuánto se desplazó el cuerpo (ver
       kelco-dialog-header::after y kelco-dialog-footer::before). */
    timeline-scope: --kelco-dialog-body;
    transition-property: opacity, transform, display, overlay;
    transition-duration: 0.25s;
    transition-timing-function: var(--ease-entrance);
    /* Aparte del shorthand: un navegador sin transition-behavior descartaría
       la declaración entera. */
    transition-behavior: allow-discrete;
  }

  /* flex sólo abierto: cerrado manda el display: none del navegador. Al
     cerrarse, la transición discreta de display conserva flex hasta que la
     caja se desvanece. */
  .kelco-dialog[open] {
    display: flex;
    animation: kelco-fade-in-up-sm 0.45s var(--ease-entrance);
  }

  .kelco-dialog:not([open]) {
    opacity: 0;
    transform: translateY(8px);
  }

  .kelco-dialog::backdrop {
    background-color: color-mix(in oklab, var(--color-ink) 45%, transparent);
    -webkit-backdrop-filter: blur(2px);
    backdrop-filter: blur(2px);
    transition-property: opacity, display, overlay;
    transition-duration: 0.25s;
    transition-timing-function: var(--ease-entrance);
    transition-behavior: allow-discrete;
  }

  .kelco-dialog[open]::backdrop {
    animation: kelco-fade-in 0.3s ease;
  }

  .kelco-dialog:not([open])::backdrop {
    opacity: 0;
  }

  .kelco-dialog-header {
    position: relative;
    display: flex;
    flex: none;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    /* Abajo, los mismos 16 px que el pie deja entre su línea y los botones:
       la línea de la cabecera queda a 16 px del título. */
    padding: 24px 24px 16px;
  }

  /* La línea de abajo de la cabecera, el espejo de la del pie: sólo mientras
     el cuerpo está desplazado desde arriba. Aparece en los primeros 24 px del
     recorrido y no está si el cuerpo entra entero (vale la opacidad 0 de acá).
     Es kelco-fade-in atado al desplazamiento del cuerpo; después de esos 24 px,
     forwards la deja visible. forwards acá no traba la salida: retiene la
     opacidad de la línea, no la de la caja. Donde no hay líneas de tiempo de
     desplazamiento, la línea no aparece nunca. Es un borde, como la del pie. */
  .kelco-dialog-header::after {
    content: "";
    position: absolute;
    inset: auto 0 0;
    border-bottom: 1px solid var(--color-divider);
    opacity: 0;
    pointer-events: none;
    animation: kelco-fade-in linear forwards;
    animation-timeline: --kelco-dialog-body;
    animation-range: 0 24px;
  }

  /* Familia y peso de titular con cualquier etiqueta, no sólo h2. Un título de
     diálogo nombra algo ("Apple · Software Update"): va como está escrito. La
     minúscula que base.css les pone a h1 y h2 no lo alcanza, porque esta capa
     le gana. */
  .kelco-dialog-title {
    margin: 0;
    font-family: var(--font-display);
    font-size: 22px;
    font-weight: var(--font-weight-heading);
    line-height: 1.2;
    letter-spacing: -0.03em;
    text-transform: none;
  }

  /* La cruz son dos bordes: en colores forzados el navegador conserva los
     bordes y borra los fondos. El área de toque sobresale hacia la esquina sin
     correr el título, y hacia abajo sin estirar la cabecera: el alto lo pone el
     título y la línea queda a 16 px de él. */
  .kelco-dialog-close {
    position: relative;
    flex: none;
    width: 36px;
    height: 36px;
    margin: -6px -10px -10px 0;
    padding: 0;
    border: 0;
    border-radius: 999px;
    background-color: transparent;
    color: inherit;
    cursor: pointer;
    transition: background-color 0.25s;
  }

  .kelco-dialog-close::before,
  .kelco-dialog-close::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 16px;
    border-top: 1.5px solid currentColor;
    transform: translate(-50%, -50%) rotate(45deg);
  }

  .kelco-dialog-close::after {
    transform: translate(-50%, -50%) rotate(-45deg);
  }

  .kelco-dialog-close:hover {
    background-color: color-mix(in oklab, currentColor 8%, transparent);
  }

  /* Lo único que se desplaza. min-height: 0 lo deja achicarse por debajo de su
     contenido cuando la caja llega al tope. */
  .kelco-dialog-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: 12px 24px 24px;
    font-size: 15px;
    line-height: 1.7;
    color: var(--color-text);
    scroll-timeline: --kelco-dialog-body block;
  }

  /* Con pie, el espacio de abajo lo pone el pie. */
  .kelco-dialog-body:has(+ .kelco-dialog-footer) {
    padding-bottom: 16px;
  }

  /* Un cuerpo vacío cuenta como si no estuviera: sin él, entre el título y
     las acciones quedan los 16 px de abajo de la cabecera y los 16 de arriba
     del pie. Sin caja no hay línea de tiempo de desplazamiento, así que las
     líneas de la cabecera y del pie no aparecen. Vacío es sin nada adentro,
     tampoco espacios: Chrome (156) los cuenta como contenido para :empty. */
  .kelco-dialog-body:empty {
    display: none;
  }

  /* Pie: las acciones, siempre a la vista. En fila, y si no entran pasan a la
     línea siguiente con su espacio entre filas y entre columnas. La alineación
     la puede cambiar el sitio con una clase propia. */
  .kelco-dialog-footer {
    position: relative;
    display: flex;
    flex: none;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px 24px;
    padding: 16px 24px 24px;
  }

  /* La línea de arriba del pie, sólo mientras queda cuerpo por desplazar
     debajo de él: se desvanece en los últimos 24 px del recorrido y no está si
     el cuerpo entra entero (sin desplazamiento la línea de tiempo está
     inactiva y vale la opacidad 0 de acá). Es kelco-fade-in al revés, atado al
     desplazamiento del cuerpo; antes de esos 24 px, backwards la deja visible.
     Donde no hay líneas de tiempo de desplazamiento (en 2026, Firefox), la
     animación dura 0 s y la línea no aparece nunca. Es un borde: en colores
     forzados el navegador lo pinta con el color del sistema. */
  .kelco-dialog-footer::before {
    content: "";
    position: absolute;
    inset: 0 0 auto;
    border-top: 1px solid var(--color-divider);
    opacity: 0;
    pointer-events: none;
    /* animation-timeline y animation-range después del shorthand, que los
       reinicia. */
    animation: kelco-fade-in linear reverse backwards;
    animation-timeline: --kelco-dialog-body;
    animation-range: calc(100% - 24px) 100%;
  }

  /* Un campo para copiar en el pie ocupa su propia fila, con el ancho entero
     del pie. */
  .kelco-dialog-footer > .kelco-copy-field {
    flex-basis: 100%;
  }

  /* Antetítulo de un titular de entrada: etiqueta serif en bronce, la primera
     en aparecer. El tamaño por defecto es el de etiqueta; un sitio puede subirlo
     a otro nivel de la escala. Literata viene sólo en 500: declararlo evita que
     el navegador la engrose sintética bajo un contenedor más pesado. */
  .kelco-eyebrow {
    margin: 0;
    font-family: var(--font-serif);
    font-size: var(--text-label);
    font-weight: 500;
    line-height: 1.5;
    color: var(--color-bronze);
    animation: kelco-fade-in 0.8s ease both;
  }

  /* Titular de entrada (headline() en kelco-design/html). Familia, peso y
     minúscula vienen de base.css. Cada línea sube desde detrás de su máscara,
     la segunda un poco después. */
  .kelco-headline {
    margin: 0;
    font-size: var(--text-h1);
    line-height: var(--text-h1--line-height);
    letter-spacing: var(--text-h1--letter-spacing);
  }

  .kelco-headline-line {
    display: block;
    overflow: hidden;
    /* Sin esto la máscara corta los descendentes. */
    padding-bottom: 0.08em;
  }

  .kelco-headline-line > span {
    display: block;
    animation: kelco-mask-up 0.9s var(--ease-entrance) 0.1s both;
  }

  .kelco-headline-line + .kelco-headline-line > span {
    animation-delay: 0.24s;
  }

  .kelco-headline-accent {
    color: var(--color-bronze);
  }

  /* Selector de idioma (languageSwitcher() en kelco-design/html). El peso de los no
     actuales se hereda del contenedor. */
  .kelco-language-switcher {
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: 12px;
    line-height: calc(16 / 12);
    letter-spacing: 0.04em;
  }

  .kelco-language-switcher a {
    /* El área de toque crece hacia arriba y abajo sin mover la barra. */
    margin: -8px 0;
    padding: 8px 4px;
    color: var(--color-text-muted);
    text-decoration: none;
    transition: color 0.25s;
  }

  .kelco-language-switcher a:hover,
  .kelco-language-switcher a[aria-current] {
    color: var(--color-ink);
  }

  .kelco-language-switcher a[aria-current] {
    font-weight: 600;
  }

  .kelco-language-switcher span {
    color: var(--color-border-strong);
  }

  /* Bajada de un titular de entrada: aparece después de las líneas. El ancho
     y los márgenes son del sitio. */
  .kelco-lead {
    margin: 0;
    font-size: 17px;
    line-height: 1.7;
    color: var(--color-text);
    animation: kelco-fade-in 0.9s ease 0.45s both;
  }

  /* El logo de Kelco en la barra superior (logos/kelco-ink.png). */
  .kelco-logo {
    display: block;
    width: 72px;
    height: 18px;
  }

  /* Barra de progreso de lectura bajo la barra superior. El ancho de
     .kelco-progress-bar lo pone el script de cada sitio. */
  .kelco-progress {
    height: 2px;
  }

  .kelco-progress-bar {
    display: block;
    width: 0;
    height: 2px;
    background-color: var(--color-bronze);
    transition: width 0.15s linear;
  }

  /* Superficie de la barra superior: marfil translúcido sobre lo que pasa por
     debajo. Posición, alto y ancho son del sitio. */
  .kelco-veil {
    background-color: color-mix(in oklab, var(--color-ivory) 88%, transparent);
    -webkit-backdrop-filter: blur(16px);
    backdrop-filter: blur(16px);
  }
}
