@font-face {
  font-family: Inter;
  src: url('/assets/fonts/inter-latin.woff2') format('woff2');
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
}

@font-face {
  font-family: Inter;
  src: url('/assets/fonts/inter-latin-ext.woff2') format('woff2');
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Inter Tight";
  src: url('/assets/fonts/inter-tight-latin.woff2') format('woff2');
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
}

@font-face {
  font-family: "Inter Tight";
  src: url('/assets/fonts/inter-tight-latin-ext.woff2') format('woff2');
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  color-scheme: light;
  /* Toda la página es un solo tono: el documento, la portada y cualquier
     sección pintan #F4F4F4. Antes el documento era blanco y la primera parte
     de cada página iba un punto más oscura; los cortes entre uno y otro se
     veían, así que ya no se alterna nada. */
  --background: #f4f4f4;
  --surface: #f4f4f4;
  /* Ya no tiñe ninguna sección: queda como fondo de las píldoras pequeñas,
     que necesitan despegarse del papel. */
  --surface-alt: #e8e8e8;
  --surface-card: #ffffff;
  /* El material de la barra pegajosa y de las cabeceras que lo copian. La
     barra es BLANCA a propósito, aunque la página sea #F4F4F4: es lo que la
     separa del documento que le pasa por debajo. */
  --bar-material: rgb(255 255 255 / 90%);
  /* La superficie de tarjeta con el nombre que usan los controles compartidos.
     Sin ella, la píldora del control segmentado caía en `--surface` y se volvía
     invisible desde que los fondos de sección son #F4F4F4 y #E8E8E8. */
  --card: #ffffff;
  --text: #262626;
  --muted: #666666;
  --display-text: #181818;
  --description: #262626;
  --subtitle: #262626;
  --line: #0000001a;
  --black: #000000;
  --white: #ffffff;
  --font-ui: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-display: "Inter Tight", Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  /* EL TAMAÑO DE UN TÍTULO, uno solo: 2,5 rem en cualquier pantalla. Lo usan
     los títulos de sección de la portada, el de Precio, los de Iniciar sesión y
     Contacto, los de las páginas de servicio y los cierres con llamada a la
     acción. La portada es la única excepción declarada, y lo dice su regla. */
  --type-display-size: 2.5rem;
  --type-display-weight: 500;
  --type-display-line: 1;
  --type-display-tracking: normal;
  --type-feature-size: 2rem;
  --type-feature-weight: 500;
  --type-feature-line: 1;
  --type-feature-tracking: normal;
  /* El estilo de enunciado de las páginas de servicio: un titular y su
     continuación en gris con la misma familia, tamaño, peso e interlínea, de
     modo que las dos se lean como una sola frase de dos colores. */
  --type-statement-size: 2rem;
  --type-statement-weight: 400;
  --type-statement-line: 1.25;
  --type-statement-tracking: normal;
  --statement-muted: #808080;
  /* El verde de las acciones de la landing: los enlaces de flecha que abren
     cada servicio y la llamada de la portada. */
  --landing-action: #418200;
  /* LOS COLORES DE SIGNIFICADO, los MISMOS que Analíticas y Reservas.
     `.analytics-trend` vive en `standard-sheet.css` y los lee de aquí; esta
     hoja no los declaraba, así que el distintivo de subida y bajada caía en los
     valores de respaldo —los claros— y en modo oscuro se veía mal. No son
     valores nuevos: son los de `analytics.css`, copiados para que una
     comparación no se lea de una forma aquí y de otra en la pantalla de al
     lado. */
  --success: #14834a;
  --success-soft: #dff3e7;
  --warning: #956500;
  --danger: #d73737;
  --danger-soft: #f8e1e1;
  --surface-raised: #f0f0f0;
  /* EL FONDO DE UN BOTÓN DENTRO DE UNA TARJETA. Un escalón desde la superficie
     de la tarjeta, no el color contrario: en claro, una fila de botones negros
     macizos grita más que lo que dicen, y ninguno de ellos es la acción
     principal de la pantalla. No es un valor nuevo, es el que ya tienen las
     superficies de este producto —`--surface-alt` en claro y
     `--surface-raised` en oscuro—, elegido en cada tema por el que de verdad
     se despega de la tarjeta. */
  --account-control: var(--surface-alt);
  --type-description-size: 1.3rem;
  --type-description-weight: 400;
  --type-description-line: 1.5;
  --type-description-tracking: -.5px;
  --type-subtitle-size: 1.5rem;
  --type-subtitle-weight: 400;
  --type-subtitle-line: 1.5;
  --type-subtitle-tracking: -.5px;
  --type-body-size: 1rem;
  --type-body-weight: 400;
  --type-body-line: 1.5;
  --type-button-size: 1rem;
  --type-button-weight: 400;
  --type-button-line: 1;
  --type-nav-size: .7rem;
  --type-nav-weight: 400;
  --type-nav-line: 1;
  --type-price-weight: 500;
  --type-price-line: 1;
  --type-price-tracking: normal;
  --type-meta-size: .8rem;
  --type-meta-weight: 400;
  --type-meta-line: 1;
  /* La barra es pegajosa, así que ocupa su hueco en el flujo antes de la
     portada: lo que mide una pantalla de portada es lo que queda por debajo. */
  --site-header-height: 52px;
  /* El aire que el móvil de la portada deja siempre por encima de sí mismo.
     Con solo el alto de la barra, en una pantalla baja y ancha la imagen
     crecía hasta rozarla; esto la detiene antes. */
  --max-width: 1240px;
  /* La distancia de cualquier título a su descripción. Vive en un solo sitio
     para que cambiarla los mueva todos a la vez. */
  --title-description-space: 20px;
  --page-padding: clamp(20px, 4vw, 64px);
  /* LOS DOS ANCHOS DE LA BARRA DEL PANEL, aquí y no en la propia barra: el
     contenido tiene que reservar su hueco y NO cuelga de ella, así que allí no
     podía verlos y su relleno caía siempre en el valor de respaldo escrito a
     mano. Con la barra fijada eso dejaba el contenido debajo de la barra. */
  --workspace-rail-width: 64px;
  --workspace-rail-open: 232px;
  --section-space: clamp(88px, 10vw, 152px);
  font-family: var(--font-ui);
  font-synthesis: none;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
}

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

html {
  scroll-padding-top: 52px;
  overflow-x: clip;
}

body {
  margin: 0;
  max-width: 100%;
  overflow-x: clip;
  background: var(--background);
  color: var(--text);
  font-size: var(--type-body-size);
  font-weight: var(--type-body-weight);
  line-height: var(--type-body-line);
}

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

a { color: inherit; text-decoration: none; }

img,
svg { display: block; max-width: 100%; }

h1,
h2,
h3,
p { margin: 0; }

h1,
h2,
h3 { text-wrap: balance; }

:is(
  .hero h1,
  .section-intro h2,
  .service h2,
  .detail-intro h1,
  .detail-block h2,
  .demo h2,
  .section-kicker,
  .plan-card-name,
  .plan-card-price,
  .legal-intro h1,
  .legal-section h2
) {
  color: var(--display-text);
  font-family: var(--font-display);
}

p { text-wrap: pretty; }

[hidden] { display: none !important; }

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

.skip-link {
  position: fixed;
  z-index: 200;
  top: 12px;
  left: 12px;
  padding: 10px 14px;
  border-radius: 4px;
  background: var(--black);
  color: var(--white);
  font-size: var(--type-button-size);
  font-weight: var(--type-button-weight);
  line-height: var(--type-button-line);
  transform: translateY(-160%);
}

.skip-link:focus { transform: translateY(0); }

.section-shell,
.site-header-inner {
  width: min(100%, calc(var(--max-width) + (var(--page-padding) * 2)));
  margin-inline: auto;
  padding-inline: var(--page-padding);
}

.site-header {
  position: sticky;
  z-index: 40;
  top: 0;
  min-height: 52px;
  background: var(--bar-material);
  color: var(--text);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  transition: background-color 200ms ease, border-color 200ms ease, color 200ms ease;
}

.site-header-inner {
  min-height: 51px;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
}

.brand {
  width: max-content;
  display: inline-flex;
  align-items: center;
  color: inherit;
}

/* EL ICONO DE LA BARRA ES UN ENLACE MÁS DE LA BARRA. Llevaba el negro puro
   mientras sus vecinos —Producto, Precio, Contacto— iban en #333333 y se
   ponían negros al pasar por encima, así que el logotipo se leía más fuerte que
   todo lo demás y no reaccionaba a nada. Mismo color de reposo, mismo negro al
   pasar y la misma transición de 200 ms: la única diferencia es que un color de
   texto aquí es un color de fondo, porque la silueta se recorta con `mask`. */
.brand-mark {
  width: 20px;
  height: 20px;
  display: block;
  background: #333333;
  -webkit-mask: url("./assets/foodev-logo.svg") center / contain no-repeat;
  mask: url("./assets/foodev-logo.svg") center / contain no-repeat;
  transition: background-color 200ms ease;
}

.brand:hover .brand-mark { background: #000000; }

.desktop-nav {
  --landing-nav-indicator-x: 0px;
  --landing-nav-indicator-w: 0px;
  position: relative;
  align-self: stretch;
  display: flex;
  align-items: center;
  gap: 0;
  color: #333333;
  font-size: var(--type-nav-size);
  font-weight: var(--type-nav-weight);
  line-height: var(--type-nav-line);
}

.desktop-nav a { transition: color 200ms ease; }

.desktop-nav a {
  height: 100%;
  padding-inline: 15px;
  display: flex;
  align-items: center;
}

.desktop-nav-label { display: block; }

.desktop-nav-indicator {
  position: absolute;
  z-index: 1;
  bottom: -1px;
  left: 0;
  width: var(--landing-nav-indicator-w);
  height: 1px;
  border-radius: 0;
  background: #000000;
  opacity: 1;
  transform: translateX(var(--landing-nav-indicator-x));
  transition: opacity 200ms ease;
  pointer-events: none;
}

.desktop-nav a:hover { color: #000000; }

.desktop-nav a.is-active,
.desktop-nav a[aria-current="location"] { color: #000000; }

/* LO ÚNICO PROPIO DE AQUÍ ES DÓNDE SE PONE Y CUÁNDO SE VE. El tamaño, el
   redondeo, el material, la sombra y el icono salen enteros de la cápsula
   compartida y de la ranura `data-foodev-icon`, exactamente como en Center.
   Antes esto dibujaba sus propias rayas a mano dentro de la cápsula, y entre
   su `display: grid` y el de la cápsula salía cualquier cosa. */
.mobile-menu-trigger {
  position: fixed;
  z-index: 60;
  top: max(12px, env(safe-area-inset-top));
  /* A LA MISMA DISTANCIA DEL BORDE QUE EL CONTENIDO. Llevaba 12 px fijos
     mientras el texto de la página empieza en `--page-padding`, así que las dos
     cápsulas flotaban más pegadas al filo que todo lo demás. */
  right: max(var(--page-padding), env(safe-area-inset-right));
  display: none;
}

/* La de volver es la MISMA cápsula, al otro lado y con el icono de volver. Se
   enseña con las mismas reglas que la de menú: en escritorio la barra lleva la
   marca, que ya lleva al inicio. */
.landing-back {
  position: fixed;
  z-index: 60;
  top: max(12px, env(safe-area-inset-top));
  left: max(var(--page-padding), env(safe-area-inset-left));
  display: none;
  color: var(--foodev-floating-capsule-color);
}

/* Las dos acciones de la barra, a la derecha, con «Regístrate» al final: es la
   acción, así que va donde cae la vista al terminar de leer. Es la cápsula
   negra que llevaba «Ver demo» hace tiempo, con el mismo redondeo completo. */
.header-actions {
  justify-self: end;
  display: inline-flex;
  align-items: center;
  gap: 14px;
}

.header-link {
  color: #333333;
  font-size: var(--type-nav-size);
  font-weight: var(--type-nav-weight);
  line-height: var(--type-nav-line);
  transition: color 200ms ease;
}

.header-link:hover { color: #000000; }

.header-action {
  min-height: 24px;
  padding: 0 var(--foodev-small-button-padding-inline);
  display: inline-flex;
  align-items: center;
  border-radius: 999px;
  background: var(--black);
  color: var(--white);
  font-size: var(--type-nav-size);
  font-weight: var(--type-button-weight);
  line-height: var(--type-button-line);
  white-space: nowrap;
}

/* Solo en escritorio: en cuanto la barra se compacta, manda el cajón, que ya
   lleva las dos entradas. */
html.landing-nav-compact .header-actions { display: none; }

@media (max-width: 900px) {
  .header-actions { display: none; }
}

/* «Servicios» abre hacia abajo y lo que se estira es LA BARRA ENTERA, no un
   panel flotante encima de la página: el desplegable es la misma superficie de
   la cabecera, que crece. Por eso el panel vive dentro de `.site-header` y
   comparte su fondo y su desenfoque en vez de pintarse los suyos.

   El alto se anima con `grid-template-rows: 0fr → 1fr`, que es lo que permite
   una transición suave hasta el alto real del contenido sin inventarse un
   `max-height` que se quedaría corto o largo. */
.header-services {
  position: relative;
  height: 100%;
  display: flex;
  align-items: center;
}

.header-services-trigger {
  height: 100%;
  padding: 0 15px;
  border: 0;
  display: inline-flex;
  align-items: center;
  /* La flecha va pegada a la palabra: 2 px. Más separada parecía un elemento
     suelto en vez de parte de «Servicios». */
  gap: 2px;
  /* El mismo peso que las demás entradas. Ser desplegable no lo hace más
     importante: la regla compartida que pone 500 a todo `<button>` se retira
     con `data-button-weight-override` en el marcado. */
  font-weight: var(--type-nav-weight);
  background: transparent;
  color: inherit;
  font: inherit;
  line-height: inherit;
  cursor: pointer;
  transition: color 200ms ease;
  -webkit-tap-highlight-color: transparent;
}

.header-services-trigger:hover,
.header-services-trigger[aria-expanded="true"] { color: #000000; }

.header-services-arrow {
  display: grid;
  place-items: center;
  line-height: 0;
  /* 1 px arriba: ópticamente el galón cuelga bajo respecto a la línea base de
     «Servicios», porque su tinta ocupa solo la mitad de abajo de su caja. */
  transform: translateY(-1px);
  transition: transform .34s cubic-bezier(.2, .8, .2, 1);
}

.header-services-arrow svg {
  width: 14px;
  height: 14px;
  display: block;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.header-services-trigger[aria-expanded="true"] .header-services-arrow {
  transform: translateY(-1px) rotate(180deg);
}

/* El panel NO empuja la página hacia abajo: se despliega ENCIMA, y lo que hay
   detrás se desenfoca. Por eso va `absolute` respecto a la cabecera y arrastra
   consigo el fondo de la barra —el mismo color y el mismo desenfoque—, de modo
   que sigue leyéndose como la barra estirada aunque ya no ocupe sitio. */
.header-services-panel {
  position: absolute;
  /* Se sube lo que sobra para que de «Servicios» a la primera fila haya el mismo
     hueco que entre filas. Ese sobrante es el aire que la barra deja bajo su
     texto, así que depende de su altura y del tipo: lo mide `landing.js` y lo
     deja en `--header-services-lift`. Sin medida no sube nada y se ve igual que
     antes, solo con más aire. */
  top: calc(100% - var(--header-services-lift, 0px));
  right: 0;
  left: 0;
  display: grid;
  grid-template-rows: 0fr;
  background: inherit;
  transition: grid-template-rows .38s cubic-bezier(.2, .8, .2, 1);
}

.header-services-panel > .header-services-panel-inner {
  min-height: 0;
  overflow: hidden;
}

.site-header.is-services-open .header-services-panel { grid-template-rows: 1fr; }

/* El panel sube y pisa una franja de la barra. Si las dos fueran translúcidas,
   esa franja acumularía dos capas y se vería una banda más clara, así que
   mientras el desplegable está abierto ambas van en sólido. Detrás ya hay
   desenfoque: no se echa de menos la transparencia. */
.site-header.is-services-open { background: #ffffff; }

/* El desenfoque va en el contenido, no en la barra: si se lo aplicara a un
   antepasado común, la propia cabecera se desenfocaría con él. Por eso son
   `main` y `footer` los que se difuminan, que es justo lo que queda detrás. */
.site-header.is-services-open ~ main,
.site-header.is-services-open ~ footer {
  filter: blur(16px);
  pointer-events: none;
}

main,
footer { transition: filter .38s cubic-bezier(.2, .8, .2, 1); }

@media (prefers-reduced-motion: reduce) {
  main,
  footer { transition-duration: .01ms !important; }
}

/* En vertical, uno debajo de otro: es una lista, y leerla en columna cuesta
   menos que en una fila que obliga a barrer la pantalla entera.

   Y arranca DEBAJO DE «Servicios», no en el borde de la página: así se ve de qué
   entrada cuelga. Ese desplazamiento no se puede escribir a mano porque la barra
   va centrada y su sitio depende del ancho, así que lo mide `landing.js` y lo
   deja en `--header-services-x`. Sin medida, cae a cero y la lista se queda a la
   izquierda: se sigue leyendo. */
.header-services-list {
  /* Sin relleno arriba: el hueco hasta la primera fila NO se cuadra aquí, sino
     subiendo el panel, porque lo que sobra no es de la lista sino de la barra
     —debajo de «Servicios» quedan ~26 px de barra vacía—. Lo mide `landing.js`. */
  padding-block: 0 18px;
  padding-left: var(--header-services-x, 0px);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0;
}

/* Apagadas respecto a las de la barra: son un segundo nivel, no entradas al
   mismo peso. El tono es `--muted`, el mismo que usa el resto de la landing
   para el texto secundario. */
.header-services-list a {
  padding: 9px 0;
  color: var(--muted);
  font-size: var(--type-nav-size);
  font-weight: var(--type-nav-weight);
  line-height: var(--type-nav-line);
  transition: color 200ms ease;
}

.header-services-list a:hover { color: #000000; }

@media (prefers-reduced-motion: reduce) {
  .header-services-panel,
  .header-services-arrow { transition-duration: .01ms !important; }
}

.landing-navigation-backdrop { --foodev-side-navigation-backdrop-layer: 12031; }
.landing-navigation-drawer { --foodev-side-navigation-layer: 12032; }

/* ENTRAR Y REGISTRARSE, PEGADOS ABAJO. No son secciones de la web: son las dos
   puertas de la cuenta, y en la misma fila que Inicio, Precio o Contacto se
   leían como una sección más. El cajón se convierte en columna y la lista
   crece, así que el pie cae al fondo sin fijarlo al borde de la pantalla —que
   se lo comería el teclado o la barra del navegador—. */
.landing-navigation-drawer {
  display: flex;
  flex-direction: column;
}

.landing-navigation-drawer .foodev-side-navigation-list {
  flex: 1 1 auto;
}

.landing-navigation-drawer .foodev-side-navigation-foot {
  margin-top: auto;
  padding-top: 24px;
  display: flex;
  flex-direction: column;
  gap: 0;
}
.landing-navigation-drawer .foodev-side-navigation-row {
  color: #333333;
}

/* En el cajón, «Regístrate» va siempre en negro con texto blanco: es la acción,
   no un enlace más. Las dos clases juntas en el selector —no solo la propia—
   son las que importan: con la misma especificidad que la regla genérica de
   arriba, el texto ganaba ella por venir después en la hoja y el blanco no se
   veía nunca sobre el fondo negro. */
.landing-navigation-drawer .foodev-side-navigation-row.foodev-side-navigation-row-primary {
  background: var(--black);
  color: var(--white);
}

/* Los servicios desplegados van apagados, como en la barra de escritorio: son un
   segundo nivel. Hacen falta las TRES clases en el selector por lo mismo de
   arriba: la regla compartida de `side-navigation.css` empata en especificidad
   con `.landing-navigation-drawer .foodev-side-navigation-row` y pierde por ser
   la landing la hoja que se carga después, así que el gris nunca se aplicaba. */
.landing-navigation-drawer .foodev-side-navigation-group-panel .foodev-side-navigation-row {
  color: var(--muted);
}

.foodev-overlay-scrollbar-thumb { color: #262626; }

.landing-section { width: 100%; }
/* Los fondos no se alternan: TODA la página es `--surface`. Las dos clases se
   conservan porque el HTML de las siete páginas las escribe, pero hoy pintan
   lo mismo. */
.section-white { background: var(--surface); }
.section-soft { background: var(--surface); }

/* En escritorio la portada mide la pantalla del dispositivo menos la barra:
   la barra es pegajosa y ya ha ocupado su hueco por encima, así que con
   `100svh` la portada sobresalía justo esos 64 px y el móvil se quedaba con el
   borde de abajo fuera de la pantalla. Apilada mide lo que haga falta para que
   el móvil se vea entero: recortarlo por abajo lo dejaba a medias. */
/* LA PORTADA: el texto quieto y los aparatos subiendo por encima.
   ---------------------------------------------------------------------
   Todo va centrado, en móvil y en escritorio. El título y el subtítulo se
   quedan pegados bajo la barra mientras se baja, y el portátil y el teléfono
   pasan por delante hasta taparlos. Ese tapado no es un truco de opacidad: el
   bloque de los aparatos lleva el FONDO OPACO de la página, así que cuando su
   borde de arriba alcanza al texto, el texto deja de verse y no vuelve a
   asomar entre el portátil y el teléfono. */
.hero {
  --hero-title-size: 5rem;
  /* ALTA DE SOBRA A PROPÓSITO. El título se queda quieto mientras los aparatos
     le pasan por encima, y para que le dé tiempo a desaparecer detrás de ellos
     hace falta recorrido: si la sección se acaba antes, el título deja de estar
     pegado y EMPIEZA A SUBIR todavía a la vista, que es el salto que se veía.
     El recorrido que hace falta es, más o menos, dos veces el alto del bloque
     de texto más medio aparato; con la pantalla justa no llegaba ni de lejos en
     un móvil, donde el texto ocupa el doble y el portátil la mitad. */
  min-height: calc(100svh - var(--site-header-height));
  padding-bottom: var(--section-space);
  /* Y lo que sobre por debajo lo tapa la banda, que se estira hasta aquí. Es
     `clip` y no `hidden` a posta: `hidden` convertiría esto en un contenedor de
     desplazamiento y el título dejaría de pegarse a la ventana. */
  overflow: clip;
  text-align: center;
}

.hero-inner {
  /* UNA SOLA DISTANCIA en el bloque de texto: del título al subtítulo, y el
     doble del subtítulo a los botones, que ahí cambia lo que se está leyendo. */
  --hero-copy-gap: 16px;
  --hero-action-gap: calc(var(--hero-copy-gap) * 2);
  /* El párrafo del subtítulo termina en su propia caja, no en su texto: el
     interlineado deja un margen invisible bajo la última línea, y sin
     descontarlo el hueco hasta los botones se ve más largo de lo que mide. */
  --hero-description-leading-fix: 4px;
  /* Se queda quieto justo debajo de la barra, que es pegajosa y mide lo que
     mide. El respiro de más es el mismo que separa el texto del borde de
     arriba cuando la portada todavía no se ha movido. */
  position: sticky;
  top: calc(var(--site-header-height) + clamp(20px, 4vh, 56px));
  z-index: 0;
  padding-block: clamp(32px, 6vh, 80px) 0;
  display: grid;
  justify-items: center;
  text-align: center;
}

/* EL ANCHO DEL TEXTO SALE DEL DIBUJO, como el de los aparatos. */
.hero-copy {
  /* EL TOPE SUBIÓ AL ANCHO DEL GRUPO DE APARATOS, no al de la pantalla del
     portátil. Con la frase corta de antes —«La herramienta que necesitas»— el
     741 px de la pantalla sobraba; con una frase que dice de verdad qué es
     Foodev, ese ancho la partía en renglones cortos en escritorio. Sigue
     atado al dibujo: lo que manda ahora es dónde se detiene el grupo entero. */
  max-width: min(100%, 900px);
  display: grid;
  gap: var(--hero-copy-gap);
  justify-items: center;
  min-width: 0;
}

/* EL LOGO ENCIMA DEL TITULAR, y quieto con él: los dos son lo mismo, la firma
   de la portada, y separarlos haría que uno se fuera y el otro se quedara. */
/* MIDE LO QUE MIDE EL TITULAR, en las dos pantallas: los dos son la firma de la
   portada y con tamaños distintos uno parecía un adorno del otro. Sale del mismo
   token, así que cambiar el titular mueve el logo con él. */
/* Y VISTE EL COLOR DEL TITULAR, no un negro puro que no está en ninguna otra
   parte de la portada. Era un `<img>`, y un SVG cargado así se pinta con su
   propio color: por muy `currentColor` que declare dentro, dentro de un `<img>`
   eso resuelve a negro y no hay CSS de fuera que lo alcance. Ahora es una
   silueta recortada con `mask`, así que lo que se ve es el fondo del elemento y
   el fondo es el token del titular. */
.hero-logo {
  width: var(--hero-title-size);
  height: var(--hero-title-size);
  margin-bottom: 4px;
  display: block;
  background: var(--display-text);
  -webkit-mask: url("./assets/foodev-logo.svg") center / contain no-repeat;
  mask: url("./assets/foodev-logo.svg") center / contain no-repeat;
}

/* EL SUBTÍTULO Y LOS BOTONES VAN DEBAJO DE LOS APARATOS, y bajan con la página
   como cualquier otra cosa: lo único que se queda quieto es el logo y el
   titular. Viven DENTRO del bloque de los aparatos a propósito —no detrás de
   él— porque la banda que tapa el titular es un pseudoelemento de los aparatos
   con `z-index: -1`: siendo hermanos suyos se pintan por delante, y fuera del
   bloque se los tragaría esa misma banda. */
.hero-below {
  display: grid;
  justify-items: center;
  /* Sin hueco: la llamada tiene que leerse como el RENGLÓN SIGUIENTE del
     subtítulo, no como un bloque aparte, y comparte con él tamaño, interlínea e
     interletrado. Lo único que la distingue es el color. */
  gap: 0;
  margin-top: clamp(40px, 6vh, 72px);
  text-align: center;
}

/* La llamada de la portada es el mismo enlace de flecha que abre cada servicio
   más abajo —mismo color y misma flecha—, pero con la medida del subtítulo que
   tiene encima: es su continuación, no un pie de página. Su margen propio sobra
   porque aquí lo pone el hueco de la retícula. */
/* Ya no hace falta declararle medida: la hereda del enlace de flecha, que ahora
   lleva la de Descripción. Lo único suyo es cuánto aire deja por encima. Se
   nombran las DOS clases porque `.landing-arrow-link` se declara más abajo en
   esta misma hoja y ganaría por orden. */
.landing-arrow-link.hero-arrow-link { margin-top: 1.5rem; }

/* El hueco de la retícula es el pequeño; aquí se le suma lo que falta hasta el
   doble y se descuenta el interlineado que le sobra al subtítulo bajo su última
   línea, para que la distancia VISIBLE sea exactamente el doble. */
.hero-copy .hero-actions {
  margin-top: calc(var(--hero-action-gap) - var(--hero-copy-gap) - var(--hero-description-leading-fix));
}

/* La banda que tapa el texto va por delante del bloque de texto, pero NO
   empieza donde empieza esta caja: arranca donde EMPIEZA la base del portátil
   (la pinta `.hero-devices::after`). Por encima de esa línea no hace falta: lo
   que tapa el título ahí es el propio portátil, que es opaco. */
.hero-stage {
  /* LA PORTADA SE DESPIDE COMO UNA SECCIÓN. Entre dos secciones hay el relleno
     de abajo de una MÁS el de arriba de la otra; la portada no ponía el suyo, y
     por eso de su llamada a la primera sección había casi la mitad de aire que
     entre dos secciones cualesquiera. Ahora pone el mismo `--section-space` que
     cualquiera, y ese es todo el aire que hay debajo: el que ponía el bloque de
     los aparatos se retira para no sumar dos. */
  --hero-stage-bottom: 0px;
  position: relative;
  z-index: 1;
  margin-top: clamp(72px, 12vh, 148px);
  padding-inline: var(--page-padding);
  padding-bottom: var(--hero-stage-bottom);
}

/* LAS TRES MEDIDAS DE LA COMPOSICIÓN, y las tres salen del propio dibujo.
   ---------------------------------------------------------------------
   · La proporción del portátil es la del archivo recortado a su tinta.
   · Lo que se alinea con el BORDE DERECHO DE LA PANTALLA del portátil —el
     91,113 % del archivo— es el ICONO DE LA BATERÍA del teléfono, que cae en
     el 84,6 % de su propio ancho. Puesto por su borde derecho el teléfono
     quedaba justo a ras de la pantalla y se leía plano; adelantado esos tres
     puntos se separa y se pone por delante. Las dos cifras están medidas sobre
     los archivos recortados, no puestas a ojo.
   · Su alto es el que le tocaría estando los dos en la misma mesa: un MacBook
     de 16 pulgadas mide 355,7 mm de ancho y un iPhone, 149,6 mm de alto, y esa
     misma razón aplicada al dibujo da el 69,63 % del alto del portátil. No es
     un número a ojo: es lo que hace que la escena parezca una foto.

   Aun adelantado, el teléfono cabe entero dentro del portátil —acaba en el
   94,25 %—: el grupo mide exactamente lo que mide el portátil y no vuela por
   ningún lado. Por eso no hay ni desplazamiento que corregir ni sombra que se
   salga de la caja. El tope de ancho es el de la página: el mismo
   `--max-width` y el mismo `--page-padding` que respeta cualquier otra
   sección, que los pone `.hero-stage`. */
.hero-devices {
  --hero-screen-right: 91.113%;
  --hero-phone-battery: .846;
  --hero-phone-height: 69.63%;
  --hero-phone-width: 20.38%;
  position: relative;
  /* MÁS GRANDES QUE LA PANTALLA SI HACE FALTA: se ven mejor aunque no quepan
     enteros de una vez. El tope sigue siendo el ancho útil de la página, el
     mismo `--max-width` que respeta cualquier otra sección. */
  width: min(100%, var(--max-width));
  margin-inline: auto;
  aspect-ratio: 2048 / 1237;
}

/* El fondo opaco que se traga el título, DESDE DONDE EMPIEZA LA BASE DEL
   PORTÁTIL. Arrancaba a media altura y ahí sobraba —lo que tapa el título por
   encima es el propio portátil, que es opaco—, y luego al 100 %, que es el
   suelo: entre el canto de arriba de la base y el suelo hay una franja de
   aparato con la que el título se cruzaba en lugar de desaparecer contra el
   canto.

   EL 93,39 % ESTÁ MEDIDO EN EL ARCHIVO, no puesto a ojo: recorriendo el dibujo
   fila a fila, el ancho de píxel opaco salta de 639 a 777 px en la fila 438 de
   469, que es exactamente donde la tapa termina y empieza la base, que es más
   ancha. Si el dibujo cambia, se vuelve a medir; no se ajusta a ojo.

   Se estira hasta los bordes de la pantalla porque el título es más ancho que
   los aparatos, y llega hasta abajo del todo de la caja. Va en `z-index: -1`
   para quedarse DETRÁS de los aparatos y de su sombra, y aun así por delante
   del texto: `.hero-stage` abre su propio contexto de apilado, así que el -1 no
   se escapa más atrás que ella. */
.hero-devices::after {
  content: "";
  position: absolute;
  /* Hasta abajo del todo de la portada, no hasta el borde del bloque: en una
     pantalla alta la sección mide más que su contenido y en ese sobrante se
     veía el título quieto, con los botones asomando por debajo de los aparatos.
     Lo que corta la banda es el `overflow: clip` de la portada. */
  inset: 93.39% calc(50% - 50vw) -200vh;
  z-index: -1;
  background: var(--surface);
  pointer-events: none;
}

/* LA SOMBRA DE LA MESA: UNA POR APARATO, y la proyecta el propio aparato.
   ---------------------------------------------------------------------
   `drop-shadow` recorta la sombra con la silueta del archivo, así que sale sola
   del dibujo: no hay que decirle dónde apoya el portátil ni dónde el teléfono,
   ni colocar manchas a mano. Y como el desplazamiento es SOLO VERTICAL, por los
   costados no asoma nada —esos bordes son verticales— y por abajo asoma
   siempre la misma altura de punta a punta. Eso es lo que antes no se conseguía:
   con elipses la sombra bajaba más por el centro que por los extremos.

   Aquí vivieron cinco degradados radiales que dibujaban la penumbra del cuerpo,
   el contacto de cada pata y el del teléfono. Se retiraron enteros: eran cinco
   manchas puestas a mano para imitar lo que la silueta ya sabe hacer.

   Un `filter` saca a estos dos a una capa de composición aparte. Aquí no
   importa —la portada no los anima, solo se desplazan con la página— y es lo
   que costó la sombra del tique NUEVO, que sí vivía dentro de una animación. */
.hero-device {
  position: absolute;
  display: block;
}

.hero-device-laptop {
  inset: 0;
  width: 100%;
  height: 100%;
  /* El seguro de que no se deforme: con la proporción declarada en la caja,
     cualquier tope que llegue de fuera encoge la caja entera en vez de
     estrujar el dibujo. */
  object-fit: contain;
}

/* LA SOMBRA DEL PORTÁTIL: UNA FRANJA DE ALTURA CONSTANTE bajo toda su base.
   ---------------------------------------------------------------------
   Aquí había un `drop-shadow`, y un `drop-shadow` recorta la sombra con la
   SILUETA: las patas sobresalen por debajo del chasis, así que bajo ellas la
   sombra llegaba más abajo que en el resto y se leían dos pegotes. Un portátil
   apoyado en una mesa no hace eso.

   Lo que sí da altura constante es un degradado LINEAL vertical: se apaga hacia
   abajo igual en todo el ancho, sin depender de por dónde asome el dibujo. Los
   extremos los suaviza una máscara horizontal, para que la franja no empiece ni
   acabe en un canto. Y es muy corta —medio punto porcentual del alto del
   grupo—: una sombra corta dice «apoyado» y una larga dice «flotando». */
.hero-devices::before {
  content: "";
  position: absolute;
  z-index: 1;
  left: 0;
  right: 0;
  top: 100%;
  height: .55%;
  background: linear-gradient(to bottom, rgb(17 17 17 / 34%), rgb(17 17 17 / 0%));
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 4%, #000 96%, transparent 100%);
  mask-image: linear-gradient(to right, transparent 0, #000 4%, #000 96%, transparent 100%);
  pointer-events: none;
}

/* Los dos apoyan en la misma línea, y eso es todo lo que hace falta decir:
   los archivos vienen recortados a su tinta, así que su borde de abajo ES el
   borde de abajo del aparato. */
.hero-device-phone {
  left: calc(var(--hero-screen-right) - var(--hero-phone-width) * var(--hero-phone-battery));
  bottom: 0;
  width: var(--hero-phone-width);
  height: var(--hero-phone-height);
  object-fit: contain;
  object-position: bottom left;
}

/* LA SOMBRA DEL TELÉFONO ES OTRA FRANJA, la misma idea que la del portátil.
   Aquí había un `drop-shadow`, y un `drop-shadow` con desenfoque no cae solo
   hacia abajo: se abre 1,5 px a cada lado de toda la silueta, así que el
   teléfono salía perfilado de sombra por los costados y por la base, y solo
   limpio por arriba. Una franja bajo su base no tiene costados que perfilar.
   Va en el hueco exacto del aparato, que ocupa su caja entera —comprobado en
   el navegador: el dibujo mide lo mismo que su caja—, y es más densa y más
   corta que la del portátil porque apoya en mucho menos sitio. */
.hero-phone-shadow {
  position: absolute;
  z-index: 1;
  bottom: 0;
  left: calc(var(--hero-screen-right) - var(--hero-phone-width) * var(--hero-phone-battery));
  width: var(--hero-phone-width);
  height: .5%;
  transform: translateY(100%);
  background: linear-gradient(to bottom, rgb(17 17 17 / 52%), rgb(17 17 17 / 0%));
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 10%, #000 90%, transparent 100%);
  mask-image: linear-gradient(to right, transparent 0, #000 10%, #000 90%, transparent 100%);
  pointer-events: none;
}

.hero h1 {
  color: var(--display-text);
  font-size: var(--hero-title-size);
  font-weight: var(--type-display-weight);
  letter-spacing: var(--type-display-tracking);
  line-height: var(--type-display-line);
}

/* EL SUBTÍTULO DE LA PORTADA ES TEXTO NORMAL, no un segundo titular. Llevaba el
   estilo de subtítulo —1,5 rem y medio píxel de interletrado negativo—, que a
   dos líneas competía con el título que tiene encima. Con el estilo de cuerpo,
   que ya existe y lo usa el resto de la landing, el título manda y esto se lee
   como lo que es: la explicación. */
/* Estrecho para que se lea de un vistazo, pero no tanto como para partirlo en
   renglones cortos: 46 caracteres dejaban tres líneas muy sueltas en
   escritorio. El tope de arriba —el ancho de la pantalla del portátil— sigue
   mandando cuando la ventana se estrecha. */
/* El subtítulo de la portada ES el estilo Descripción, el mismo que la frase
   que acompaña a cada título más abajo: se declara con ellas ahí arriba y aquí
   solo queda lo que de verdad es suyo. Tuvo medida propia —1,3 rem, interlínea
   1,55— que era la de Descripción con otro nombre. */
.hero-description {
  max-width: 68ch;
  /* Su aire por arriba lo pone el bloque que lo contiene, no él. */
  margin-top: 0;
}

.hero-actions {
  margin-top: 30px;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px;
}

.hero-actions .button {
  min-height: 52px;
  padding-inline: 28px;
  border-radius: 999px;
}

.button {
  min-height: 52px;
  padding: 0 28px;
  border: 0;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  font-size: var(--type-button-size);
  font-weight: var(--type-button-weight);
  line-height: var(--type-button-line);
}

/* TODOS los botones de la landing van a 400. Es el estándar de estas páginas:
   un botón no pesa más que el texto que lo rodea.

   `standard-sheet.css` sube a 500 cualquier `<button>` y lo hace con
   `!important` y con un `:not(#id)` que le da peso de identificador, porque en
   el producto privado ese es el estándar contrario. Para devolverlo aquí no
   basta con `!important`: hay que pesar más que aquel selector, y por eso este
   arrastra las mismas negaciones y una más. Se aplica al vocabulario propio de
   la landing, no a `button` a secas, para no tocar los componentes compartidos
   —filas de selector, acciones de aviso— que sí quieren su 500. */
html body :is(
  .button,
  .header-link,
  .header-action,
  .header-services-trigger,
  .mobile-menu-trigger,
  .primary-button,
  .secondary-button
):not(#foodev-button-weight-override):not(.foodev-selection-option):not(.foodev-select-option):not(.foodev-connected-action):not(.foodev-settings-row) {
  font-weight: var(--type-button-weight) !important;
}

html body :is(
  .button,
  .header-link,
  .header-action,
  .header-services-trigger,
  .mobile-menu-trigger,
  .primary-button,
  .secondary-button
):not(#foodev-button-weight-override):not(.foodev-selection-option):not(.foodev-select-option):not(.foodev-connected-action):not(.foodev-settings-row) :where(.button-label, .desktop-nav-label) {
  font-weight: var(--type-button-weight) !important;
}

.button-pill { border-radius: 999px; }
.button-primary { background: var(--black); color: var(--white); }
/* El secundario se dibuja con los TOKENS, no con negro literal. Con `#000000`
   escrito a mano, en modo oscuro era una línea negra sobre fondo casi negro:
   el botón existía y no se veía. `--black` y `--white` se intercambian con el
   tema, que es para lo que están. */
.button-secondary { border: 0; background: transparent; color: var(--black); box-shadow: inset 0 0 0 1px var(--black); }

:is(.button, a, button, input, textarea, summary):focus,
:is(.button, a, button, input, textarea, summary):focus-visible {
  outline: 0;
  box-shadow: none;
}

/* LOS BOTONES CUYO BORDE ES UNA SOMBRA vuelven a declararlo al recibir el foco.
   La regla de arriba quita la sombra para matar el anillo del navegador y de
   paso se llevaba el borde, y eso se ve al CERRAR un sheet: el estándar
   devuelve el foco al botón que lo abrió, así que el idioma del pie se quedaba
   sin contorno hasta que se tocaba otra cosa. */
.button-secondary:is(:focus, :focus-visible),
.site-footer-language:is(:focus, :focus-visible) {
  box-shadow: inset 0 0 0 1px currentColor !important;
}

:is(a, button, input, textarea, summary) { -webkit-tap-highlight-color: transparent; }


.product,
.service,
.pricing,
.faq,
.demo,
.contact,
.signup,
.account { padding-block: var(--section-space); }

/* Producto es la frase que recibe a quien baja de la portada, y ocupa una
   pantalla entera con el texto centrado en ella. El relleno vuelve a ser igual
   arriba y abajo: llevaba el doble arriba para compensar que el móvil de la
   portada termina pegado al borde, y con la frase centrada en la pantalla ese
   doble solo la bajaba del centro. */
.product {
  min-height: 100svh;
  padding-block: var(--section-space);
  display: grid;
  align-content: center;
}

.section-intro {
  max-width: 820px;
  margin-bottom: clamp(72px, 9vw, 120px);
}

.section-kicker {
  margin: 0 0 16px;
  color: var(--display-text);
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: var(--type-display-weight);
  letter-spacing: var(--type-display-tracking);
  line-height: var(--type-display-line);
}

.section-intro-compact { margin-bottom: clamp(44px, 6vw, 70px); }

.section-intro h2,
.demo h2 {
  color: var(--display-text);
  font-size: var(--type-display-size);
  font-weight: var(--type-display-weight);
  letter-spacing: var(--type-display-tracking);
  line-height: var(--type-display-line);
}

.section-intro > p:not(.section-kicker),
.landing-lead,
.hero-description {
  max-width: 650px;
  margin-top: var(--title-description-space);
  color: var(--description);
  font-size: var(--type-description-size);
  font-weight: var(--type-description-weight);
  letter-spacing: var(--type-description-tracking);
  line-height: var(--type-description-line);
}

/* La retícula de dos lados que comparten las secciones de servicio de la
   portada y los bloques de sus páginas: texto a un lado, imagen al otro. El
   lado se alterna para que varias seguidas no se lean como una lista, y
   apiladas van siempre texto y después imagen, que es el orden en que se leen.
   El reflejo mueve solo el texto, así que el marcado no cambia de orden y quien
   navega con teclado o lector recorre siempre título, texto, enlace, imagen. */
.landing-split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: center;
  gap: clamp(40px, 6vw, 96px);
}

.landing-split-copy { min-width: 0; }
.landing-split-mirrored .landing-split-copy { order: 2; }

.service h2 {
  color: var(--display-text);
  font-size: var(--type-display-size);
  font-weight: var(--type-display-weight);
  letter-spacing: var(--type-display-tracking);
  line-height: var(--type-display-line);
}

/* El enlace a la página del servicio: mismo azul que los contactos del pie, y
   la flecha del catálogo compartido en vez de un glifo propio. */
/* LA MISMA DISTANCIA PARA TODO. De la descripción a su enlace hay exactamente
   lo mismo que del título a la descripción: un solo hueco declarado en un solo
   sitio en vez de un 32 escrito aquí a mano. Y la misma medida que la
   descripción que tiene encima, porque es su continuación, no un botón. */
.landing-arrow-link {
  margin-top: var(--title-description-space);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--landing-action);
  font-size: var(--type-description-size);
  font-weight: var(--type-description-weight);
  letter-spacing: var(--type-description-tracking);
  line-height: var(--type-description-line);
}

.landing-arrow-link:hover { text-decoration: underline; text-underline-offset: 3px; }

.landing-arrow-link > span,
.landing-arrow-link svg {
  width: 20px;
  height: 20px;
  flex: 0 0 20px;
}

.landing-arrow-link svg {
  display: block;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Hueco reservado para una imagen que todavía no existe. Dentro va escrito qué
   imagen tiene que ir ahí, así que sustituirla es cambiar el bloque entero por
   un `img` sin tocar nada más. */
.landing-placeholder {
  --landing-placeholder-ratio: 4 / 3;
  min-width: 0;
  aspect-ratio: var(--landing-placeholder-ratio);
  padding: 32px;
  display: grid;
  place-content: center;
  background: var(--surface-card);
}

.landing-placeholder p {
  max-width: 34ch;
  color: var(--muted);
  font-size: var(--type-body-size);
  font-weight: var(--type-body-weight);
  line-height: var(--type-body-line);
  text-align: center;
  text-wrap: pretty;
}

/* Las páginas de servicio. La entrada presenta el servicio, cada bloque cuenta
   una parte concreta y el cierre invita a probarlo. La retícula de dos lados y
   el marcador de imagen son los de arriba: aquí solo se declara lo propio. */
.detail-block { padding-block: var(--section-space); }

/* La entrada de una página de servicio no lleva descripción: son el rótulo y el
   enunciado, solos, ocupando la pantalla entera y centrados en sus dos ejes.
   Es la primera pantalla de la página, no un bloque más.

   El centrado es el de la PANTALLA, no el del hueco que queda bajo la barra.
   La sección empieza donde termina la barra, así que centrar dentro de ella
   dejaba el texto medio alto de barra por debajo del centro visual: se veía
   caído. El relleno de abajo se lleva ese alto de más y lo sube justo eso. */
.detail-intro {
  /* LA PORTADA DE UN SERVICIO ES UNA ACUARELA, Y LA ACUARELA ES UNA IMAGEN.
     -------------------------------------------------------------------------
     El dibujo son ocho manchas de contorno irregular —nada de elipses—, cada
     una con el borde roto por un ruido fractal y desenfocada para que sangre.
     Todo eso se resuelve UNA VEZ, fuera del navegador
     (`scripts/generar-acuarela.mjs`), y lo que viaja aquí es el resultado: 7 KB
     de AVIF con WebP de respaldo.

     Estuvo escrito como un SVG dentro de la hoja, y tenía dos problemas. El
     grande: el filtro se calculaba en cada visita, tardaba lo suyo, y mientras
     tanto la portada se quedaba del verde plano de debajo —un parpadeo verde en
     la primera pantalla—. Y el otro: un `data:` dentro del CSS no existe hasta
     que la hoja se ha descargado y analizado, así que no se puede pedir por
     adelantado. Siendo un archivo, cada página de servicio lo precarga en su
     cabecera y llega con el primer pintado.

     El color de respaldo es el PROMEDIO de la imagen, no el verde de la marca:
     si aun así quedara un hueco entre el primer pintado y la imagen, lo que se
     ve es un tono que ya está dentro de la acuarela y el cambio no se nota. Lo
     calcula el mismo script que dibuja.

     Y como es una imagen se coloca como una imagen: `cover` centrado. Una
     pantalla estrecha la RECORTA; nunca la deforma, que es lo que le pasaba al
     degradado medido en porcentajes. */
  position: relative;
  isolation: isolate;
  overflow: hidden;
  min-height: calc(100svh - var(--site-header-height));
  padding-top: var(--section-space);
  padding-bottom: calc(var(--section-space) + var(--site-header-height));
  display: grid;
  align-content: center;
  background-color: #546713;
  background-image: url("./assets/landing/acuarela-servicio.webp");
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
}

/* Donde se entienda AVIF, la mitad de peso por la misma imagen. Va en un
   `@supports` y no en un `image-set` suelto porque un navegador que no sepa
   leer la función descarta la declaración entera y se quedaría sin fondo. */
@supports (background-image: image-set(url("x.avif") type("image/avif"))) {
  .detail-intro {
    background-image: image-set(
      url("./assets/landing/acuarela-servicio.avif") type("image/avif"),
      url("./assets/landing/acuarela-servicio.webp") type("image/webp")
    );
  }
}

/* EL GRANO, sobre la acuarela: una tesela de 160 px de ruido generada una sola
   vez y repetida. Es el papel, y va por encima del dibujo pero por debajo del
   texto. */
.detail-intro::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: 0;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.7' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23g)'/%3E%3C/svg%3E");
  background-size: 160px 160px;
  background-repeat: repeat;
  opacity: .5;
  mix-blend-mode: overlay;
}

/* El rótulo y el enunciado, en blanco: es el único color que se lee limpio
   sobre las ocho manchas, que van del amarillo claro al verde oscuro. */
.detail-intro .section-kicker,
.detail-intro h1 { color: #ffffff; }

.detail-intro > .section-shell { position: relative; z-index: 1; width: 100%; text-align: center; }

.detail-intro h1 {
  max-width: 900px;
  margin-inline: auto;
  font-size: var(--type-display-size);
  font-weight: var(--type-display-weight);
  letter-spacing: var(--type-display-tracking);
  line-height: var(--type-display-line);
}

/* El primer punto lleva el hueco DOBLE por arriba, porque es el único que no
   tiene un vecino que ponga la otra mitad. Entre dos puntos la distancia son
   dos huecos de sección —el de abajo del primero y el de arriba del segundo—,
   mientras que la portada termina justo en su borde y no aporta ninguno: con un
   solo hueco, el primer punto empezaba a la mitad de distancia que todos los
   demás. Es la misma cuenta que hace el cierre por abajo. */
.detail-intro + .detail-block {
  padding-top: calc(var(--section-space) * 2);
}

/* Y el cierre deja hasta el pie el mismo aire que hay entre el último bloque y
   él: dos huecos de sección, porque ahí se suman el de abajo del bloque y el de
   arriba del cierre. Con uno solo el pie parecía subírsele encima. */
.detail-close {
  padding-top: var(--section-space);
  padding-bottom: calc(var(--section-space) * 2);
}

/* El enunciado de cada bloque de servicio: el titular y su continuación en
   gris. Comparten familia, tamaño, peso e interlínea, así que se leen como una
   sola frase de dos colores. La continuación no lleva margen propio: con la
   misma interlínea, su primera línea cae del titular exactamente a la distancia
   que separa dos líneas del propio titular. Cambiar la interlínea mueve las dos
   cosas a la vez y la relación se mantiene sola. */
.detail-block h2,
.detail-block .landing-lead {
  font-family: var(--font-display);
  font-size: var(--type-statement-size);
  font-weight: var(--type-statement-weight);
  letter-spacing: var(--type-statement-tracking);
  line-height: var(--type-statement-line);
}

.detail-block .landing-lead {
  max-width: none;
  margin-top: 0;
  color: var(--statement-muted);
}

.detail-close-inner { text-align: center; }

.detail-close h2 {
  max-width: 760px;
  margin-inline: auto;
  color: var(--display-text);
  font-family: var(--font-display);
  font-size: var(--type-display-size);
  font-weight: var(--type-display-weight);
  letter-spacing: var(--type-display-tracking);
  line-height: var(--type-display-line);
}

.detail-close-actions {
  margin-top: clamp(28px, 4vw, 44px);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 10px;
}

.landing-expand-symbol {
  position: relative;
  display: block;
}

.landing-expand-symbol::before,
.landing-expand-symbol::after {
  position: absolute;
  top: 50%;
  left: 50%;
  border-radius: 999px;
  content: '';
  background: currentColor;
  transform: translate(-50%, -50%);
  transform-origin: center;
}

.demo {
  position: relative;
  isolation: isolate;
  background: var(--surface);
  color: var(--text);
}

/* Precio ya no es una sección oscura: la landing es clara de principio a fin. */
.pricing {
  position: relative;
  isolation: isolate;
  background: var(--surface);
  color: var(--text);
  padding-bottom: var(--section-space);
}


.pricing > .section-shell,
.demo > .section-shell {
  position: relative;
  z-index: 1;
}

/* El rótulo y el título de Precio van centrados, como en cualquier sección.
   Este selector se quedó pegado al de la retícula de abajo en una edición, y el
   título heredaba `display: grid` con dos columnas: el texto caía en la
   estrecha y se partía palabra a palabra. */
.pricing .section-intro { margin-inline: auto; text-align: center; }
.pricing .section-intro h2 { max-width: 100%; }

/* En escritorio las dos columnas miden lo que ocupan y el par queda centrado
   en la página. Con columnas proporcionales, la lista se estiraba hasta el
   borde y sus divisores acababan a un palmo del texto más largo. */
/* El alta de cliente. Reutiliza el grupo de campos del acceso privado, igual
   que Contacto: no se dibuja un formulario propio para cada página. */
/* El alta y el acceso ocupan al menos la pantalla entera aunque su contenido
   sea corto, y entonces va centrado en la altura. Sin esto el formulario se
   quedaba pegado arriba y el pie subía a media pantalla. */
.signup {
  min-height: calc(100svh - var(--site-header-height));
  display: grid;
  align-content: center;
}

/* El alta y el acceso son pantallas sin barra ni pie: solo el contenido. Sin
   barra encima no hay nada que descontar, así que la sección mide la pantalla
   entera y su contenido queda centrado en ella. */
.landing-page-bare .signup {
  min-height: 100svh;
}

/* El alta va centrada entera: título, frase del plan y formulario. */
.signup .section-intro {
  margin-inline: auto;
  text-align: center;
}

.signup-form {
  width: min(420px, 100%);
  margin-inline: auto;
  display: grid;
  gap: 16px;
  text-align: left;
}

/* `margin-inline: auto` no sobra: una regla general limita a 650 px los
   párrafos del rótulo, y sin centrar esa caja el texto quedaba centrado dentro
   de ella pero la caja pegada a la izquierda. */
/* La medida y el margen se declaran con el rótulo delante porque la regla
   general de las descripciones —`.section-intro > p:not(.section-kicker)`— pesa
   más que el nombre a secas y le imponía sus 650 px, sus 20 px y su tracking.
   La medida es la MISMA que la del formulario, no una propia: los dos bloques
   son la misma columna y con anchos distintos se veían desalineados. */
.signup .section-intro > .signup-plan {
  max-width: none;
  width: min(420px, 100%);
  margin-top: 12px;
  font-size: 1rem;
  letter-spacing: normal;
}

.signup-plan {
  margin-inline: auto;
  color: var(--muted);
  font-size: 1rem;
  letter-spacing: normal;
  text-align: center;
}

.signup-plan strong { color: var(--text); font-weight: 600; }
.signup-plan a { color: inherit; text-decoration: underline; }

/* La raya que separa las dos vías, con el rótulo encima de la línea y no al
   lado: así aguanta cualquier ancho sin partirse. */
/* La dirección y su terminación fija comparten fila: el sufijo no es editable
   porque todos los dominios acaban igual, así que no se pide, se enseña. */
.signup-domain {
  display: flex;
  align-items: baseline;
  gap: 2px;
  min-width: 0;
}

.signup-domain input { flex: 1 1 auto; }

.signup-domain-suffix {
  flex: 0 0 auto;
  color: var(--muted);
  font-size: 1rem;
}

.signup-hint {
  color: var(--muted);
  font-size: var(--type-meta-size);
  line-height: 1.45;
}

.signup-consent {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--description);
  font-size: .92rem;
  line-height: 1.35;
  cursor: pointer;
}

.signup-consent a { color: inherit; text-decoration: underline; }

.signup-consent input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}

/* Cierra el grupo de campos, igual que el de Contacto: mismo ancho y sin
   redondeo, para que los dos se lean como una sola pieza. */
.signup-send {
  width: 100%;
  border-radius: 0;
  background: var(--black);
  color: var(--white);
}

/* La segunda vía: entrar con una cuenta que ya existe. Comparte el ancho del
   botón principal y su falta de redondeo, para que los dos cierren el grupo. */
.signup-secondary {
  width: 100%;
  border-radius: 0;
  justify-content: center;
}

/* La bienvenida cubre la pantalla entera, cabecera y pie incluidos: por eso es
   `position: fixed` y no le importa dónde caiga en el documento. Aparece tras
   crear la cuenta, así que el resto queda `inert` mientras dura. Sin `hidden`
   un lector de pantalla la seguiría anunciando de fondo aunque `opacity` la
   borre a la vista; con `hidden` desaparece del árbol de accesibilidad del
   todo, y `.is-open` es solo lo que dispara el fundido.

   Es una pantalla NORMAL: fondo blanco, texto negro y el botón primario de
   siempre. Aquí vivió un acabado de metal —chapa de tres capas, grano fractal
   en `soft-light` y un filtro SVG que grababa el logo y el titular— y se
   retiró entero, con su `#foodev-grabado` y su `.foodev-filter-defs`. No era
   una decoración más: era un tema propio que no existe en ningún otro sitio del
   producto, y esta pantalla es lo primero que se ve de él. */
.signup-welcome {
  position: fixed;
  inset: 0;
  z-index: 500;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 22px;
  padding: 32px;
  background: var(--white);
  color: var(--display-text);
  text-align: center;
  opacity: 0;
  transition: opacity .5s cubic-bezier(.15, 1, .4, 1);
}

.signup-welcome.is-open { opacity: 1; }
.signup-welcome:focus { outline: none; }

.signup-welcome-mark {
  width: 76px;
  height: 76px;
  margin-bottom: 2px;
  object-fit: contain;
}

.signup-welcome h1 {
  max-width: 22ch;
  color: var(--display-text);
  font-family: var(--font-display);
  font-size: clamp(2.5rem, 7vw, 4.5rem);
  font-weight: var(--type-display-weight);
  line-height: 1.05;
}

/* El botón es el primario estándar y nada más: negro sobre blanco, con el alto
   y el redondeo de `.button`. Lo único suyo es el aire de encima. */
.signup-welcome-action {
  margin-top: 12px;
}

@media (prefers-reduced-motion: reduce) {
  .signup-welcome { transition-duration: .01ms !important; }
}

/* LA CONFIGURACIÓN INICIAL. Cubre la pantalla entera —no es un formulario
   dentro del panel, es LO QUE HAY que hacer antes de tener panel— y se recorre
   en pasos, con el avance a la vista arriba.

   NO TIENE MEDIDAS PROPIAS: por dentro es la misma página que Entrar y Crear
   cuenta. La caja es `.section-shell`, el rótulo es `.section-intro-compact`
   con su `h2`, el formulario es `.signup-form` con sus 420 px y los planes son
   la rejilla de la página de precio, clonada. Aquí solo vive lo que no existe
   en ningún otro sitio: la barra de avance, la respuesta de la dirección, el
   teléfono partido en prefijo y número, la fila de un día y las zonas. */
/* EL FONDO ES EL DE LA INTERFAZ, no el blanco de la marca. `--white` en modo
   oscuro es negro puro, y sobre negro puro los botones secundarios —que se
   dibujan con una línea negra— desaparecían: «Elegir» y «Volver» no se veían.
   `--background` es el fondo que usa el resto del panel en los dos temas. */
.setup {
  position: fixed;
  inset: 0;
  z-index: 400;
  overflow-y: auto;
  overscroll-behavior: contain;
  /* EL MISMO FONDO QUE EL PANEL DE LA CUENTA, que es sobre lo que se abre: la
     cuenta pinta `--surface` y esto pintaba `--background`, así que en oscuro
     la pantalla de plan salía negra sobre un panel que no lo es. */
  background: var(--surface);
  color: var(--text);
  opacity: 0;
  transition: opacity .4s cubic-bezier(.15, 1, .4, 1);
}

.setup.is-open { opacity: 1; }

.setup-inner {
  min-height: 100%;
  display: flex;
  flex-direction: column;
}

.setup-head { padding-top: 40px; }

.setup-head-inner {
  display: grid;
  gap: 10px;
}

.setup-step {
  color: var(--muted);
  font-size: var(--type-meta-size);
  line-height: var(--type-meta-line);
}

/* La barra de avance es una línea, no una cápsula con relleno: dice cuánto
   queda sin pedir atención. Crece con la misma curva que las transiciones del
   producto. */
.setup-progress {
  height: 2px;
  background: var(--line);
  overflow: hidden;
}

.setup-progress-bar {
  width: 0;
  height: 100%;
  display: block;
  background: var(--black);
  transition: width .4s cubic-bezier(.15, 1, .4, 1);
}

/* El contenido no salta de un paso al siguiente: se apaga, se cambia y se
   enciende. `margin-block: auto` es lo que lo deja centrado en la altura
   sobrante sin pelearse con la cabecera, que va arriba del todo. */
.setup-body {
  margin-block: auto;
  padding-block: 48px;
  transition: opacity .2s ease, transform .2s ease;
}

.setup-body.is-changing {
  opacity: 0;
  transform: translateY(8px);
}

.setup .section-intro {
  margin-inline: auto;
  text-align: center;
}

.setup .section-intro > .signup-plan {
  max-width: none;
  width: min(420px, 100%);
  margin-top: 12px;
  font-size: 1rem;
  letter-spacing: normal;
}

/* El paso de los planes necesita la anchura entera: son tres tarjetas, no un
   formulario de 420 px. */
.setup-form-wide { width: 100%; }
.setup-form-wide > .setup-actions {
  width: min(420px, 100%);
  margin-inline: auto;
}

/* LA RESPUESTA DE LA DIRECCIÓN. Un cuadro de tamaño fijo con el texto siempre
   en blanco: lo que dice si la dirección sirve o no es EL COLOR DEL CUADRO, no
   la frase. Así se lee de un vistazo y la pantalla no se mueve al cambiar,
   porque el cuadro mide lo mismo diga lo que diga. */
.setup-answer {
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--muted);
  color: var(--white);
  font-size: .8rem;
  line-height: 1;
}

.setup-answer[data-estado="bien"] { background: var(--foodev-status-success, #14834a); }
.setup-answer[data-estado="mal"] { background: var(--foodev-status-danger, #d73737); }

/* Y el campo donde se escribe lleva el color del mismo estado: la respuesta y
   la casilla dicen lo mismo, así que se leen como una sola pieza. El borde va
   en el grupo entero, que es quien lo dibuja. */
.foodev-private-login-fields:has(.signup-domain-field[data-estado="bien"]) { border-color: var(--foodev-status-success, #14834a); }
.foodev-private-login-fields:has(.signup-domain-field[data-estado="mal"]) { border-color: var(--foodev-status-danger, #d73737); }

/* El teléfono son dos casillas: el prefijo y el número. El «+» no es texto que
   se pueda borrar, es una marca fija de la casilla. */
.setup-phone {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}

.setup-phone-prefix {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 2px;
}

/* El «+» es parte del número, no una etiqueta: va en el mismo color que lo que
   se escribe al lado. */
.setup-phone-plus { color: inherit; }
.setup-phone-prefix input { width: 3.5ch; }
.setup-phone > input { flex: 1 1 auto; min-width: 0; }

/* La arroba de una red social es la misma pieza que el «+» del teléfono: parte
   de lo que se escribe, no una etiqueta, y no se puede borrar. */
.setup-handle {
  display: flex;
  align-items: center;
  gap: 2px;
  min-width: 0;
}

.setup-handle-at { color: inherit; }
.setup-handle > input { flex: 1 1 auto; min-width: 0; }

/* La vista previa de la tipografía enseña el nombre del restaurante al tamaño
   al que se va a leer en su portada. */
/* El nombre va dentro de su recuadro: sobre el fondo de la página, un nombre
   suelto en una tipografía distinta cada vez parecía un título de la pantalla y
   no una muestra de lo que se está eligiendo. */
.setup-font-preview {
  margin-bottom: 18px;
  padding: 24px 20px;
  border-radius: 8px;
  background: var(--setup-font-preview-bg, #F0F0F0);
  color: var(--display-text);
  font-size: clamp(1.75rem, 4vw, 2.5rem);
  line-height: 1.1;
  text-align: center;
  overflow-wrap: anywhere;
}

:root[data-theme="dark"] .setup-font-preview,
:root:not([data-theme="light"]) .setup-font-preview {
  --setup-font-preview-bg: #1B1B1B;
}

:root[data-theme="light"] .setup-font-preview {
  --setup-font-preview-bg: #F0F0F0;
}

/* La fila de un día. Cerrado ocupa UNA fila: su nombre y su primer horario.
   Al abrirlo el bloque CRECE HASTA EL DOBLE y debajo aparece el segundo turno,
   que es donde se activa. Crece con `grid-template-rows: 0fr → 1fr`, que es lo
   único que anima hasta el alto real del contenido sin inventarse un
   `max-height` que se quedaría corto o largo. */
/* El aire de arriba y de abajo es el MISMO abierto y cerrado. Con el alto
   mínimo de la fila estándar y el contenido centrado, al crecer el bloque se
   quedaba sin ese aire y se pegaba a sus vecinos: 21 px cerrado, 10 px abierto.
   Se cambia el mínimo por un relleno declarado, que no depende de cuánto mida
   dentro. Cerrado sigue midiendo lo mismo que cualquier otra fila del grupo:
   32 + 20 + 20 = 72. */
.setup-day {
  --setup-day-row: 32px;
  --setup-day-gap: 10px;
  min-height: 0;
  padding-block: 20px;
  display: grid;
  /* Alineado ARRIBA, no centrado. La fila estándar centra su contenido, y con
     el bloque creciendo eso significaba que la primera línea se iba subiendo
     mientras la segunda aparecía: el día entero se movía durante la animación y
     lo que se descubría parecía taparse. Anclado arriba, lo que ya estaba se
     queda quieto y lo nuevo crece por debajo, como en Preguntas frecuentes. */
  align-content: start;
  gap: 0;
}

.setup-day-row {
  height: var(--setup-day-row);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

/* Se abre y se cierra igual que una pregunta frecuente: la altura crece con su
   curva y el contenido entra con un fundido, sin moverse. Las medidas y los
   tiempos son los de allí, para que las dos cosas se sientan iguales.

   EL RELLENO ES CONSTANTE, y eso es justo lo que evita el salto: cuando solo
   existía en el estado abierto, al cerrar desaparecía de golpe y el segundo
   turno daba un tirón hacia arriba antes de esfumarse. Vive en el hijo, dentro
   de lo que se recorta, y no cambia nunca.

   La altura se anima con una medida, no con `grid-template-rows: 0fr → 1fr`.
   Ese truco necesita que la pista `1fr` se resuelva al contenido, y aquí no lo
   hace: el hijo lleva `min-height: 0` —lo necesita para poder cerrarse— y
   entonces la pista se queda en cero también abierta. Comprobado en el
   navegador: 10 px en vez de 42.
   La medida no es un `max-height` inventado a ojo, que es lo que esta casa
   prohíbe: la fila de un día mide EXACTAMENTE `--setup-day-row`, porque así se
   declara arriba, así que abierto son dos filas y su separación. Cambiar el
   token mueve las dos cosas a la vez. */
.setup-day-extra {
  height: 0;
  overflow: hidden;
  opacity: 0;
  transition: height 300ms cubic-bezier(.4, 0, .2, 1), opacity 240ms ease;
}

.setup-day-extra > div { padding-top: var(--setup-day-gap); }

.setup-day.is-open .setup-day-extra {
  height: calc(var(--setup-day-row) + var(--setup-day-gap));
  opacity: 1;
}

.setup-check {
  display: flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
}

.setup-check > input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}

/* Las horas van pegadas al borde derecho de la fila, alineadas entre sí en los
   dos turnos: es una columna de datos, no texto suelto. */
.setup-day-shift {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 6px;
  transition: opacity .2s ease;
}

.setup-day-shift input {
  width: auto;
  min-width: 0;
  text-align: right;
}

/* El reloj que Chrome añade dentro del campo se retira: ocupaba el sitio de la
   hora y la dejaba recortada en «13:0». El campo sigue siendo `type="time"`,
   así que el teclado del móvil y el selector nativo no cambian. */
.setup-day-shift input::-webkit-calendar-picker-indicator {
  display: none;
  -webkit-appearance: none;
  appearance: none;
}

.setup-day-separator { color: var(--muted); }
.setup-day.is-closed .setup-day-shift,
.setup-day-shift.is-off { opacity: .35; }
.setup-day-second { font-size: .92rem; color: var(--muted); }

/* Las zonas: tantas como tenga el local, cada una con sus mesas. */
.setup-zones {
  display: grid;
  gap: 20px;
}

.setup-zone {
  display: grid;
  gap: 10px;
}

/* Quitar una zona se dibuja como la respuesta de la dirección: el mismo cuadro
   de alto fijo con el texto en blanco. Aquí el color no cambia nunca —es rojo
   siempre— porque no informa de un estado, avisa de lo que hace. */
.setup-zone-remove {
  width: 100%;
  height: 32px;
  padding: 0;
  border: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--foodev-status-danger, #d73737);
  color: var(--white);
  font-size: .8rem;
  line-height: 1;
  cursor: pointer;
}

/* El mismo aire que separa los botones del formulario, no pegado al último
   campo. */
.setup-zone-add {
  width: 100%;
  margin-top: 16px;
}

/* La cifra de mesas se lee a la izquierda, como todo lo que se escribe en un
   campo. Las flechitas del navegador se retiran: empujaban el número y hacían
   que pareciera centrado. */
.setup-zone input[type="number"] {
  text-align: left;
  -moz-appearance: textfield;
}

.setup-zone input[type="number"]::-webkit-outer-spin-button,
.setup-zone input[type="number"]::-webkit-inner-spin-button {
  margin: 0;
  -webkit-appearance: none;
  appearance: none;
}

/* La portada: la foto elegida se ve tal cual va a verse, en la proporción de
   una pantalla de móvil, y no un nombre de archivo. */
/* LA PORTADA: el cuadro ES el botón. El sitio donde va a aparecer la foto es
   el sitio donde se pulsa para ponerla, que es lo que cualquiera intenta
   primero; un botón aparte debajo sobraba. Y para quitarla, una equis en su
   esquina, sobre la propia foto: mientras no hay foto no hay nada que quitar. */
.setup-cover {
  position: relative;
  display: grid;
}

.setup-cover-drop {
  position: relative;
  aspect-ratio: 4 / 3;
  border: 1px solid var(--line);
  background: var(--surface);
  display: grid;
  place-items: center;
  overflow: hidden;
  cursor: pointer;
}

.setup-cover-drop img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.setup-cover-invite {
  position: relative;
  display: grid;
  justify-items: center;
  gap: 10px;
  color: var(--muted);
  font-size: 1rem;
}

.setup-cover-invite svg {
  width: 32px;
  height: 32px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.25;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.setup-cover:not(.is-empty) .setup-cover-invite { display: none; }
.setup-cover.is-empty img { display: none; }

.setup-cover-clear {
  position: absolute;
  z-index: 1;
  top: 12px;
  right: 12px;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 0;
  border-radius: 999px;
  display: grid;
  place-items: center;
  background: rgb(0 0 0 / 80%);
  color: var(--white);
  cursor: pointer;
}

.setup-cover-clear svg {
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* El plan elegido se marca en su propia tarjeta, no con un control aparte: el
   botón pasa a primario y la tarjeta enseña su borde. */
.setup .plan-card.is-chosen { box-shadow: inset 0 0 0 1px var(--black); }

/* La rejilla de planes no añade aire propio: el que la separa del rótulo es el
   de `section-intro-compact`, el mismo de todos los pasos. */
.setup .plan-grid { margin-top: 0; }

/* La comparación completa vive detrás de su botón y no arrastra la cabecera
   pegajosa de la landing, que la mueve un guion que aquí no se carga. */
.setup-compare-toggle {
  width: min(420px, 100%);
  justify-self: center;
  margin-inline: auto;
  margin-top: 16px;
}

/* LA COMPARACIÓN ES UN SHEET. Sube desde abajo, ocupa la pantalla entera y se
   cierra con la cápsula de siempre: es el `action-sheet` compartido, con su
   barra de arrastre y su gesto, no un panel dibujado aquí. */
/* ESTE SHEET ES UNA PANTALLA ENTERA, y es la segunda excepción declarada a los
   tres números compartidos —la otra es el sheet de un plato en móvil—. Lo que
   lleva dentro es una tabla de tres columnas de plan: en la columna de 480 px
   del sheet normal no cabe, y estrecharla o dejarla desplazarse a un lado
   convierte una comparación en un acertijo. Por eso pide la pantalla completa,
   sin hueco arriba ni a los lados. No se cambia por consulta de medios: es una
   sola medida para móvil y escritorio, como el resto. */
.setup-compare-sheet {
  --setup-compare-top: 76px;
  --foodev-sheet-top-gap: 0px;
  --foodev-sheet-side-gap: 0px;
  --foodev-sheet-width: 100%;
  --foodev-sheet-max-height: 100svh;
  position: relative;
  border-radius: 0;
  padding-top: 0;
}

/* La cápsula va a la IZQUIERDA, alineada con el contenido y QUIETA: es la única
   salida de la hoja, así que no puede irse con el desplazamiento. Ocupa la
   banda de arriba —su alto vive en `--setup-compare-top`— y los rótulos de plan
   se pegan justo debajo, sin hueco vacío en medio: aquí esta cápsula hace el
   papel que en la landing hace la barra de navegación.

   Va por ENCIMA de la fila de nombres. Estuvo por debajo mientras la banda
   pintaba el fondo de la barra, y entonces la sombra de la cápsula se cortaba
   contra los nombres. Ahora el fondo lo pinta la propia tabla —la misma pieza
   que en la landing lleva su línea a los dos costados, estirada hacia arriba
   hasta cubrir esta banda—, así que aquí solo queda la cápsula y puede ir
   arriba del todo con su sombra entera. */
.setup-compare-top {
  position: sticky;
  z-index: 3;
  top: 0;
  width: min(100%, calc(var(--max-width) + (var(--page-padding) * 2)));
  height: var(--setup-compare-top);
  margin-inline: auto;
  padding: 16px var(--page-padding) 0;
  /* La banda no captura el ratón: lo único pulsable es la cápsula. Así la tabla
     de debajo sigue siendo suya. */
  pointer-events: none;
}

.setup-compare-close {
  position: relative;
  z-index: 1;
  pointer-events: auto;
}

/* LA BARRA ES OPACA, sin transparencia ni desenfoque, y la pinta UNA SOLA
   PIEZA: el pseudoelemento que la tabla ya usa en la landing para llevar su
   línea a los dos costados de la pantalla, estirado hacia arriba hasta cubrir
   también la banda de la cápsula. Con el color macizo de la hoja da igual que
   por debajo pase contenido, y desaparecen de golpe los dos problemas que daba
   el material translúcido: el tono doble donde se solapaban dos capas y el
   trozo sin desenfocar donde solo había una. */

/* Los rótulos se pegan bajo la cápsula, y su fondo se enciende SOLO al quedarse
   pegados, igual que en la página de precio: lo decide el mismo testigo de 1 px
   que allí, medido contra esta banda. */
.setup-compare-sheet .plan-compare-table thead th {
  top: var(--setup-compare-top);
  background: var(--foodev-sheet-surface);
}

/* La fila de nombres se queda como en la landing: su fondo y su línea son los
   suyos, y el pseudoelemento de la primera celda los lleva a los dos costados.
   Aquí solo cambian dos cosas: el material pasa a ser el opaco de la hoja, y
   ese pseudoelemento sube hasta cubrir la banda de la cápsula, que es lo que
   hace que la barra entera sea una sola pieza. */
.setup-compare-sheet .plan-compare.is-pinned .plan-compare-table thead th,
.setup-compare-sheet .plan-compare.is-pinned .plan-compare-table thead th:first-child::after {
  background: var(--foodev-sheet-surface);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

.setup-compare-sheet .plan-compare.is-pinned .plan-compare-table thead th:first-child::after {
  top: calc(-1 * var(--setup-compare-top));
}

/* Y los rótulos no se quedan el ratón: están por encima de la cápsula y no hay
   nada que pulsar en ellos. */
.setup-compare-sheet .plan-compare-table thead th { pointer-events: none; }

/* El cuerpo no pone márgenes: los pone la caja de dentro, que es la MISMA
   construcción que la cápsula de cerrar y que `.section-shell` en el resto de
   la web. Con el relleno aquí y otra caja centrada dentro, las dos cosas
   quedaban a distancias distintas del borde: 100 px la cápsula, 58 px la
   tabla. */
.setup-compare-body {
  padding: 0 0 48px;
}

/* Una hoja quieta no dibuja barra de agarre. */
.setup-compare-sheet .sheet-drag-bar,
.setup-compare-sheet .sheet-drag-hit-area { display: none; }

/* Dentro, la comparación respeta la misma caja que el resto de la web. */
.setup-compare-inner {
  width: min(100%, calc(var(--max-width) + (var(--page-padding) * 2)));
  padding-inline: var(--page-padding);
}

/* La comparación no añade `overflow` propio: la tabla cabe estrecha desde que
   las columnas de plan son fijas, y cualquier antepasado con `overflow` rompe
   la cabecera pegajosa de la landing, que es el mismo marcado. */
.setup-compare-inner { margin-inline: auto; }

/* El botón que la abre va centrado. `margin-inline: auto` no basta: `.button`
   es `inline-flex`, y una caja en línea no se centra con márgenes automáticos.
   Se vuelve de bloque para que sí lo haga. */
.setup-compare-toggle { display: flex; }

/* Atrás y Continuar comparten fila: caben, y separarlos en dos líneas hacía
   que el paso pareciera más largo de lo que es. Continuar manda, así que se
   lleva el espacio que sobre. */
.setup-actions {
  display: flex;
  align-items: center;
  gap: 10px;
}

/* Un botón apagado tiene que PARECER apagado: aquí se apaga cuando el paso
   todavía no está resuelto, y con el mismo negro de siempre no se distinguía de
   uno vivo. En espera es distinto —ahí conserva su color y enseña el spinner,
   que es el estándar—, así que esa regla se excluye. */
.setup-actions .signup-send:disabled:not(.is-loading) { opacity: .4; }

/* Atrás es cuadrado como Continuar: dos botones de la misma fila con
   redondeos distintos se leen como piezas de sitios distintos. */
.setup-actions .setup-back {
  flex: 0 0 auto;
  border-radius: 0;
}
.setup-actions .signup-send { flex: 1 1 auto; width: auto; }
.setup-actions .setup-back[hidden] { display: none; }

.setup-summary > div:first-child { padding-top: 0; }

@media (prefers-reduced-motion: reduce) {
  .setup,
  .setup-body,
  .setup-progress-bar { transition-duration: .01ms !important; }
}

/* El selector de idioma del pie. Se lee como una fila que se abre, con la
   flecha del estándar; no es una acción, así que no pesa como un botón. */
.site-footer-language {
  align-self: start;
  justify-self: start;
  width: fit-content;
  margin-top: 20px;
  /* La misma cápsula pequeña que «Regístrate»: mismo alto, mismo relleno del
     estándar y mismo redondeo. Lo único distinto es que aquí el fondo es el del
     pie y lo que dibuja el botón es su borde. */
  min-height: 24px;
  padding: 0 var(--foodev-small-button-padding-inline);
  border: 0;
  border-radius: 999px;
  box-shadow: inset 0 0 0 1px #ffffff;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: transparent;
  color: #ffffff;
  font-family: inherit;
  font-size: var(--type-nav-size);
  font-weight: 400;
  cursor: pointer;
}

.site-footer-language .standard-sheet-chevron {
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Tres planes en fila, los tres iguales. No hay uno destacado: si más adelante
   vuelve a haberlo, que sea con el relleno del botón y no con un borde o una
   escala, porque una tarjeta más grande que sus vecinas descuadra la fila. */
.plan-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 16px;
  align-items: stretch;
  margin-top: clamp(40px, 5vw, 64px);
}

/* El orden de la tarjeta es el orden en que se decide: qué plan es, qué te da,
   cuánto cuesta, y entonces el botón. La lista viene detrás, sin línea que la
   separe: es la continuación del argumento, no otra sección. */
/* Sin fondo ni redondeo: la tarjeta es solo su borde, y el fondo que se ve es
   el de la sección. */
.plan-card {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 28px 24px 30px;
  border: 1px solid var(--line);
  background: transparent;
}

.plan-card-name {
  color: var(--display-text);
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: 500;
  line-height: 1.1;
}

/* La descripción va pegada al nombre y en negro: es parte de la respuesta a
   «qué plan es este», no un pie de foto. */
/* Ocho píxeles menos que el hueco de la tarjeta: el nombre del plan y para
   quién es son una sola idea y se leen juntos. */
.plan-card-for {
  margin-top: -8px;
  color: var(--text);
  font-size: 1rem;
  line-height: 1.45;
}

/* Y el importe se separa, porque es la otra pregunta. */
.plan-card-price {
  display: flex;
  align-items: baseline;
  gap: 6px;
  margin-top: 34px;
  color: var(--display-text);
  font-family: var(--font-display);
}

/* El importe lleva el euro delante y pegado —«€29»—, así que se escribe como
   una sola pieza y se aprieta para que el símbolo no quede suelto. */
.plan-card-amount {
  font-size: 2.75rem;
  font-weight: var(--type-price-weight);
  line-height: var(--type-price-line);
  letter-spacing: -2px;
  font-variant-numeric: tabular-nums;
}

.plan-card-period {
  color: var(--muted);
  font-family: var(--font-ui);
  font-size: 1rem;
  font-weight: 400;
}

/* «Elegir» es un botón recto: en una tarjeta de plan la píldora competía con
   el propio recuadro de la tarjeta. */
/* El redondeo completo es el estándar de los botones de la landing: el de
   `.button-pill` que ya trae la clase. Aquí solo se declaran el ancho y el aire
   de abajo. */
.plan-card-action {
  width: 100%;
  margin-bottom: 40px;
  justify-content: center;
}

.plan-card-list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 12px;
  color: var(--text);
  font-size: 1rem;
  line-height: 1.4;
}

.plan-card-list li {
  display: grid;
  grid-template-columns: 20px 1fr;
  gap: 10px;
  align-items: start;
}

/* El tick es el estándar del catálogo: el mismo trazado que dibuja
   `FoodevStandardIcons`, aquí con 1 px de grosor. No es un carácter de la
   tipografía, así que su grosor se controla de verdad. */
.plan-tick {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.plan-card-list .plan-tick { margin-top: .12em; }

.plan-grid-note {
  margin-top: 20px;
  color: var(--muted);
  font-size: var(--type-meta-size);
  line-height: 1.5;
  text-align: center;
}

/* La comparativa sustituye al diálogo de «Todo lo que incluye». Un desplegable
   escondía justo lo que se necesita para decidir, y obligaba a recordar una
   columna mientras se miraba otra. */
.plan-compare {
  margin-top: clamp(72px, 9vw, 120px);
}

.plan-compare-title {
  margin-bottom: 24px;
  color: var(--display-text);
  font-family: var(--font-display);
  font-size: var(--type-feature-size);
  font-weight: var(--type-feature-weight);
  line-height: var(--type-feature-line);
  text-align: center;
}

.plan-compare-table {
  width: 100%;
  border-collapse: collapse;
  text-align: left;
}

/* Las tres columnas de plan reparten a partes iguales lo que sobra, así que
   llegan hasta el borde derecho. Repartiéndolo por el contenido quedaba un
   hueco grande a la derecha y los planes se amontonaban a la izquierda. */
.plan-compare-feature { width: 40%; }
.plan-compare-table colgroup col:not(.plan-compare-feature) { width: 20%; }

.plan-compare-table thead th {
  padding: 14px 16px;
  color: var(--display-text);
  font-family: var(--font-display);
  font-size: 1.125rem;
  font-weight: 500;
}

.plan-compare-table tbody th,
.plan-compare-table tbody td {
  padding: 14px 16px;
  border-bottom: 1px solid var(--line);
  color: var(--text);
  font-size: 1rem;
  line-height: 1.4;
  vertical-align: top;
}

.plan-compare-table tbody th { font-weight: 400; }

/* Lo de cada plan va centrado en su columna; el nombre de la prestación, no. */
.plan-compare-table :is(thead, tbody) :is(th, td) + :is(th, td) { text-align: center; }

/* Las líneas empiezan y acaban donde empieza y acaba el texto: el relleno
   lateral de las celdas de los extremos las alargaba más allá. */
.plan-compare-table :is(th, td):first-child { padding-left: 0; }
.plan-compare-table :is(th, td):last-child { padding-right: 0; }

.plan-compare-table .plan-compare-group th {
  padding-top: 40px;
  border-bottom: 1px solid var(--line);
  color: var(--display-text);
  font-family: var(--font-display);
  font-size: 1.25rem;
  font-weight: 500;
}

/* El tick de la tabla lleva el mismo grosor que el de las tarjetas. El «no» es
   una raya, y va en el mismo negro que todo lo demás: en gris parecía una
   celda deshabilitada en vez de una respuesta. */
.plan-compare-table td :is(.plan-tick, span[aria-hidden]) { display: inline-block; }
.plan-compare-table td[data-plan-no] { color: var(--text); }

/* El testigo mide cuándo la fila de nombres se queda pegada: en cuanto sale de
   la pantalla por arriba, `landing.js` marca la tabla. No hay selector CSS para
   «pegado», así que hace falta este trozo de altura cero. */
/* 1 px, no 0: un elemento sin área nunca cruza el umbral del observador y la
   marca no llegaba a ponerse. */
.plan-compare-sentinel { height: 1px; margin-bottom: -1px; }

/* Para que el `sticky` se mida contra la ventana y no contra una caja
   intermedia, NINGÚN antepasado puede tener `overflow` distinto de `visible`.
   Por eso el contenedor no desborda en ningún ancho: la tabla cabe estrecha
   desde que las columnas de plan son fijas y se reducen a un color. */
.plan-compare-scroll { overflow: visible; }

/* Suelta lleva el fondo de la página y su línea acaba donde las demás. */
.plan-compare-table thead th {
  position: sticky;
  z-index: 2;
  top: var(--site-header-height);
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}

/* Pegada toma el material de la barra de navegación. */
.plan-compare.is-pinned .plan-compare-table thead th {
  background: var(--bar-material);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
}

/* Y solo entonces la línea se extiende a toda la pantalla, con un
   pseudoelemento de 200 vw anclado a la primera celda: un borde acabaría donde
   acaba la tabla. Va detrás del texto de su celda, y las otras tres pintan
   encima por orden natural. */
.plan-compare.is-pinned .plan-compare-table thead th:first-child::after {
  content: "";
  position: absolute;
  z-index: -1;
  top: 0;
  bottom: -1px;
  left: calc(50% - 100vw);
  width: 200vw;
  border-bottom: 1px solid var(--line);
  background: var(--bar-material);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
}

/* Un color por plan. Solo se usan cuando el nombre no cabe: en pantalla ancha
   la cabecera dice «Gratis», «Plus» y «Pro» con todas sus letras. */
:root {
  --plan-color-gratis: #a0a0a0;
  --plan-color-plus: #4a7cc4;
  --plan-color-premium: #181818;
}

.plan-dot {
  width: 14px;
  height: 14px;
  border-radius: 999px;
  display: none;
  flex: 0 0 14px;
}

.plan-dot[data-plan="gratis"] { background: var(--plan-color-gratis); }
.plan-dot[data-plan="plus"] { background: var(--plan-color-plus); }
.plan-dot[data-plan="premium"] { background: var(--plan-color-premium); }

/* La leyenda solo existe para explicar esos colores, así que acompaña a la
   cabecera reducida y desaparece con ella. */
.plan-legend {
  margin: 0 0 20px;
  padding: 0;
  list-style: none;
  display: none;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px 18px;
  color: var(--text);
  font-size: .92rem;
}

.plan-legend li {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}

@media (max-width: 900px) {
  /* Estrecha, la cabecera cambia el nombre por su color y las columnas de plan
     se encogen a lo justo para un tick o dos palabras. Así la tabla entra sin
     desplazarse, que es lo que antes obligaba a arrastrarla de lado. */
  .plan-legend { display: flex; }
  .plan-dot { display: block; }
  .plan-head-name { display: none; }

  /* `fixed` no sobra: con el reparto automático, «Sin límite» o «Hasta 15
     mesas» ensanchaban su columna y las tres dejaban de medir lo mismo. */
  .plan-compare-table { table-layout: fixed; }

  .plan-compare-table thead th { padding-block: 10px; }
  .plan-compare-table thead th .plan-dot { margin-inline: auto; }

  /* La columna de la izquierda se queda con lo que sobre; las tres de plan
     miden lo mismo. */
  .plan-compare-feature { width: auto; }
  .plan-compare-table colgroup col:not(.plan-compare-feature) { width: 68px; }

  .plan-compare-table tbody th,
  .plan-compare-table tbody td {
    padding: 12px 8px;
    font-size: .92rem;
  }

  .plan-compare-table :is(th, td):first-child { padding-left: 0; }
  .plan-compare-table :is(th, td):last-child { padding-right: 0; }

  .plan-grid { display: flex; flex-direction: column; }
}

.contact > .section-shell {
  padding-block: 24px;
}

.contact .section-intro {
  margin-inline: auto;
  text-align: center;
}

.contact-form {
  width: min(560px, 100%);
  margin-inline: auto;
  display: grid;
  gap: 16px;
  text-align: left;
}

/* Los campos son literalmente los del acceso privado: un solo grupo con su
   borde, las filas separadas por una línea y el rótulo encima del campo. Antes
   eran cuatro cajas redondeadas sueltas, un patrón que no existía en ningún
   otro sitio de Foodev. */
/* «(opcional)» es parte del rótulo, no un apunte aparte: hereda su color y su
   peso. Con un color propio se leía más oscuro que la palabra a la que
   acompaña, justo al revés de lo que quiere decir. */
.contact-field-optional {
  color: inherit;
  font-weight: inherit;
}

/* El señuelo antirrobots. No vale `display: none` ni `hidden`: muchos robots
   saltan lo que el navegador no pinta, y entonces el señuelo no señuela nada.
   Se saca de la pantalla, que sí lo deja existir. */
.contact-form-trap {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* El consentimiento usa la casilla compartida, no una dibujada aquí. */
.contact-form-consent {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--description);
  font-size: .92rem;
  line-height: 1.35;
  cursor: pointer;
}

.contact-form-consent a {
  color: inherit;
  text-decoration: underline;
}

/* La casilla nativa se esconde sin quitarla del árbol: `display: none` la
   sacaría de la validación y del foco, y el control visible es el
   `.foodev-choice-control` compartido. Es el mismo recurso que usa
   `.show-password-row` en las herramientas privadas. */
.contact-form-consent input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}

/* El botón cierra el formulario: mismo ancho que el grupo de campos, sin
   redondeo, para que los dos se lean como una sola pieza. */
.contact-form-send {
  width: 100%;
  border-radius: 0;
  background: var(--black);
  color: var(--white);
}

.contact-form-note {
  margin: 0;
  min-height: 1.2em;
  color: var(--description);
  font-size: .92rem;
  text-align: center;
}

/* Precio, Contacto y Demo son páginas propias: su contenido empieza bajo la
   barra, que es fija. En la principal ese hueco lo pone la portada, que ocupa
   la pantalla entera.

   La entrada de un servicio y las páginas de alta y acceso quedan fuera: esas
   ocupan la pantalla entera y centran su contenido en ella, así que un relleno
   extra solo arriba las bajaba del centro. */
.landing-page-detail main > .landing-section:first-child:not(.detail-intro):not(.signup) {
  padding-top: calc(80px + clamp(24px, 4vw, 64px));
}

/* El botón de Preguntas es el primario estándar. No lleva margen propio: el
   suyo lo pone la fila, que lo centra verticalmente con el texto de al lado.
   Con `margin-top` se descolgaba hacia abajo. */
.faq-contact-action {
  flex: 0 0 auto;
  background: var(--black);
  color: var(--white);
}

/* El bloque de Preguntas va centrado en la página; lo único que se queda a la
   izquierda es el texto de dentro de cada pregunta, que se lee en línea. */
.faq .section-intro {
  margin-inline: auto;
  text-align: center;
}

/* Sin líneas verticales: solo el borde superior e inferior de la lista y el
   divisor entre preguntas, los tres horizontales. El texto y el símbolo ya no
   se apartan de ellos con un relleno propio, así que ocupan el ancho entero
   entre uno y otro extremo. */
.faq-list {
  max-width: 900px;
  margin-inline: auto;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

.faq-list details { border: 0; }
.faq-list details + details { border-top: 1px solid var(--line); }

.faq-list summary {
  min-height: 76px;
  padding-block: 20px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  cursor: pointer;
  color: #000000;
  font-size: var(--type-body-size);
  /* La pregunta pesa lo mismo que su respuesta: es una lista para recorrer con
     la vista, y con 500 cada enunciado pedía turno como si fuera un titular. */
  font-weight: var(--type-body-weight);
  line-height: var(--type-body-line);
  list-style: none;
}

.faq-list summary::-webkit-details-marker { display: none; }
.faq-symbol {
  width: 32px;
  height: 32px;
  flex: 0 0 32px;
}

.faq-symbol::before { width: 18px; height: 1.5px; }
.faq-symbol::after {
  width: 1.5px;
  height: 18px;
  transition: transform 300ms cubic-bezier(.4, 0, .2, 1);
}

.faq-list details.is-expanded .faq-symbol::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.faq-answer {
  height: 0;
  overflow: hidden;
  opacity: 0;
  transition: height 300ms cubic-bezier(.4, 0, .2, 1), opacity 240ms ease;
}

.faq-list details.is-expanded .faq-answer { opacity: 1; }
/* La respuesta va apagada: con el mismo negro que la pregunta, y ahora que
   pesan lo mismo, no se distinguía cuál era cuál. */
.faq-list details p { max-width: 900px; padding: 0 0 24px; color: var(--muted); font-size: var(--type-body-size); font-weight: var(--type-body-weight); line-height: var(--type-body-line); }

/* El pie de Preguntas: el par va centrado en el bloque, pero el texto se lee
   alineado a la izquierda mientras comparte línea con el botón. Solo cuando el
   botón baja —apilado— pasa todo a centrado. */
.faq-contact {
  max-width: 900px;
  margin-top: 32px;
  margin-inline: auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 20px;
  text-align: left;
}

/* El texto se queda en el ancho que necesita, no en uno fijo: así el botón va
   pegado a él en vez de quedarse lejos por el hueco de la última línea. */
.faq-contact p {
  width: fit-content;
  max-width: min(100%, 30rem);
  color: #000000;
  font-size: var(--type-body-size);
  font-weight: var(--type-body-weight);
  line-height: var(--type-body-line);
}

/* El teléfono empieza donde empieza el rótulo «Demo»: las dos columnas se
   alinean por arriba. Con la alineación inferior la foto, más alta que el
   texto, arrancaba casi 300 px por encima del rótulo. */
/* La demo vive al final de la página principal y va centrada en una sola
   columna. Tuvo página propia y una fotografía de un móvil al lado; las dos
   cosas se retiraron. */
.demo-inner {
  display: grid;
  justify-items: center;
  text-align: center;
}

.demo-copy {
  min-width: 0;
  width: 100%;
  display: grid;
  justify-items: center;
}

.demo-copy > p:not(.section-kicker) {
  max-width: 640px;
  margin-top: var(--title-description-space);
  color: var(--description);
  font-size: var(--type-description-size);
  font-weight: var(--type-description-weight);
  letter-spacing: var(--type-description-tracking);
  line-height: var(--type-description-line);
}















/* SE ENTRA POR EL QR. El código va sobre una placa blanca siempre, también
   en oscuro: un lector de códigos necesita el contraste en ese sentido y no en
   el contrario, y un QR claro sobre fondo negro no lo lee ninguna cámara. La
   placa es lo único de la página que no cambia con el tema. */
.demo-access {
  margin-top: clamp(36px, 4vw, 52px);
  display: grid;
  justify-items: center;
  gap: 24px;
}

.demo-qr-code {
  width: 200px;
  height: 200px;
  padding: 16px;
  box-sizing: border-box;
  background: #ffffff;
  border-radius: 12px;
  box-shadow: 0 1px 2px #0000000f, 0 8px 24px #00000014;
}

/* El dibujante devuelve un `<svg>` con su propio tamaño en atributos. Se le
   deja ocupar la placa entera y no al revés. */
.demo-qr-code > svg {
  display: block;
  width: 100%;
  height: 100%;
}

/* El pie es exactamente el mismo en todas las páginas: la principal, las tres
   propias, las seis de servicio y las legales. Antes había dos variantes —una
   clara y otra para las legales, más estrecha— y mantener dos pies para el
   mismo contenido solo servía para que se separaran. Fondo negro, texto blanco,
   la marca en grande a la izquierda y a su derecha las listas de enlaces. */
.site-footer {
  padding-block: clamp(56px, 7vw, 88px);
  background: #000000;
  color: #ffffff;
}

/* EL IDIOMA VA SIEMPRE PEGADO DEBAJO DEL LOGO, en las dos disposiciones: es
   parte de la marca, no una columna más ni una coletilla del final. Se coloca a
   mano con áreas con nombre en vez de dejarlo caer donde lo lleve el orden del
   documento, que es lo que lo mandaba al fondo del pie: apilado quedaba detrás
   de las cuatro listas, y en escritorio la primera fila la estiraban las listas
   y el botón caía a la altura de su última línea.

   El hueco entre filas es cero y las separaciones se ponen a mano: la que hay
   del logo al idioma no es la misma que la que separa la marca de los enlaces.
   Las listas ocupan las dos filas para que la columna de la marca pueda repartir
   su alto sin arrastrarlas. */
.site-footer-inner {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas:
    "marca"
    "idioma"
    "enlaces";
  column-gap: clamp(48px, 6vw, 72px);
  row-gap: 0;
}

.site-footer-brand { grid-area: marca; }
.site-footer-language { grid-area: idioma; }
.site-footer-columns { grid-area: enlaces; margin-top: clamp(48px, 6vw, 72px); }

@media (min-width: 901px) {
  .site-footer-inner {
    grid-template-columns: minmax(220px, 1fr) minmax(0, 3fr);
    grid-template-rows: auto 1fr;
    grid-template-areas:
      "marca enlaces"
      "idioma enlaces";
  }

  .site-footer-columns { margin-top: 0; }
}

.site-footer-brand {
  align-self: start;
  display: block;
  width: 56px;
}

/* El logotipo lleva sus grises pensados para un fondo claro; el pie es negro
   siempre, sin depender del tema, así que se invierte a mano en vez de crear
   una segunda variante del archivo. */
.site-footer-brand img {
  display: block;
  width: 100%;
  height: auto;
  filter: invert(1);
}

/* Las columnas caben las que quepan: cuatro en escritorio, dos en una tableta
   y dos todavía en un móvil estrecho, sin un corte escrito para cada anchura.
   El espacio entre filas es mayor que el de columnas: cuando dos listas caen
   una encima de otra necesitan más aire que el que separa dos que están lado
   a lado. */
.site-footer-columns {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  row-gap: clamp(40px, 6vw, 56px);
  column-gap: 24px;
}

.site-footer-heading {
  margin: 0 0 20px;
  color: #a0a0a0;
  font-family: var(--font-ui);
  font-size: var(--type-meta-size);
  font-weight: var(--type-meta-weight);
  letter-spacing: .08em;
  line-height: var(--type-meta-line);
  text-transform: uppercase;
}

.site-footer-column ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

.site-footer-column li + li { margin-top: 14px; }

.site-footer-column a {
  color: inherit;
  font-size: var(--type-body-size);
  font-weight: var(--type-body-weight);
  line-height: var(--type-body-line);
}

.site-footer-column a:hover {
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Public legal pages have no navigation bar. Their only navigation is the
   canonical floating back capsule, aligned with the document column. */
.legal-main { padding-bottom: clamp(72px, 9vw, 128px); }

.legal-intro {
  padding-block: clamp(112px, 12vw, 160px) 20px;
}

/* LAS PÁGINAS LEGALES VAN EN BLANCO, documento entero: el papel del resto de la
   web es #F4F4F4, y un texto largo se lee mejor sobre el blanco de una hoja. El
   cuerpo también, porque el pie queda fuera del documento. */
.legal-document-page,
.legal-main { background: var(--white); }

.legal-intro-inner {
  width: min(calc(100% - (var(--page-padding) * 2)), 880px);
  margin-inline: auto;
}

.legal-back-row {
  width: 100%;
  margin: 0 0 clamp(48px, 6vw, 72px);
}

.legal-back {
  position: fixed;
  z-index: 40;
  top: calc(20px + env(safe-area-inset-top, 0px));
  left: max(var(--page-padding), calc((100vw - 880px) / 2));
}

.legal-document {
  width: min(calc(100% - (var(--page-padding) * 2)), 880px);
  margin-inline: auto;
}

.legal-intro h1 {
  color: #262626;
  font-size: var(--type-display-size);
  font-weight: var(--type-display-weight);
  letter-spacing: var(--type-display-tracking);
  line-height: var(--type-display-line);
}

.legal-updated {
  margin-top: 12px;
  color: var(--description);
  font-size: var(--type-description-size);
  font-weight: var(--type-description-weight);
  letter-spacing: var(--type-description-tracking);
  line-height: var(--type-description-line);
}

/* LA LÍNEA BAJO EL CABEZADO. Separa el título y su fecha del documento, y mide
   lo mismo que el documento porque vive en su misma columna: el ancho no se
   repite aquí, lo pone `.legal-intro-inner`. */
.legal-rule {
  height: 0;
  margin: clamp(28px, 4vw, 40px) 0 0;
  border: 0;
  border-top: 1px solid var(--line);
}

.legal-section { margin-top: 52px; }

/* EL TÍTULO DE CADA APARTADO ES EL RÓTULO DE LA PORTADA, el que va encima del
   titular de cada servicio en el inicio: `.section-kicker`. No se copia su
   estilo, se le pone su clase —así que si cambia allí, cambia aquí—. Iban a
   2 rem, el tamaño de un titular de sección, y en un documento de quince
   apartados eso son quince titulares compitiendo con el de la página. */

.legal-section h3 {
  margin-top: 28px;
  color: #262626;
  font-size: var(--type-body-size);
  font-weight: 600;
  line-height: var(--type-body-line);
}

.legal-section p,
.legal-section li,
.legal-section dd,
.legal-section dt {
  color: #000000;
  font-size: var(--type-body-size);
  font-weight: var(--type-body-weight);
  line-height: var(--type-body-line);
}

.legal-section h2 + p,
.legal-section p + p,
.legal-section p + ul,
.legal-section p + dl,
.legal-section h3 + p,
.legal-section h3 + ul,
.legal-section ul + p { margin-top: 16px; }

.legal-section ul { margin-bottom: 0; padding-left: 22px; }
.legal-section li + li { margin-top: 8px; }
.legal-section a { color: inherit; text-decoration: underline; text-underline-offset: 3px; }

/* AQUÍ ESTABA LA REJILLA DE DATOS de los documentos legales, y ya no está. Era
   una tabla —dos columnas con filos— para decir siete cosas: el titular, el
   NIF, el domicilio. Un documento legal se lee en una columna de texto; lo que
   sea una enumeración se enumera con una lista normal, que es lo que hay
   ahora. */

/* La barra pasa a formato móvil cuando el botón «Ver demo» ya no cabe en una
   línea, no a un ancho fijo: entre los enlaces y el botón, el punto exacto
   depende de la longitud de los textos, y con un corte fijo el botón se partía
   en dos antes de llegar a él. Lo decide `landing.js` midiendo el botón con y
   sin ajuste de línea, así que se calibra solo aunque cambien los textos.
   Estas reglas son las mismas que aplica el corte de 900 px de más abajo. */
/* COMPACTADA NO HAY BARRA: HAY UNA CÁPSULA. La barra se quedaba con una franja
   entera del alto de la pantalla para enseñar un logo y un botón, y en un móvil
   esa franja es cara. La cápsula abre el mismo cajón, que ya lleva todo:
   Inicio, Servicios, Precio, Contacto y las dos puertas de la cuenta. */
html.landing-nav-compact .site-header { display: none; }
html.landing-nav-compact :is(.mobile-menu-trigger, .landing-back) { display: grid; }

@media (max-width: 900px) {
  :root {
    --type-feature-size: 2.125rem;
    --type-statement-size: 1.7rem;
    --type-description-size: 1.25rem;
    --type-subtitle-size: 1.375rem;
  }

  .site-header { display: none; }
  :is(.mobile-menu-trigger, .landing-back) { display: grid; }
  /* Sin barra, la portada empieza en el borde de la pantalla. */
  :root { --site-header-height: 0px; }
  html { scroll-padding-top: 16px; }

  /* Apilada el texto ocupa el doble y el aparato la mitad, así que el recorrido
     que necesita el título para esconderse es MAYOR que en escritorio, no
     menor. Aquí ponía `auto` y por eso en móvil el título empezaba a subir casi
     enseguida. */
  .hero { min-height: calc(100svh - var(--site-header-height)); }
  .hero-inner { padding-top: 82px; }
  .hero { --hero-title-size: var(--type-display-size); }

  /* Apilada, la imagen va debajo del texto siempre: el reflejo solo tiene
     sentido mientras hay dos columnas. */
  .landing-split { grid-template-columns: minmax(0, 1fr); gap: clamp(32px, 6vw, 48px); }
  .landing-split-mirrored .landing-split-copy { order: 0; }
  .landing-placeholder { --landing-placeholder-ratio: 3 / 2; }

  /* Apilado, lo que sigue al título son tres tarjetas, no un párrafo, y con el
     aire estándar de una sección el rótulo quedaba flotando lejos de ellas. */
  .pricing .section-intro-compact { margin-bottom: clamp(44px, 6vw, 56px); }

}

/* En la pantalla más estrecha la placa del QR se aprieta un poco. Por debajo
   de este tamaño una cámara ya empieza a costarle el enfoque, así que no baja
   más. */
@media (max-width: 359px) {
  .demo-qr-code { width: 172px; height: 172px; padding: 14px; }
}

@media (max-width: 620px) {
  :root {
    --section-space: 80px;
    --type-feature-size: 2rem;
    --type-statement-size: 1.6rem;
    --type-description-size: 1.125rem;
    --type-subtitle-size: 1.25rem;
  }
  h1,
  h2,
  h3 { text-wrap: wrap; }

  /* El subtítulo es más pequeño aquí, así que su interlineado sobrante
     también encoge un poco: se redeclara en el propio elemento, porque una
     variable heredada de `:root` no puede ganarle a la que ya fija aquí la
     regla base. */
  .hero-inner { padding-block: 48px 0; --hero-description-leading-fix: 3px; }
  .hero { --hero-title-size: var(--type-display-size); }
  .hero h1 { letter-spacing: var(--type-display-tracking); }
  .section-intro { margin-bottom: 56px; }
  .section-intro h2,
  .demo h2 { font-size: var(--type-display-size); }

  .section-kicker { font-size: 1.5rem; }
  .plan-card-amount { font-size: 2.5rem; }
  .faq-list summary { min-height: 68px; padding-block: 18px; }
  .faq-list details p { padding: 0 0 20px; }
  /* Apilado el botón baja, y entonces sí va todo centrado. */
  .faq-contact { gap: 16px; text-align: center; }
  .faq-contact p { max-width: none; }

  .legal-intro { padding-top: 104px; padding-bottom: 16px; }
  .legal-back { top: calc(16px + env(safe-area-inset-top, 0px)); }
}

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

/* LAS CUENTAS QUE YA HAN ENTRADO EN ESTE NAVEGADOR.
   ---------------------------------------------------------------------
   Van justo antes del correo y la contraseña, que es donde ahorran trabajo:
   pulsar una pone su dirección y deja el cursor en la contraseña. Cada una es
   un cuadro con el nombre arriba y el correo debajo, con el mismo filo y el
   mismo fondo que el bloque de campos que tiene justo debajo, para que se lean
   como la misma pieza y no como un adorno pegado encima.

   La X vive dentro del cuadro pero FUERA del botón: un botón dentro de otro no
   existe en HTML y deja de responder al teclado. Los dos se apoyan en la misma
   caja, el botón ocupándola entera y la X flotando sobre su borde interior
   derecho, con sitio reservado en el relleno del botón para que el correo
   nunca pase por debajo. */
.login-accounts {
  display: grid;
  gap: 8px;
}

.login-account-slot {
  position: relative;
  min-width: 0;
}

.login-account {
  width: 100%;
  min-width: 0;
  padding: 12px 52px 12px 16px;
  display: grid;
  gap: 3px;
  border: 1px solid var(--border, var(--line, #0000001f));
  background: transparent;
  color: inherit;
  text-align: left;
  cursor: pointer;
}

.login-account-copy {
  min-width: 0;
  display: grid;
  gap: 3px;
}

.login-account-name,
.login-account-mail {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.login-account-name {
  font: 500 .95rem/1.2 "Inter", sans-serif;
}

.login-account-mail {
  color: var(--muted, var(--text-secondary, #666));
  font: 400 .8rem/1.2 "Inter", sans-serif;
}

.login-account-remove {
  position: absolute;
  top: 50%;
  right: 10px;
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--muted, var(--text-secondary, #666));
  cursor: pointer;
  transform: translateY(-50%);
}

/* Al pasar por encima se pone negra: es el único aviso de que ese aspa hace
   algo, y de que lo que hace es sobre esa tarjeta y no sobre la cuenta. Solo
   donde hay puntero de verdad; en una pantalla táctil el estado de reposo se
   quedaría pegado después de tocarla. */
@media (hover: hover) and (pointer: fine) {
  .login-account-remove:hover {
    color: var(--text);
  }
}

.login-account-remove:focus-visible {
  color: var(--text);
}

.login-account-remove svg {
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
}
