/*
 * Base del sitio: reset, chrome (header/footer), controles, biblioteca y
 * estados especiales. Se carga en todas las paginas.
 *
 * La ficha y el lector viven en story.css, que solo carga /relatos/:slug.
 *
 * Regla: aca no hay valores de marca hardcodeados. Todo sale de tokens.css.
 */

/* ---------------------------------------------------------------- reset --- */

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

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

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-ui);
  font-size: var(--size-body);
  line-height: var(--leading-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1,
h2,
h3,
h4 {
  margin: 0;
  font-weight: 600;
  line-height: var(--leading-tight);
  text-wrap: balance;
}

p {
  margin: 0;
}

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

a {
  color: inherit;
}

/*
 * `hidden` tiene que ganarle a cualquier display: grid/flex que le pongamos
 * despues a un componente. Sin esto, un elemento que el JS oculta seguiria
 * visible por culpa de su propio layout.
 */
[hidden] {
  display: none !important;
}

/* El foco se ve SIEMPRE, y con el mismo tratamiento en todo el sitio. */
:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 3px;
  border-radius: var(--radius-1);
}

/*
 * Todo el movimiento del sitio esta detras de esta preferencia. Es la unica
 * regla que apaga animaciones, para no tener que recordarlo en cada componente.
 */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/*
 * Nada de `scroll-behavior: smooth`.
 *
 * Con capitulos de 2000 palabras —unas siete pantallas de telefono— cualquier
 * salto de ancla son miles de pixeles, y suavizarlo lo convierte en un
 * deslizamiento largo que marea y que ademas se puede interrumpir a mitad de
 * camino. Para un lector, el salto instantaneo es lo correcto: se llega al
 * punto, no se viaja hasta el.
 */

/* Solo visible para lectores de pantalla. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
}

.skip-link:focus {
  left: var(--space-4);
  top: var(--space-4);
  background: var(--color-surface);
  color: var(--color-text);
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-2);
  border: 1px solid var(--color-border);
}

/* --------------------------------------------------------------- chrome --- */

.shell {
  width: 100%;
  max-width: var(--content-width);
  margin-inline: auto;
  padding-inline: var(--space-5);
}

@media (min-width: 48rem) {
  .shell {
    padding-inline: var(--space-6);
  }
}

/*
 * Header minimo a proposito: el sitio es para leer, no para navegar. Es el
 * logo, la bajada y el idioma, sin menu, sin buscador y sin barra de sesion.
 * Cuando exista una pagina "Acerca de" real, su link va junto al selector; hoy
 * no se pone un link muerto solo para llenar el espacio.
 */
.site-header {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding-block: var(--space-4);
}

.site-wordmark {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  text-decoration: none;
  color: var(--color-text);
}

/*
 * El logo.
 *
 * Se dimensiona por ALTURA, no por ancho: asi el eje del header no se mueve si
 * algun dia el logotipo se dibuja mas largo o mas corto. El archivo tiene el
 * triple de resolucion que el tamano de pantalla, para que se vea nitido en
 * telefonos.
 */
.site-logo {
  display: block;
  width: auto;
  height: 1.6rem;
}

@media (min-width: 48rem) {
  .site-logo {
    height: 2rem;
  }
}

/*
 * Modo oscuro sin un segundo archivo.
 *
 * `invert` pasa la tinta negra a marfil (y el fondo, que esta recortado, no se
 * entera); `hue-rotate` le devuelve al rojo el tono que `invert` le habia dado
 * vuelta hacia el cian. Dos archivos se desincronizan a la primera correccion
 * del logotipo; un filtro, no.
 *
 * Los dos selectores son los mismos que usa tokens.css para la paleta oscura:
 * el sistema cuando no hay eleccion, y el atributo cuando la hay. Si aca se
 * escribiera solo la media query, quien eligiera "oscuro" a mano veria el
 * logotipo negro sobre carbon.
 *
 * Sepia no lleva filtro: la tinta negra sobre papel crema se ve como en papel.
 */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) .site-logo {
    filter: invert(1) hue-rotate(180deg);
  }
}

:root[data-theme="dark"] .site-logo {
  filter: invert(1) hue-rotate(180deg);
}

/*
 * La bajada de la marca.
 *
 * Solo en la home —en la ficha el header se reduce a la vuelta— y solo cuando
 * hay ancho de sobra: en telefono competiria con el logo por la misma linea y
 * perderian los dos.
 */
.site-tagline {
  display: none;
  font-size: var(--size-micro);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--color-text-muted);
}

@media (min-width: 62rem) {
  .site-tagline {
    display: block;
  }
}

/* El idioma se va siempre al extremo, este o no la bajada. */
.language-switch {
  margin-left: auto;
}

/* La flecha vuelve al eje optico del texto: centrada da la sensacion de estar
   un pelo baja, porque la mayuscula no llena la caja de linea. */
.site-back-icon {
  margin-block-start: -1px;
  color: var(--color-text-muted);
}

.site-wordmark:hover .site-back-icon {
  color: var(--color-accent);
}

/*
 * Selector de idioma.
 *
 * Tres etiquetas de dos letras, del peso visual de una nota al pie: el idioma
 * es una decision que se toma una vez, no una seccion del sitio. El activo se
 * distingue por color y peso, no por una caja: en un header de una sola linea,
 * un recuadro pesa mas que el nombre del sitio.
 *
 * Son <abbr> con `title`, asi que al pasar el mouse dicen "Português" entero.
 * El subrayado punteado que los navegadores les ponen por defecto se quita: aca
 * el titulo es una ayuda, no una convencion tipografica que valga la tinta.
 */
.language-switch-list {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  list-style: none;
  margin: 0;
  padding: 0;
}

.language-switch-item {
  font-family: var(--font-ui);
  font-size: var(--size-micro);
  font-weight: 600;
  letter-spacing: var(--tracking-wide);
  color: var(--color-text-muted);
  text-decoration: none;
  transition: color var(--transition-fast);
}

.language-switch-item abbr {
  text-decoration: none;
  border-bottom: none;
  cursor: inherit;
}

.language-switch-item:hover {
  color: var(--color-accent);
}

.language-switch-item.is-current {
  color: var(--color-text);
}

/*
 * El relato se esta mostrando en un idioma que no es el de la interfaz porque
 * todavia no hay traduccion. Es informacion, no un error: va arriba de la tapa,
 * con el peso de una nota al pie y en el tono del resto de los datos
 * secundarios. Nada de amarillo ni de iconos de advertencia.
 */
.story-translation-notice {
  max-width: var(--reading-width);
  margin-inline: auto;
  margin-bottom: var(--space-5);
  font-family: var(--font-ui);
  font-size: var(--size-small);
  line-height: var(--leading-body);
  color: var(--color-text-muted);
  text-wrap: pretty;
}

/*
 * Pie.
 *
 * Una cita y la marca, en la misma linea. La cita es la unica frase de autor de
 * todo el sitio y por eso esta abajo: el que llega hasta aca ya leyo algo.
 */
.site-footer {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2) var(--space-5);
  margin-top: var(--space-8);
  padding-block: var(--space-5);
  border-top: 1px solid var(--color-border);
  color: var(--color-text-muted);
}

.site-footer-quote {
  font-family: var(--font-reading);
  font-size: var(--size-small);
  font-style: italic;
}

.site-footer-name {
  font-size: var(--size-micro);
  font-weight: 600;
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--color-gold);
}

/* ------------------------------------------------------------ controles --- */

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: 2.75rem; /* objetivo tactil comodo en telefono */
  padding: var(--space-2) var(--space-5);
  font-family: var(--font-ui);
  font-size: var(--size-small);
  font-weight: 600;
  line-height: 1.2;
  text-decoration: none;
  text-align: center;
  color: var(--color-accent-contrast);
  background: var(--color-accent);
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  cursor: pointer;
  transition: background-color var(--transition-fast);
}

.button:hover {
  background: var(--color-accent-hover);
}

.button--primary {
  min-height: 3rem;
  padding-inline: var(--space-7);
  font-size: var(--size-body);
}

.button--quiet {
  color: var(--color-text);
  background: transparent;
  border-color: var(--color-border-strong);
}

.button--quiet:hover {
  background: var(--color-surface-sunken);
}

.button[aria-disabled="true"] {
  opacity: 0.35;
  pointer-events: none;
}

/* Link discreto de texto, con subrayado que respeta las descendentes. */
.text-link {
  color: var(--color-accent);
  text-decoration: underline;
  text-underline-offset: 0.2em;
  text-decoration-thickness: 1px;
}

/*
 * Los SVG en linea heredan color y se dimensionan en `em` del contexto, asi que
 * una flecha dentro de un boton chico sale chica sin una clase extra.
 */
.icon {
  flex: none;
  width: 1.15em;
  height: 1.15em;
}

.meta {
  font-family: var(--font-ui);
  font-size: var(--size-small);
  color: var(--color-text-muted);
}

/* Separadores "·" entre datos, puestos por CSS: no son contenido. */
.meta-list {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2);
  list-style: none;
  margin: 0;
  padding: 0;
}

.meta-list > li + li::before {
  content: "·";
  margin-right: var(--space-2);
  color: var(--color-border-strong);
}

.tag-list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: var(--size-micro);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--color-text-muted);
}

/* ----------------------------------------------------------- portadas ----- */

/*
 * Toda portada del sitio usa la misma relacion de aspecto y `object-fit: cover`:
 * las imagenes nunca se deforman, aunque el archivo subido tenga otra forma.
 */
.cover {
  display: block;
  width: 100%;
  aspect-ratio: var(--cover-ratio);
  object-fit: cover;
  background: var(--color-surface-sunken);
  border-radius: var(--radius-2);
}

/*
 * Fallback cuando no hay portada: no un icono de imagen rota, sino una placa
 * con la inicial del titulo. Digno, y coherente con el resto del sitio.
 */
.cover--placeholder {
  display: grid;
  place-items: center;
  background: var(--color-surface-sunken);
  border: 1px solid var(--color-border);
  color: var(--color-border-strong);
  font-family: var(--font-display);
  font-size: 3rem;
  line-height: 1;
  user-select: none;
}

/* ---------------------------------------------------------------- home ---- */

/*
 * La promesa.
 *
 * Una cinta a ancho completo, del alto de una linea. Es la unica franja con
 * fondo propio de todo el sitio y se lo gana porque dice la unica cosa que no
 * puede pasar desapercibida: que no hay que pagar ni registrarse. Va fuera de
 * `.shell` porque es una cinta, no una seccion; cortarla al ancho del contenido
 * la convertiria en otra caja mas.
 */
.promise {
  border-block: 1px solid var(--color-border);
  background: var(--color-surface-sunken);
}

.promise-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-6);
  padding-block: var(--space-3);
}

.promise-item {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--size-micro);
  font-weight: 600;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--color-gold);
}

/* La segunda linea es informacion, no promesa: mismo cuerpo, menos tinta. */
.promise-item--soft {
  font-weight: 400;
  letter-spacing: var(--tracking-wide);
  color: var(--color-text-muted);
}

/* En telefono queda solo la primera: los idiomas ya los dice el selector. */
@media (max-width: 47.999rem) {
  .promise-item--soft {
    display: none;
  }
}

/*
 * El hero.
 *
 * Tres piezas: el argumento, la portada del relato destacado y su ficha. En
 * telefono se apilan en ese mismo orden, que es tambien el orden en que
 * importan; en pantallas medianas el argumento se queda con la fila de arriba y
 * la tapa y la ficha comparten la de abajo; en desktop van las tres en fila.
 */
.hero {
  display: grid;
  gap: var(--space-6);
  padding-block: var(--space-7) var(--space-8);
  grid-template-areas:
    "lead"
    "cover"
    "feature";
}

.hero-lead {
  grid-area: lead;
}

.hero-cover {
  grid-area: cover;
}

.hero-feature {
  grid-area: feature;
}

@media (min-width: 46rem) {
  .hero {
    /* 17.25rem = tapa + asomo del disco, o sea el ancho exacto de .hero-cover. */
    grid-template-columns: 17.25rem minmax(0, 1fr);
    grid-template-areas:
      "lead lead"
      "cover feature";
    align-items: center;
    column-gap: var(--space-7);
  }
}

@media (min-width: 68rem) {
  .hero {
    grid-template-columns: minmax(0, 1.15fr) 17.25rem minmax(0, 0.9fr);
    grid-template-areas: "lead cover feature";
    column-gap: var(--space-8);
  }
}

/*
 * Volanta con filete.
 *
 * El filete dorado se estira hasta donde llegue y es lo unico que marca el
 * comienzo del bloque: una linea horizontal separa igual que un borde y no
 * encierra nada.
 */
.hero-eyebrow {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  font-size: var(--size-micro);
  font-weight: 600;
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--color-accent);
}

.hero-eyebrow::after {
  content: "";
  flex: 1 1 auto;
  max-width: 7rem;
  border-top: 1px solid var(--color-gold-line);
}

/*
 * El titular.
 *
 * Es lo mas grande de la pagina y el unico texto en negrita: el resto de la
 * jerarquia la hace el espacio. El ancho en `ch` lo parte en dos o tres lineas
 * cortas en cualquiera de los tres idiomas, que es lo que le da el aire de
 * portada de libro en vez de titulo de landing.
 */
.hero-title {
  margin-top: var(--space-4);
  max-width: 18ch;
  font-family: var(--font-display);
  font-size: var(--size-hero);
  font-weight: 700;
  line-height: 1.02;
  letter-spacing: -0.025em;
}

.hero-lede {
  margin-top: var(--space-4);
  max-width: 30rem;
  font-family: var(--font-reading);
  font-size: var(--size-reading);
  line-height: var(--leading-body);
  color: var(--color-text-muted);
  text-wrap: pretty;
}

/* Los tres motivos: gratis, sin registro, sin muro de pago. */
.benefit-list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4) var(--space-6);
  list-style: none;
  margin: var(--space-6) 0 0;
  padding: 0;
}

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

.benefit .icon {
  width: 1.5rem;
  height: 1.5rem;
  color: var(--color-accent);
}

.benefit-body {
  display: flex;
  flex-direction: column;
  line-height: var(--leading-snug);
}

.benefit-title {
  font-size: var(--size-small);
  font-weight: 600;
}

.benefit-note {
  font-size: var(--size-micro);
  color: var(--color-text-muted);
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4) var(--space-6);
  margin-top: var(--space-6);
}

/*
 * La segunda accion no es un boton: es un enlace. Dos botones uno al lado del
 * otro obligan a elegir; un boton y un enlace dicen cual es el camino y dejan
 * el otro disponible para quien prefiera mirar antes de entrar.
 */
.hero-explore {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--size-micro);
  font-weight: 600;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  text-decoration: none;
  color: var(--color-text-muted);
  transition: color var(--transition-fast);
}

.hero-explore:hover {
  color: var(--color-accent);
}

/*
 * La portada del destacado.
 *
 * El disco rojo no es decoracion gratuita: despega la tapa del papel sin
 * ponerle un marco, y es lo unico que aporta color en toda la mitad superior de
 * la pagina. Es un `::before`, asi que no cuesta un request ni un byte.
 */
/*
 * La tapa del destacado y su disco.
 *
 * El bloque mide tapa + asomo, y la tapa se apoya contra su borde derecho: asi
 * el disco vive SIEMPRE dentro de la caja, con `inset-inline-start: 0`, y no
 * hay ninguna posicion negativa que pueda desbordar la pagina cuando la columna
 * se angosta. El asomo es espacio reservado, no un voladizo.
 *
 * Las dos medidas son variables para que no se puedan desincronizar: si la tapa
 * crece, crecen con ella el disco y la caja que los contiene.
 */
.hero-cover {
  --cover-width: 15rem;
  --disc-peek: 2.25rem;

  position: relative;
  display: flex;
  justify-content: flex-end;
  width: 100%;
  max-width: calc(var(--cover-width) + var(--disc-peek));
  margin-inline: auto;
  padding-inline-start: var(--disc-peek);
}

.hero-cover::before {
  content: "";
  position: absolute;
  z-index: 0;
  inset-block-start: -1.25rem;
  inset-inline-start: 0;
  width: calc(var(--cover-width) * 0.78);
  aspect-ratio: 1;
  border-radius: 50%;
  background: var(--color-hero-disc);
}

.cover--featured {
  position: relative;
  z-index: 1;
  width: 100%;
  box-shadow: var(--shadow-cover);
}

.hero-feature {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-3);
}

.hero-kicker {
  display: flex;
  align-items: center;
  align-self: stretch;
  gap: var(--space-3);
  font-size: var(--size-micro);
  font-weight: 600;
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--color-text-muted);
}

.hero-kicker::after {
  content: "";
  flex: 1 1 auto;
  border-top: 1px solid var(--color-gold-line);
}

.feature-title {
  font-family: var(--font-display);
  font-size: var(--size-chapter);
  font-weight: 500;
  line-height: var(--leading-snug);
}

.feature-title a {
  text-decoration: none;
}

.feature-title a:hover {
  color: var(--color-accent);
}

.feature-synopsis {
  max-width: 34rem;
  font-family: var(--font-reading);
  font-size: var(--size-reading);
  line-height: var(--leading-body);
  color: var(--color-text-muted);
  text-wrap: pretty;
}

/*
 * Los generos del destacado si llevan contorno, y son la unica excepcion a
 * "pocas cajas": estan pegados a la linea de datos y sin una forma propia las
 * dos lineas se leerian como una sola enumeracion larga.
 */
.hero-feature .tag-list > li {
  padding: 0.15em 0.6em;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-pill);
}

.feature-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-2);
  padding-bottom: 2px;
  font-size: var(--size-small);
  font-weight: 600;
  text-decoration: none;
  color: var(--color-accent);
  border-bottom: 1px solid currentcolor;
}

.library {
  padding-bottom: var(--space-4);
}

.library-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3) var(--space-5);
  padding-bottom: var(--space-3);
  border-bottom: 1px solid var(--color-border);
  margin-bottom: var(--space-5);
}

.library-heading {
  font-size: var(--size-micro);
  font-weight: 600;
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--color-gold);
}

/*
 * Buscador y orden.
 *
 * Sin caja, sin icono de lupa, sin boton de "buscar": un campo subrayado y un
 * desplegable del sistema. Filtra mientras se escribe, asi que un boton seria
 * un adorno; el icono, ruido que la etiqueta ya resuelve.
 */
.library-tools {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4);
  margin-left: auto;
}

.field-input,
.field-select {
  font-family: var(--font-ui);
  font-size: var(--size-small);
  color: var(--color-text);
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--color-border-strong);
  border-radius: 0;
  padding: var(--space-2) 0;
  min-height: 2.5rem;
}

.field-input {
  width: 11rem;
  max-width: 100%;
  transition: border-color var(--transition-fast);
}

.field-input::placeholder {
  color: var(--color-text-muted);
}

.field-input:focus,
.field-select:focus {
  outline: none;
  border-bottom-color: var(--color-accent);
}

.field-input:focus-visible,
.field-select:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 4px;
}

.field-select {
  /* La flecha nativa es distinta en cada sistema; dejarla es mas honesto que
     dibujar una propia que no coincida con el desplegable real. */
  cursor: pointer;
}

/* En telefono el buscador ocupa su propia linea y todo el ancho. */
@media (max-width: 33.999rem) {
  .library-head {
    gap: var(--space-4);
  }

  .library-tools {
    width: 100%;
    margin-left: 0;
    justify-content: space-between;
  }

  .library-tools .field:first-child {
    flex: 1 1 9rem;
  }

  .field-input {
    width: 100%;
  }
}

.library-status:empty {
  display: none;
}

.library-status {
  margin-bottom: var(--space-4);
  font-size: var(--size-small);
  color: var(--color-text-muted);
}

.library-empty {
  padding-block: var(--space-6);
  font-family: var(--font-reading);
  font-size: var(--size-reading);
  color: var(--color-text-muted);
}

/*
 * Dos columnas desde el telefono: una biblioteca se lee de un vistazo, como una
 * estanteria. A una sola columna, con portadas de 3/4, cada relato ocupaba la
 * pantalla entera y no se intuia que hubiera mas.
 *
 * De ahi en mas, tantas columnas como entren sin que la portada quede diminuta.
 */
.library-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--space-6) var(--space-4);
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media (min-width: 34rem) {
  .library-grid {
    gap: var(--space-6) var(--space-5);
    grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
  }
}

@media (min-width: 64rem) {
  .library-grid {
    gap: var(--space-7) var(--space-5);
    grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  }
}

/*
 * A dos columnas en un telefono la columna mide ~150 px: la escala tipografica
 * del catalogo baja un escalon para que el titulo no ocupe tres renglones.
 */
@media (max-width: 33.999rem) {
  .story-card {
    gap: var(--space-1);
  }

  .story-card-title {
    font-size: 1.0625rem;
  }

  .story-card .meta {
    font-size: var(--size-micro);
  }

  .story-card-synopsis {
    font-size: var(--size-small);
    line-height: 1.45;
  }
}

/*
 * La tarjeta no es una caja: es la portada y el texto debajo, sin borde ni
 * fondo propio. Un solo enlace real (el del titulo) se estira sobre toda la
 * tarjeta con ::after, asi que el area clickeable es grande pero los lectores
 * de pantalla y el tabulador ven UN destino, no tres.
 */
.story-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.story-card .cover {
  /* Un escalon mas que el `gap`: el titulo tiene que despegarse de la imagen
     mas de lo que se despegan entre si las lineas de texto. */
  margin-bottom: var(--space-1);
  box-shadow: var(--shadow-cover);
  transition: transform var(--transition-base);
}

.story-card:hover .cover {
  transform: translateY(-2px);
}

.story-card-title {
  font-family: var(--font-display);
  font-size: var(--size-card-title);
  font-weight: 400;
  line-height: var(--leading-snug);
}

.story-card-title a {
  text-decoration: none;
}

.story-card-title a::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: var(--radius-2);
}

.story-card-title a:focus-visible {
  outline: none;
}

.story-card-title a:focus-visible::after {
  outline: 2px solid var(--color-focus);
  outline-offset: 4px;
}

.story-card-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2) var(--space-3);
}

/*
 * El sello "Gratis".
 *
 * Esta en cada tarjeta porque es la pregunta que se hace cualquiera al ver una
 * portada de novela, y responderla una sola vez arriba no alcanza para quien
 * llega a la grilla desde un buscador. Por eso es lo mas callado que puede ser
 * sin dejar de leerse: un pixel de borde dorado y nada de fondo.
 */
.badge-free {
  flex: none;
  padding: 0.1em 0.5em;
  font-size: var(--size-micro);
  font-weight: 600;
  line-height: 1.5;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--color-gold);
  border: 1px solid var(--color-gold-line);
  border-radius: var(--radius-1);
}

.story-card-synopsis {
  font-family: var(--font-reading);
  line-height: var(--leading-body);
  color: var(--color-text-muted);
  text-wrap: pretty;
}

/*
 * "Continuar · Capitulo 3". Lo agrega home.js desde localStorage, asi que sin
 * JS simplemente no existe. Va por encima del ::after del titulo (z-index) para
 * poder ser su propio enlace al capitulo exacto.
 */
.story-card-resume {
  position: relative;
  z-index: 1;
  align-self: flex-start;
  font-size: var(--size-micro);
  font-weight: 600;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--color-accent);
  text-decoration: none;
  border-bottom: 1px solid currentcolor;
  padding-bottom: 1px;
}

/* ------------------------------------------------ estados especiales ------ */

/*
 * Biblioteca vacia, 404 y errores comparten tratamiento: centrados, con aire y
 * sin dramatismo. Un 404 tambien es una pagina del sitio, no una pantalla rota.
 */
.notice {
  max-width: var(--prose-width);
  margin-inline: auto;
  padding-block: var(--space-7) var(--space-8);
  text-align: center;
}

.notice-kicker {
  font-size: var(--size-micro);
  font-weight: 600;
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--color-text-muted);
}

.notice-title {
  margin-top: var(--space-3);
  font-family: var(--font-display);
  font-size: var(--size-title);
  font-weight: 400;
}

.notice-text {
  margin-top: var(--space-3);
  font-family: var(--font-reading);
  font-size: var(--size-reading);
  line-height: var(--leading-body);
  color: var(--color-text-muted);
  text-wrap: pretty;
}

.notice-actions {
  margin-top: var(--space-5);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  justify-content: center;
}

.notice-hint {
  margin-top: var(--space-5);
  font-size: var(--size-small);
  color: var(--color-text-muted);
}

.notice-hint code {
  font-family: var(--font-mono);
  font-size: 0.9em;
  background: var(--color-surface-sunken);
  padding: 0.1em 0.4em;
  border-radius: var(--radius-1);
}
