/* =========================================================================
   QR Creator — JR Netmedia
   Hoja de estilos unica del proyecto. CSS puro con BEM, sin marcos de
   utilidades ni generadores de clases.

   Reglas que cumple (00-SETUP.md):
     - Fondo blanco siempre. Grises casi blancos solo en franjas pequenas.
     - Todos los colores en variables :root, para que anadir el modo oscuro
       sea cambiar veinte lineas. NO se escribe CSS de modo oscuro aqui.
     - Sin position:sticky salvo el header.
     - Alturas reservadas en todo lo que se rellena despues (anuncios,
       imagenes, paneles desplegables) para que el layout shift sea 0.
     - Consultas de contenedor, no @media, cuando lo que manda es el ancho
       de la tarjeta y no el de la ventana.
   ========================================================================= */

/* -------------------------------------------------------------------------
   0. TIPOGRAFIA — Inter, autoalojada
   Nunca desde CDN: el 25/07 las reglas de seguridad del navegador de Miia
   bloquearon todas las imagenes remotas de una entrega. Con las fuentes
   pasaria lo mismo.
   font-display:swap para que el texto se vea desde el primer pintado.

   Las rutas de las fuentes van RELATIVAS a este fichero, no absolutas:
   asi funcionan igual si el sitio cuelga de la raiz del dominio o de un
   subdirectorio (/qr/). Con '/fuentes/...' daba 404 al desplegar en
   subcarpeta, comprobado.
   ------------------------------------------------------------------------- */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('fuentes/inter-variable.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('fuentes/inter-variable-ext.woff2') format('woff2');
  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;
}

/* -------------------------------------------------------------------------
   1. TOKENS
   ------------------------------------------------------------------------- */
:root {
  /* Color de marca: azul editorial.
     Jorge, 26/07: "habria que hacer la APP en color editorial, Azul, que
     siempre funciona mejor con la publicidad". Se aplica igual en web. */
  --color-brand: #1a56db;
  --color-brand-dark: #1543ac;
  --color-brand-light: #eff4fe;

  --color-bg: #ffffff;
  --color-surface: #fafafa;
  --color-surface-alt: #f9fafb;

  --color-text: #111827;
  --color-text-muted: #4b5563;
  --color-text-soft: #6b7280;

  --color-border: #e5e7eb;
  --color-border-strong: #d1d5db;

  --color-success: #047857;
  --color-success-bg: #ecfdf5;
  --color-warning: #b45309;
  --color-warning-bg: #fffbeb;
  --color-danger: #b91c1c;
  --color-danger-bg: #fef2f2;

  --color-focus: #1a56db;

  /* Tipografia. Base 16 px, como pide el SETUP (14-16). */
  --font-base: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
    'Helvetica Neue', Arial, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;

  --size-xs: 0.75rem;
  --size-sm: 0.875rem;
  --size-base: 1rem;
  --size-lg: 1.125rem;
  --size-xl: 1.375rem;
  --size-2xl: 1.75rem;
  --size-3xl: 2.25rem;

  --line-tight: 1.25;
  --line-base: 1.55;

  /* Espaciado */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 3rem;
  --space-8: 4rem;

  --radius-sm: 4px;
  --radius: 8px;
  --radius-lg: 12px;

  --shadow-sm: 0 1px 2px rgba(17, 24, 39, 0.06);
  --shadow: 0 1px 3px rgba(17, 24, 39, 0.08), 0 1px 2px rgba(17, 24, 39, 0.04);

  --width-page: 1200px;
  --width-text: 68ch;

  --header-height: 64px;

  /* Medidas del lateral de .layout-doc (hoy solo la ficha de ayuda de
     contacto). Heredan el 300x250 del rectangulo publicitario que ocupaba
     ese hueco antes del rediseno 07/2026 (AdSense eliminado): cambiarlas
     cambiaria el reparto de columnas de la pagina de contacto. */
  --lateral-width: 300px;
  --lateral-height: 250px;

  /* El hueco de imagen (seccion 20) no tiene medidas propias aqui: coge de
     ancho --width-text, el mismo que el titular y la entradilla de su
     seccion, y de alto lo que salga del aspect-ratio 16:9. Asi comparte los
     dos bordes con el texto al que acompana en vez de tener un ancho suyo
     que no cuadra con nada. */
}

/* -------------------------------------------------------------------------
   2. REINICIO
   ------------------------------------------------------------------------- */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background-color: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-base);
  font-size: var(--size-base);
  line-height: var(--line-base);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

h1,
h2,
h3,
h4 {
  margin: 0 0 var(--space-3);
  line-height: var(--line-tight);
  font-weight: 700;
  color: var(--color-text);
}

h1 { font-size: var(--size-3xl); letter-spacing: -0.02em; }
h2 { font-size: var(--size-2xl); letter-spacing: -0.01em; }
h3 { font-size: var(--size-xl); }
h4 { font-size: var(--size-lg); }

p { margin: 0 0 var(--space-4); }
p:last-child { margin-bottom: 0; }

a {
  color: var(--color-brand);
  text-decoration: underline;
  text-underline-offset: 2px;
}
a:hover { color: var(--color-brand-dark); }

img,
svg {
  max-width: 100%;
}

img {
  height: auto;
  display: block;
}

ul, ol { margin: 0 0 var(--space-4); padding-left: var(--space-5); }
li { margin-bottom: var(--space-2); }

hr {
  border: 0;
  border-top: 1px solid var(--color-border);
  margin: var(--space-6) 0;
}

/* Accesibilidad: el foco tiene que verse. Lo agradecieron expresamente. */
:focus-visible {
  outline: 3px solid var(--color-focus);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* -------------------------------------------------------------------------
   3. UTILIDADES DE ESTRUCTURA
   ------------------------------------------------------------------------- */
.container {
  width: 100%;
  max-width: var(--width-page);
  margin-inline: auto;
  padding-inline: var(--space-4);
}

/* -------------------------------------------------------------------------
   MAQUETACION A DOS COLUMNAS DE LAS PAGINAS DE DOCUMENTO
   (legales, preguntas frecuentes, formularios y fichas de tipo)

   Por que existe, medido a 1440 px sobre el build anterior:
   el contenedor deja 1168 px utiles, pero .prose, .faq y .form estan topados
   en 68ch = 686 px y van pegados a la izquierda. Sobraban 482 px vacios a la
   derecha, y el rectangulo de publicidad iba centrado en el contenedor
   (eje 584) mientras el texto tenia el eje en 343: 241 px de desvio en unas
   paginas y 675 px en otras, en 29 de las 31 paginas.

   Con esta rejilla el texto conserva sus 68 ch —que es lo que mantiene la
   linea legible— y los 482 px muertos se los queda el anuncio, que ademas se
   ve mientras se lee. Los dos bordes exteriores caen sobre los bordes del
   contenedor: 0 px de desvio.

   La columna del anuncio se declara con la anchura EXACTA del rectangulo, no
   con un porcentaje: asi el hueco esta reservado desde el primer pintado y el
   texto no se recoloca cuando AdSense rellena.

   Sin position:sticky en la barra lateral: regla del cliente.
   ------------------------------------------------------------------------- */
.layout-doc {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-6);
  align-items: start;
}

.layout-doc__principal {
  /* Contenedor de consulta: lo que manda dentro de esta columna es SU ancho
     (686 px con la barra lateral puesta), nunca el de la ventana. */
  container-type: inline-size;
  min-width: 0;
  /* En una sola columna el tope de 68 ch lo pone la propia columna, para que
     ninguna linea se vaya a 990 px de ancho entre 768 y 1023 px. */
  max-width: var(--width-text);
}

/* Los bloques de dentro ya no ponen su propio tope: lo pone la columna.
   Si cada uno pusiera el suyo, los bordes derechos no coincidirian: 68 ch de
   .prose son 686 px y 68 ch de .pagina-texto__fecha, que va en 0,875rem, son
   601 px. Medido: 85 px de diferencia entre esos dos bloques en
   /es-ES/cookies/. */
.layout-doc__principal .prose,
.layout-doc__principal .faq,
.layout-doc__principal .faq-tema__caja,
.layout-doc__principal .form,
.layout-doc__principal .formulario__pie,
.layout-doc__principal .proteccion-datos,
.layout-doc__principal .pagina-texto__fecha,
.layout-doc__principal .pagina-texto__indice,
.layout-doc__principal .section__head,
.layout-doc__principal .intro-tipo {
  max-width: none;
}

.layout-doc__lateral {
  display: grid;
  gap: var(--space-5);
  align-content: start;
  justify-items: center;
  /* En una sola columna la barra lateral mide LO MISMO que la columna de
     texto, no todo el contenedor. Asi el anuncio, que va centrado, cae sobre
     el mismo eje que el texto. Sin este tope, a 768 px el texto tenia el eje
     en 343 y el anuncio en 368: el mismo fallo de dos ejes que se ha
     arreglado en escritorio, en pequeno. */
  max-width: var(--width-text);
  /* Altura reservada aunque la columna este vacia: si el hueco naciera del
     contenido, al llegar la ficha empujaria lo de debajo. */
  min-height: var(--lateral-height);
}

/* A partir de 1024 px caben las dos columnas: 686 + 32 + 300 = 1018 px, y el
   contenedor mas estrecho que llega aqui deja 992 px utiles, con lo que la
   columna de texto se encoge sola en ese tramo sin desbordar. */
@media (min-width: 1024px) {
  .layout-doc {
    grid-template-columns: minmax(0, var(--width-text)) var(--lateral-width);
    /* El sobrante (1168 - 686 - 300 - 32 = 150 px a 1440) va al hueco central,
       no al borde: las dos columnas cierran contra el contenedor. */
    justify-content: space-between;
  }

  .layout-doc__principal {
    max-width: none;
  }
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  left: var(--space-4);
  top: -100px;
  z-index: 100;
  background: var(--color-brand);
  color: #fff;
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius);
  text-decoration: none;
  transition: top var(--dur-micro) var(--curva);
}
.skip-link:focus {
  top: var(--space-2);
  color: #fff;
}

/* -------------------------------------------------------------------------
   4. CABECERA — unico elemento con sticky permitido
   ------------------------------------------------------------------------- */
.header {
  position: sticky;
  top: 0;
  z-index: 50;
  background-color: var(--color-bg);
  border-bottom: 1px solid var(--color-border);
  height: var(--header-height);
  min-height: var(--header-height);
  display: flex;
  align-items: center;
}

.header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  width: 100%;
}

.header__logo {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  /* padding-block (01/08): la cabecera mide 64px de alto (mas que de sobra,
     ver .header) pero el enlace en si solo media ~28px de zona tocable
     (el alto del icono). El relleno vertical no cambia el aspecto, solo
     agranda la caja clicable dentro de la cabecera centrada. */
  padding-block: 8px;
  font-weight: 700;
  font-size: var(--size-lg);
  color: var(--color-text);
  text-decoration: none;
  white-space: nowrap;
}
.header__logo:hover { color: var(--color-text); }

.header__logo-mark {
  width: 28px;
  height: 28px;
  flex: 0 0 28px;
  color: var(--color-brand);
}

.header__nav {
  display: flex;
  align-items: center;
  gap: var(--space-5);
}

.header__nav-list {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  list-style: none;
  margin: 0;
  padding: 0;
}

.header__nav-item {
  margin: 0;
}

.header__link {
  color: var(--color-text-muted);
  text-decoration: none;
  font-size: var(--size-sm);
  font-weight: 500;
  white-space: nowrap;
}
.header__link:hover,
.header__link--active {
  color: var(--color-brand);
}

/* El menu se oculta por debajo de 1024 px, no de 768.
   Medido: a 768 px de ventana el logo, los cuatro enlaces y el boton suman
   48 px mas de los que caben, y desbordaban horizontalmente en las 31 paginas.
   A 1024 px si caben (medido: 0 px de desborde). Por eso el corte esta aqui y
   no en el breakpoint "de movil" habitual.
   Por debajo del corte los enlaces y el selector de idioma se mueven al
   desplegable .header__menu (logo + hamburguesa + CTA es lo que queda en
   la barra), asi no se repite el desborde que este mismo comentario
   describia antes de que existiera el menu movil. */
@media (max-width: 1023px) {
  .header__nav-list { display: none; }
  /* .header__idioma se oculta en la seccion 23: su regla base (display:
     inline-block) esta mas abajo en el fichero y con igual especificidad
     ganaria por orden de cascada si el "none" se pusiera aqui. */
}

@media (min-width: 1024px) {
  .header__menu { display: none; }
}

.header__menu {
  position: relative;
}

.header__menu-boton {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background-color: transparent;
  color: var(--color-text);
  cursor: pointer;
  list-style: none;
}
.header__menu-boton::-webkit-details-marker { display: none; }
.header__menu-boton::marker { content: ''; }
.header__menu-boton:hover { border-color: currentColor; }

.header__menu-icono--cerrar { display: none; }
.header__menu[open] .header__menu-icono--abrir { display: none; }
.header__menu[open] .header__menu-icono--cerrar { display: block; }

.header__menu-panel {
  position: absolute;
  top: calc(100% + var(--space-2));
  right: 0;
  z-index: 10;
  min-width: 220px;
  background-color: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: var(--space-3);
}

.header__menu-lista {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  list-style: none;
  margin: 0 0 var(--space-3);
  padding: 0;
}

.header__menu-link {
  /* flex+min-height (01/08): con solo padding block:8px la fila medía
     ~38px; el menu movil es el unico sitio donde se navega el sitio
     entero en pantallas estrechas, asi que se sube al minimo tactil. */
  display: flex;
  align-items: center;
  min-height: 44px;
  padding-inline: var(--space-2);
  border-radius: var(--radius-sm);
  color: var(--color-text-muted);
  text-decoration: none;
  font-size: var(--size-sm);
  font-weight: 500;
  white-space: nowrap;
}
.header__menu-link:hover,
.header__menu-link--active {
  color: var(--color-brand);
  background-color: var(--color-surface);
}

.header__menu-idioma {
  display: block;
  padding: var(--space-2);
  border-top: 1px solid var(--color-border);
  margin-top: var(--space-2);
  padding-top: var(--space-3);
  color: inherit;
  text-decoration: none;
  font-size: var(--size-sm);
  font-weight: 600;
  white-space: nowrap;
}
.header__menu-idioma:hover { color: var(--color-brand); }

/* -------------------------------------------------------------------------
   5. PIE
   ------------------------------------------------------------------------- */
.footer {
  margin-top: auto;
  background-color: var(--color-surface);
  border-top: 1px solid var(--color-border);
  padding-block: var(--space-6) var(--space-5);
  font-size: var(--size-sm);
}

/* Cuatro bloques. El numero de columnas se fija en divisores de cuatro (2 y
   4): con auto-fit salian tres a 768 px y el bloque de ayuda se quedaba solo,
   a todo lo ancho, en una cuarta fila. Dos columnas ya desde movil para que
   el pie no se dispare de alto apilando los cuatro bloques uno debajo de
   otro. */
.footer__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-5);
  margin-bottom: var(--space-5);
}

@media (min-width: 900px) {
  .footer__grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

.footer__heading {
  font-size: var(--size-sm);
  font-weight: 700;
  margin-bottom: var(--space-3);
}

.footer__list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.footer__list li { margin-bottom: var(--space-2); }

.footer__link {
  color: var(--color-text-muted);
  text-decoration: none;
}
.footer__link:hover {
  color: var(--color-brand);
  text-decoration: underline;
}

/* Lema bajo el logotipo (rediseno 07/2026): la promesa del pago unico. */
.footer__tagline {
  margin-top: var(--space-3);
  max-width: 28ch;
  color: var(--color-text-muted);
}

.footer__bottom {
  border-top: 1px solid var(--color-border);
  padding-top: var(--space-4);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
  justify-content: space-between;
  color: var(--color-text-soft);
  font-size: var(--size-xs);
}

/* -------------------------------------------------------------------------
   6. MIGAS DE PAN — encima del contenido en las paginas interiores
   ------------------------------------------------------------------------- */
.breadcrumbs {
  padding-block: var(--space-3);
  font-size: var(--size-sm);
  color: var(--color-text-soft);
}

.breadcrumbs__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}
.breadcrumbs__list li { margin: 0; }

.breadcrumbs__sep {
  color: var(--color-border-strong);
}

.breadcrumbs a {
  color: var(--color-text-muted);
  text-decoration: none;
}
.breadcrumbs a:hover { text-decoration: underline; }

/* -------------------------------------------------------------------------
   7. PUBLICIDAD — ELIMINADA en el rediseno 07/2026.
   El sitio pasa a landing de conversion con pago unico y AdSense sale de
   todas las paginas (docs/plan-rediseno.md): las reglas .ad-slot que vivian
   aqui se han borrado junto con el componente AdSlot.astro. Se conserva la
   cabecera para no renumerar las secciones siguientes.
   ------------------------------------------------------------------------- */

/* -------------------------------------------------------------------------
   8. BOTONES
   ------------------------------------------------------------------------- */
.button {
  display: flex;               /* NO inline-flex: ignora los margenes auto */
  width: fit-content;          /* auto ocuparia todo el ancho */
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-5);
  min-height: 44px;            /* objetivo tactil */
  border: 1px solid transparent;
  border-radius: var(--radius);
  font-family: inherit;
  font-size: var(--size-sm);
  font-weight: 600;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  background-color: var(--color-brand);
  color: #ffffff;
}
.button:hover {
  background-color: var(--color-brand-dark);
  color: #ffffff;
}

.button--secondary {
  background-color: var(--color-bg);
  color: var(--color-brand);
  border-color: var(--color-border-strong);
}
.button--secondary:hover {
  background-color: var(--color-brand-light);
  color: var(--color-brand-dark);
}

.button--ghost {
  background-color: transparent;
  color: var(--color-text-muted);
  border-color: transparent;
}
.button--ghost:hover {
  background-color: var(--color-surface);
  color: var(--color-text);
}

.button--center { margin-inline: auto; }
.button--block { width: 100%; }
.button--small { min-height: 36px; padding: var(--space-2) var(--space-4); }

/* El CTA "Create QR code" de la cabecera reutiliza .button--small y sale en
   las 120 paginas del sitio: 36px de alto se quedaba 8px corto del minimo
   tactil recomendado. Acotado a la cabecera para no tocar los botones
   auxiliares del editor (Deshacer/Rehacer/Invertir...) que tambien usan
   .button--small y estan pensados mas compactos a proposito (01/08). */
.header__nav .button--small {
  min-height: 44px;
}

.button[disabled],
.button[aria-disabled='true'] {
  opacity: 0.55;
  cursor: not-allowed;
}

.button__icon {
  width: 18px;
  height: 18px;
  flex: 0 0 18px;
}

/* -------------------------------------------------------------------------
   9. SECCIONES Y TARJETAS
   ------------------------------------------------------------------------- */
.section {
  padding-block: var(--space-7);
}
.section--tight { padding-block: var(--space-6); }
.section--surface { background-color: var(--color-surface); }

/* Un solo criterio de alineacion en todo el sitio: titulo, entradilla,
   contenido y boton de cierre de una seccion van al mismo eje, el izquierdo.
   La unica excepcion es .cierre, que centra las tres cosas a la vez. */
.section__head {
  max-width: var(--width-text);
  margin-bottom: var(--space-6);
}

.section__lead {
  color: var(--color-text-muted);
  font-size: var(--size-lg);
}

/* Rejilla de tarjetas. Consultas de contenedor activadas: lo que manda es
   el ancho de la rejilla, no el de la ventana. */
.card-grid {
  container-type: inline-size;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: var(--space-4);
  list-style: none;
  margin: 0;
  padding: 0;
}
.card-grid > li { margin: 0; }

.card {
  display: grid;
  grid-template-rows: auto auto 1fr;   /* la accion se apoya abajo */
  height: 100%;
  padding: var(--space-4);
  background-color: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  text-decoration: none;
  color: inherit;
}
.card:hover {
  border-color: var(--color-brand);
  box-shadow: var(--shadow);
  color: inherit;
}

.card__icon {
  width: 32px;
  height: 32px;
  flex: 0 0 32px;
  color: var(--color-brand);
  margin-bottom: var(--space-3);
}

.card__title {
  font-size: var(--size-base);
  font-weight: 600;
  margin-bottom: var(--space-1);
  /* Altura reservada a 1 linea: todas las tarjetas de la fila miden igual */
  min-height: calc(1.35em * 1);
}

.card__text {
  font-size: var(--size-sm);
  color: var(--color-text-muted);
  margin: 0;
  /* Recorte a 2 lineas con la altura reservada, para que ninguna tarjeta
     de la misma fila visual sea mas alta que otra. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: calc(1.5em * 2);
}

.card__badge {
  display: inline-block;
  align-self: start;
  /* .card es un grid: sin esto el navegador estira la etiqueta a todo el
     ancho de la tarjeta (medido: 246 px dentro de una tarjeta de 280 px,
     cuando el texto ocupa unos 66). Venia suelto en src/estilos/portada.css
     y se ha traido a la regla original al fusionar. */
  justify-self: start;
  margin-top: var(--space-3);
  padding: 2px var(--space-2);
  border-radius: var(--radius-sm);
  font-size: var(--size-xs);
  font-weight: 600;
  letter-spacing: 0.02em;
  background-color: var(--color-brand-light);
  color: var(--color-brand-dark);
}
.card__badge--static {
  background-color: var(--color-surface);
  color: var(--color-text-soft);
}

/* -------------------------------------------------------------------------
   10. PORTADA
   ------------------------------------------------------------------------- */
.hero {
  padding-block: var(--space-7);
  border-bottom: 1px solid var(--color-border);
}

.hero__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-6);
  align-items: center;
}

@media (min-width: 1024px) {
  .hero__grid { grid-template-columns: 1.1fr 0.9fr; }
}

.hero__title {
  font-size: var(--size-3xl);
  margin-bottom: var(--space-4);
}

.hero__lead {
  font-size: var(--size-lg);
  color: var(--color-text-muted);
  max-width: 52ch;
  margin-bottom: var(--space-5);
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}
.hero__actions .button { width: auto; }

/* Caja de la vista previa de portada: alto fijo, sin sorpresas al cargar */
.hero__preview {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 320px;
  min-height: 320px;
  background-color: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
}

/* Pasos numerados. Son tres: o los tres en fila o los tres apilados.
   Con auto-fit salian 2 + 1 a 768 px y el tercer paso quedaba solo. */
.steps {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-5);
  list-style: none;
  margin: 0;
  padding: 0;
}

@media (min-width: 860px) {
  .steps { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.steps > li { margin: 0; }

.step__number {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  flex: 0 0 36px;
  border-radius: 50%;
  background-color: var(--color-brand);
  color: #fff;
  font-weight: 700;
  margin-bottom: var(--space-3);
}

.step__title {
  font-size: var(--size-lg);
  margin-bottom: var(--space-2);
}

.step__text {
  color: var(--color-text-muted);
  font-size: var(--size-sm);
  margin: 0;
}

/* Lista de ventajas */
.feature-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--space-5);
  list-style: none;
  margin: 0;
  padding: 0;
}
.feature-list > li { margin: 0; }

/* Modificador para las listas de SEIS ventajas. Con el auto-fit general salen
   cuatro en la primera fila y dos en la segunda, que queda coja. A partir de
   1024 px se fuerzan tres columnas y quedan 3 + 3.
   Aqui la consulta correcta es @media y no @container: esta lista ocupa el
   contenedor entero de la seccion, sin ninguna barra lateral por medio, asi
   que lo que manda es el ancho de la ventana. */
@media (min-width: 1024px) {
  .feature-list--tres {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* -------------------------------------------------------------------------
   REJILLAS DE CUATRO TARJETAS
   Con el auto-fill general salen tres columnas a 1024 px y la cuarta tarjeta
   queda suelta debajo. Estos modificadores fijan el numero de columnas en
   divisores de cuatro —1, 2 y 4— asi que la ultima fila no queda nunca coja.

   Se usan en las dos rejillas de la portada, en los cuatro usos y en los
   cuatro tipos relacionados de las 21 paginas de tipo: los 21 tipos tienen
   exactamente 4 usos y 4 relacionados (comprobado sobre los datos, no a ojo).

   La consulta es @media porque estas rejillas ocupan el contenedor entero de
   su seccion, sin barra lateral por medio: manda el ancho de la ventana.
   NO usarlos en una rejilla que viva dentro de .layout-doc__principal, donde
   el ancho lo marca la columna de 686 px y no la ventana.
   ------------------------------------------------------------------------- */
@media (min-width: 520px) {
  .card-grid--cuatro,
  .feature-list--cuatro {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 1000px) {
  .card-grid--cuatro,
  .feature-list--cuatro {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

.feature__icon {
  width: 28px;
  height: 28px;
  flex: 0 0 28px;
  color: var(--color-brand);
  margin-bottom: var(--space-2);
}

.feature__title {
  font-size: var(--size-base);
  font-weight: 600;
  margin-bottom: var(--space-1);
}

.feature__text {
  font-size: var(--size-sm);
  color: var(--color-text-muted);
  margin: 0;
}

/* -------------------------------------------------------------------------
   11. DESPLEGABLES SIN JAVASCRIPT (<details>/<summary>)
   La altura se reserva en la caja de FUERA, nunca en el <details>: el
   navegador trata al <summary> de forma especial y la reserva no se respeta.
   ------------------------------------------------------------------------- */
.faq {
  max-width: var(--width-text);
}

.faq__item {
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  margin-bottom: var(--space-3);
  background-color: var(--color-bg);
}

.faq__summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-4);
  min-height: 56px;
  font-weight: 600;
  cursor: pointer;
  list-style: none;
}
.faq__summary::-webkit-details-marker { display: none; }

.faq__chevron {
  width: 20px;
  height: 20px;
  flex: 0 0 20px;
  color: var(--color-text-soft);
  transition: transform var(--dur-micro) var(--curva);
}
.faq__item[open] .faq__chevron { transform: rotate(180deg); }

.faq__content {
  padding: 0 var(--space-4) var(--space-4);
  color: var(--color-text-muted);
}

/* -------------------------------------------------------------------------
   12. FORMULARIOS
   ------------------------------------------------------------------------- */
.form {
  display: grid;
  gap: var(--space-4);
  max-width: var(--width-text);
}

.field {
  display: grid;
  gap: var(--space-2);
}

.field__label {
  font-size: var(--size-sm);
  font-weight: 600;
}

.field__required {
  color: var(--color-danger);
  margin-left: 2px;
}

.field__control {
  width: 100%;
  min-height: 44px;
  padding: var(--space-2) var(--space-3);
  font-family: inherit;
  font-size: var(--size-base);
  color: var(--color-text);
  background-color: var(--color-bg);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius);
}
.field__control:hover { border-color: var(--color-text-soft); }

textarea.field__control {
  min-height: 120px;
  resize: vertical;
  line-height: var(--line-base);
}

.field__help {
  font-size: var(--size-xs);
  color: var(--color-text-soft);
  /* Reservado siempre, aunque no haya texto: evita el salto al mostrarlo */
  min-height: 1.2em;
}

.field--inline {
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: var(--space-3);
}

.field__checkbox {
  width: 20px;
  height: 20px;
  flex: 0 0 20px;
  accent-color: var(--color-brand);
}

/* -------------------------------------------------------------------------
   13. AVISOS
   ------------------------------------------------------------------------- */
.notice {
  display: flex;
  gap: var(--space-3);
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-left-width: 4px;
  border-radius: var(--radius);
  background-color: var(--color-surface);
  font-size: var(--size-sm);
}

.notice__icon {
  width: 20px;
  height: 20px;
  flex: 0 0 20px;
  margin-top: 2px;
}

.notice--info {
  border-left-color: var(--color-brand);
  background-color: var(--color-brand-light);
}
.notice--info .notice__icon { color: var(--color-brand); }

.notice--success {
  border-left-color: var(--color-success);
  background-color: var(--color-success-bg);
}
.notice--success .notice__icon { color: var(--color-success); }

.notice--warning {
  border-left-color: var(--color-warning);
  background-color: var(--color-warning-bg);
}
.notice--warning .notice__icon { color: var(--color-warning); }

.notice--danger {
  border-left-color: var(--color-danger);
  background-color: var(--color-danger-bg);
}
.notice--danger .notice__icon { color: var(--color-danger); }

/* -------------------------------------------------------------------------
   14. CONTENIDO DE TEXTO (legales, articulos)
   ------------------------------------------------------------------------- */
.prose {
  max-width: var(--width-text);
}
.prose h2 { margin-top: var(--space-6); font-size: var(--size-xl); }
.prose h3 { margin-top: var(--space-5); font-size: var(--size-lg); }
.prose li { color: var(--color-text-muted); }
.prose table {
  width: 100%;
  border-collapse: collapse;
  margin-bottom: var(--space-5);
  font-size: var(--size-sm);
}
.prose th,
.prose td {
  border: 1px solid var(--color-border);
  padding: var(--space-2) var(--space-3);
  text-align: left;
  vertical-align: top;
}
.prose th { background-color: var(--color-surface); font-weight: 600; }

/* Contenedor de desbordamiento para tablas anchas en movil */
.table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

/* -------------------------------------------------------------------------
   15. PORTADA (/es-ES/)
   Fusionado desde src/estilos/portada.css (ese directorio ya no existe).
   ------------------------------------------------------------------------- */

/* -------------------------------------------------------------------------
   HERO — vista previa con un codigo QR real
   El SVG es un QR de verdad (29x29 modulos, correccion M) que apunta a
   /es-ES/. Se dibujo una vez con qrcode-generator y se comprobo con jsQR
   antes de pegarlo: decodifica "https://qrcreator.jrnetmedia.com/es-ES/".
   Va estatico en el HTML porque la portada no lleva ni una etiqueta <script>.
   ------------------------------------------------------------------------- */
.hero__qr {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  margin: 0;
}

.hero__qr-svg {
  /* Medida fija: la caja de fuera (.hero__preview) mide 320 px y aqui caben
     200 de codigo + 12 de hueco + el pie. Nada se mueve al terminar de cargar. */
  width: 200px;
  height: 200px;
  flex: 0 0 200px;
  padding: 0;
  background-color: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  color: var(--color-text);
}

.hero__qr-pie {
  font-size: var(--size-xs);
  color: var(--color-text-soft);
  text-align: center;
  margin: 0;
}

.hero__nota {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-4);
  margin-bottom: 0;
  font-size: var(--size-sm);
  color: var(--color-text-muted);
}

.hero__nota-icono {
  width: 18px;
  height: 18px;
  flex: 0 0 18px;
  color: var(--color-success);
}

/* -------------------------------------------------------------------------
   PIE DE SECCION — el enlace que cierra un bloque (ver todos los tipos,
   ver todas las preguntas). Generico a proposito.
   ------------------------------------------------------------------------- */
.section__foot {
  margin-top: var(--space-6);
}

/* -------------------------------------------------------------------------
   PREGUNTAS DE LA PORTADA — dos columnas

   Antes era una columna de 686 px pegada a la izquierda con 482 px vacios al
   lado, medido a 1440 px. En dos columnas el bloque ocupa el contenedor
   entero y las cuatro preguntas se leen de un vistazo.

   Ya no se reserva altura: las respuestas van siempre visibles (aqui no queda
   ni un <details>), asi que no hay nada que pueda crecer y desplazar la
   pagina. Las min-height de 512 / 360 / 336 px que habia aqui eran de la
   version con desplegables y hoy solo dejaban hueco muerto.

   align-items:stretch es explicito a proposito: las dos preguntas de una
   misma fila tienen que medir igual aunque su respuesta ocupe menos lineas.
   ------------------------------------------------------------------------- */
.faq--portada {
  /* .faq esta topado en 68 ch; aqui el bloque ocupa el contenedor entero. */
  max-width: none;
  display: grid;
  gap: var(--space-3);
  align-items: stretch;
}

.faq--portada .faq__item {
  margin-bottom: 0;
}

@media (min-width: 768px) {
  .faq--portada {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* -------------------------------------------------------------------------
   16. PAGINAS DE ATERRIZAJE POR TIPO (/es-ES/generar/<slug>/ y su indice)
   Fusionado desde src/estilos/aterrizaje.css (ese directorio ya no existe).
   ------------------------------------------------------------------------- */

/* -------------------------------------------------------------------------
   1. BOTON GRANDE — modificador del bloque .button
   La llamada principal de estas paginas lleva el nombre del tipo dentro
   ("Crear mi codigo QR de Galeria de imagenes"). .button es nowrap, que en
   movil se saldria de la pantalla: aqui el texto se parte en varias lineas.
   ------------------------------------------------------------------------- */
.button--grande {
  padding: var(--space-4) var(--space-6);
  min-height: 52px;
  font-size: var(--size-base);
  white-space: normal;
  text-align: center;
}

/* -------------------------------------------------------------------------
   2. ENTRADILLA DE LA PAGINA DE TIPO
   ------------------------------------------------------------------------- */
.intro-tipo {
  max-width: var(--width-text);
}

/* La cabecera a dos columnas de esta pagina esta en la seccion 21, con el
   resto de reglas del hueco de imagen. */

/* Icono del tipo + insignia dinamico/estatico en una fila (31/07: el icono
   quedaba encima de la insignia, dos elementos sueltos sin relacion visual
   entre si). */
.intro-tipo__cabecera {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-3);
}

.intro-tipo__icono {
  width: 40px;
  height: 40px;
  flex: 0 0 40px;
  color: var(--color-brand);
}

.intro-tipo__titulo {
  margin-bottom: var(--space-3);
}

.intro-tipo__lead {
  font-size: var(--size-lg);
  color: var(--color-text-muted);
  margin-bottom: var(--space-4);
}

.intro-tipo__texto {
  color: var(--color-text-muted);
}

.intro-tipo__acciones {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-5);
}

/* Etiqueta de dinamico / estatico, encima del titular */
.marca-tipo {
  display: inline-block;
  padding: 2px var(--space-2);
  border-radius: var(--radius-sm);
  background-color: var(--color-brand-light);
  color: var(--color-brand-dark);
  font-size: var(--size-xs);
  font-weight: 600;
  letter-spacing: 0.02em;
}

.marca-tipo--estatico {
  background-color: var(--color-surface);
  color: var(--color-text-muted);
}

/* -------------------------------------------------------------------------
   3. QUE DATOS NECESITAS — campos del formulario del tipo
   ------------------------------------------------------------------------- */
.campos {
  display: grid;
  /* auto-FIT, no auto-fill: con auto-fill las columnas vacias se quedan
     ocupando sitio y con 2 campos (url, texto, url-fija, youtube) quedaban
     dos columnas muertas y las tarjetas encogidas a la izquierda. Con
     auto-fit las pistas vacias colapsan y las tarjetas se reparten el ancho.
     16 de los 21 tipos tienen un numero de campos que no es multiplo de 4. */
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--space-3);
  list-style: none;
  margin: 0;
  padding: 0;
}
.campos > li {
  margin: 0;
}

.campo {
  height: 100%;
  padding: var(--space-4);
  background-color: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
}

.campo__nombre {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2);
  margin-bottom: var(--space-1);
  font-size: var(--size-sm);
  font-weight: 600;
}

.campo__marca {
  padding: 1px var(--space-2);
  border-radius: var(--radius-sm);
  background-color: var(--color-brand-light);
  color: var(--color-brand-dark);
  font-size: var(--size-xs);
  font-weight: 600;
  white-space: nowrap;
}

.campo__marca--opcional {
  background-color: var(--color-surface-alt);
  color: var(--color-text-muted);
}

.campo__ayuda {
  margin: 0;
  font-size: var(--size-sm);
  color: var(--color-text-muted);
}

/* -------------------------------------------------------------------------
   4. PARRAFO ATENUADO
   La rejilla de "texto + publicidad al lado" ya no vive aqui: es .layout-doc,
   que la comparten las paginas de tipo y las de texto.
   ------------------------------------------------------------------------- */
.texto-suave {
  color: var(--color-text-muted);
}

/* -------------------------------------------------------------------------
   5. CIERRE DE PAGINA
   ------------------------------------------------------------------------- */
.cierre {
  max-width: var(--width-text);
  margin-inline: auto;
  text-align: center;
}

.cierre__titulo {
  margin-bottom: var(--space-3);
}

.cierre__texto {
  color: var(--color-text-muted);
  margin-bottom: var(--space-5);
}

.cierre__accion {
  margin-top: var(--space-2);
}

/* -------------------------------------------------------------------------
   17. PAGINAS DE TEXTO, LEGALES, PREGUNTAS FRECUENTES Y FORMULARIOS
   Fusionado desde src/estilos/paginas-texto.css (ese directorio ya no existe).
   ------------------------------------------------------------------------- */

/* -------------------------------------------------------------------------
   A. ESTRUCTURA COMUN DE LAS PAGINAS DE TEXTO
   ------------------------------------------------------------------------- */
.pagina-texto__fecha {
  max-width: var(--width-text);
  margin-bottom: var(--space-5);
  font-size: var(--size-sm);
  color: var(--color-text-soft);
}

/* Los titulos a los que apunta el indice no pueden quedar tapados por la
   cabecera fija (64 px). Con scroll-behavior:smooth activo se nota mucho. */
.pagina-texto h2[id],
.pagina-texto h3[id] {
  scroll-margin-top: calc(var(--header-height) + var(--space-4));
}

.pagina-texto__indice {
  max-width: var(--width-text);
  margin-bottom: var(--space-6);
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background-color: var(--color-surface);
}

.pagina-texto__indice-titulo {
  margin-bottom: var(--space-3);
  font-size: var(--size-sm);
  font-weight: 700;
}

.pagina-texto__indice-lista {
  columns: 2;
  column-gap: var(--space-5);
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: var(--size-sm);
}

.pagina-texto__indice-lista li {
  margin-bottom: var(--space-2);
  break-inside: avoid;
}

@media (max-width: 600px) {
  .pagina-texto__indice-lista { columns: 1; }
}

/* Ficha de la barra lateral (.layout-doc__lateral). Ocupa el ancho de la
   columna, que son los mismos 300 px del rectangulo de publicidad. */
.pagina-texto__ficha {
  width: 100%;
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background-color: var(--color-surface);
  font-size: var(--size-sm);
}

.pagina-texto__ficha-titulo {
  margin-bottom: var(--space-2);
  font-size: var(--size-base);
}

.pagina-texto__ficha-lista {
  list-style: none;
  margin: 0;
  padding: 0;
  color: var(--color-text-muted);
}

.pagina-texto__ficha-lista li { margin-bottom: var(--space-2); }
.pagina-texto__ficha-lista li:last-child { margin-bottom: 0; }

/* .notice no trae margenes propios (se usa dentro de otras cajas). Cuando va
   suelto en una pagina de texto necesita separacion. */
.pagina-texto__aviso {
  margin-bottom: var(--space-5);
}

.pagina-texto__aviso--final {
  margin-top: var(--space-6);
  margin-bottom: 0;
}

/* Separacion entre bloques sueltos (una lista de ventajas, una rejilla)
   y el texto que viene detras. */
.pagina-texto__bloque {
  margin-bottom: var(--space-7);
}

/* Titulo de un bloque suelto dentro de una columna de documento: una rejilla
   de ventajas, un formulario. Va a la MISMA escala y con la misma separacion
   que los h2 de .prose (--size-xl y --space-6 por arriba).
   Antes esos titulos usaban .section__head, que es --size-2xl y no lleva
   margen superior: en /es-ES/quienes-somos/ y /es-ES/dmca/ convivian dos
   tamanos distintos de titulo del mismo nivel, y "Como trabajamos" quedaba
   pegado al parrafo de encima. */
.bloque-titulo {
  margin-top: var(--space-6);
  margin-bottom: var(--space-4);
  font-size: var(--size-xl);
}

/* -------------------------------------------------------------------------
   B. BLOQUES DE PREGUNTAS FRECUENTES

   La altura la reserva la caja de FUERA (.faq-tema__caja), nunca el
   <details>: el navegador trata al <summary> de forma especial y una
   min-height puesta en el <details> no impide el desplazamiento.

   Variables:
     --faq-cerrado   altura de una pregunta cerrada, margen inferior incluido
     --faq-items     numero de preguntas del bloque
     --faq-respuesta altura de la respuesta MAS LARGA del bloque

   Medido en el navegador sobre la pagina ya construida, no estimado:
     1280 px de ancho  pregunta cerrada 70 px
                       respuesta mas larga por bloque:
                       basico 214 · tipos 190 · diseno 461 · impresion 165
      375 px de ancho  pregunta cerrada 95 px (el titulo ocupa dos lineas)
                       respuesta mas larga por bloque:
                       basico 438 · tipos 438 · diseno 982 · impresion 363
   Los valores de abajo llevan unos pocos px de holgura sobre esas medidas.
   Si se cambia el texto de una respuesta, hay que volver a medir.

   Con esto, abrir una respuesta cualquiera no mueve ni el pie ni los huecos
   de publicidad. Abrir dos a la vez si desplaza lo de debajo, pero eso ya es
   una accion del usuario y no cuenta como layout shift.

   La primera pregunta de cada bloque va abierta de serie y es la de la
   respuesta mas larga: asi el espacio reservado se ve ocupado al cargar y
   no queda un hueco blanco.
   ------------------------------------------------------------------------- */
.faq-tema {
  margin-bottom: var(--space-6);
}

.faq-tema__titulo {
  margin-bottom: var(--space-4);
  font-size: var(--size-xl);
}

.faq-tema__caja {
  --faq-cerrado: 70px;
  --faq-items: 5;
  --faq-respuesta: 220px;
  min-height: calc(var(--faq-cerrado) * var(--faq-items) + var(--faq-respuesta));
}

.faq-tema__caja--basico { --faq-respuesta: 220px; }
.faq-tema__caja--tipos { --faq-respuesta: 196px; }
.faq-tema__caja--diseno { --faq-respuesta: 468px; }
.faq-tema__caja--impresion { --faq-respuesta: 172px; }

/* Por debajo de 640 px la pregunta ocupa dos lineas y la respuesta se va al
   doble de alto. Entre 590 y 640 px el texto ya no encoge mas (.faq esta
   topado en 68ch), asi que este tramo reserva de sobra, nunca de menos. */
@media (max-width: 640px) {
  .faq-tema__caja { --faq-cerrado: 95px; }
  .faq-tema__caja--basico { --faq-respuesta: 444px; }
  .faq-tema__caja--tipos { --faq-respuesta: 444px; }
  .faq-tema__caja--diseno { --faq-respuesta: 988px; }
  .faq-tema__caja--impresion { --faq-respuesta: 370px; }
}

/* Listas dentro de una respuesta: heredan el color atenuado del bloque. */
.faq__content ul,
.faq__content ol {
  margin-bottom: var(--space-4);
}

.faq__content p:last-child,
.faq__content ul:last-child {
  margin-bottom: 0;
}

/* -------------------------------------------------------------------------
   C. FORMULARIOS: PIE DEL FORMULARIO Y NOTA DE PROTECCION DE DATOS
   ------------------------------------------------------------------------- */
.formulario__pie {
  display: grid;
  gap: var(--space-4);
  max-width: var(--width-text);
  margin-top: var(--space-2);
}

.formulario__leyenda {
  font-size: var(--size-xs);
  color: var(--color-text-soft);
}

/* Bloque legal debajo del formulario. Texto pequeno pero con contraste AA.
   El tamano reducido va en la lista y NO en la caja: var(--width-text) esta
   en "ch", asi que bajar la fuente aqui estrecharia la caja y dejaria de
   alinear con el formulario. */
.proteccion-datos {
  max-width: var(--width-text);
  margin-top: var(--space-6);
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background-color: var(--color-surface);
  color: var(--color-text-muted);
}

.proteccion-datos__titulo {
  margin-bottom: var(--space-3);
  font-size: var(--size-base);
  color: var(--color-text);
}

.proteccion-datos__lista {
  margin: 0;
  padding: 0;
  font-size: var(--size-sm);
}

.proteccion-datos__lista div {
  margin-bottom: var(--space-2);
}

.proteccion-datos__lista dt {
  font-weight: 600;
  color: var(--color-text);
}

.proteccion-datos__lista dd {
  margin: 0 0 var(--space-2);
}

@media (min-width: 600px) {
  .proteccion-datos__lista div {
    display: grid;
    grid-template-columns: 10rem minmax(0, 1fr);
    gap: var(--space-3);
  }
  .proteccion-datos__lista dd { margin-bottom: 0; }
}

/* -------------------------------------------------------------------------
   18. EDITOR DE CODIGOS QR (/es-ES/editor/)
   Fusionado desde src/estilos/editor.css (ese directorio ya no existe).
   ------------------------------------------------------------------------- */

/* -------------------------------------------------------------------------
   E1. ESTRUCTURA DE LA PAGINA
   ------------------------------------------------------------------------- */
.editor {
  padding-block: var(--space-5) var(--space-7);
}

.editor__cabecera {
  max-width: var(--width-text);
  margin-bottom: var(--space-5);
}

.editor__lead {
  color: var(--color-text-muted);
  font-size: var(--size-lg);
  margin: 0;
}

.editor__noscript {
  margin-bottom: var(--space-5);
}

/* Utilidad de ocultacion controlada por JavaScript.
   Se acompana de los selectores compuestos para ganar en especificidad a
   .button y .notice sin recurrir a !important. OJO: cualquier clase con
   `display` propio declarada DESPUES en el archivo pisa a `.oculto` — el
   checkout enseñaba una tarjeta fantasma de 943px por esto (30/07). */
.oculto,
.button.oculto,
.notice.oculto,
.logo-actual__imagen.oculto,
.pago__panel.oculto,
/* 05/08/2026: los colores por ojo salian SIEMPRE, con su casilla marcada o
   sin marcar. `.colores-ojos { display: grid }` se declara mucho mas abajo
   (misma especificidad, gana por orden) y con el acordeon de colores cerrado
   el fallo no se veia. Encontrado al revisar una captura de Ceferin del
   bloque de colores, y confirmado recorriendo las paginas en un navegador:
   es el UNICO elemento del sitio que lleva .oculto y aun asi ocupa sitio. */
.colores-ojos.oculto {
  display: none;
}

/* -------------------------------------------------------------------------
   E2. INDICADOR DE PASOS
   ------------------------------------------------------------------------- */
.pasos {
  margin-bottom: var(--space-6);
  border-bottom: 1px solid var(--color-border);
  padding-bottom: var(--space-4);
}

.pasos__lista {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3) var(--space-5);
  list-style: none;
  margin: 0;
  padding: 0;
}

.pasos__item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  color: var(--color-text-soft);
  font-size: var(--size-sm);
  font-weight: 600;
  /* Altura fija: al marcar un paso cambian colores, nunca la caja */
  min-height: 36px;
}

.pasos__numero {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  flex: 0 0 28px;
  border-radius: 50%;
  border: 1px solid var(--color-border-strong);
  background-color: var(--color-bg);
  color: var(--color-text-soft);
  font-size: var(--size-sm);
  font-weight: 700;
}

.pasos__item--activo {
  color: var(--color-brand-dark);
}
.pasos__item--activo .pasos__numero {
  background-color: var(--color-brand);
  border-color: var(--color-brand);
  color: #ffffff;
}

.pasos__item--hecho {
  color: var(--color-success);
}
.pasos__item--hecho .pasos__numero {
  background-color: var(--color-success-bg);
  border-color: var(--color-success);
  color: var(--color-success);
}

/* -------------------------------------------------------------------------
   E3. PASOS
   El paso 1 llega marcado como activo desde el servidor: en la carga no se
   mueve nada. Cambiar de paso si mueve la pagina, pero eso lo provoca el
   usuario al pulsar un boton.
   ------------------------------------------------------------------------- */
.paso:not(.paso--activo) {
  display: none;
}

/* El paso 2 es un formulario y nada mas: el titulo, la entradilla, el aviso de
   errores, los campos y la barra de botones comparten ancho.
   Antes el aviso y la barra de acciones median 1168 px y los campos 686:
   dos anchos distintos dentro del mismo bloque. */
.paso--estrecho {
  max-width: var(--width-text);
}

.paso__titulo {
  font-size: var(--size-2xl);
  margin-bottom: var(--space-3);
}

.paso__lead {
  color: var(--color-text-muted);
  max-width: var(--width-text);
  margin-bottom: var(--space-5);
}

.acciones {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-top: var(--space-6);
  padding-top: var(--space-5);
  border-top: 1px solid var(--color-border);
}
.acciones--fin {
  justify-content: flex-end;
}

/* -------------------------------------------------------------------------
   E4. PASO 1 — SELECTOR DE TIPO
   ------------------------------------------------------------------------- */
.tipos {
  border: 0;
  margin: 0 0 var(--space-6);
  padding: 0;
}

.tipos__leyenda {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0;
  margin-bottom: var(--space-4);
  font-size: var(--size-lg);
  font-weight: 700;
  color: var(--color-text);
}

.tipos__leyenda-icono {
  width: 20px;
  height: 20px;
  flex: 0 0 20px;
  color: var(--color-brand);
}

.tipos__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: var(--space-3);
  list-style: none;
  margin: 0;
  padding: 0;
}

.tipos__item {
  position: relative;
  margin: 0;
}

.tipos__label {
  display: grid;
  grid-template-rows: auto auto 1fr auto;
  gap: var(--space-1);
  height: 100%;
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background-color: var(--color-bg);
  box-shadow: var(--shadow-sm);
  cursor: pointer;
}
.tipos__label:hover {
  border-color: var(--color-brand);
  box-shadow: var(--shadow);
}

.tipos__icono {
  width: 28px;
  height: 28px;
  flex: 0 0 28px;
  color: var(--color-brand);
  margin-bottom: var(--space-2);
}

.tipos__nombre {
  font-size: var(--size-base);
  font-weight: 600;
  /* Una linea reservada: todas las tarjetas de la fila miden igual */
  min-height: calc(1.35em * 1);
}

.tipos__texto {
  font-size: var(--size-sm);
  color: var(--color-text-muted);
  display: -webkit-box;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: calc(1.5em * 3);
}

.tipos__insignia {
  justify-self: start;
  margin-top: var(--space-3);
  padding: 2px var(--space-2);
  border-radius: var(--radius-sm);
  font-size: var(--size-xs);
  font-weight: 600;
  letter-spacing: 0.02em;
  background-color: var(--color-brand-light);
  color: var(--color-brand-dark);
}
.tipos__insignia--estatico {
  background-color: var(--color-surface);
  color: var(--color-text-soft);
}

.tipos__radio:checked + .tipos__label {
  border-color: var(--color-brand);
  border-width: 2px;
  /* Se compensa el borde extra con el relleno: la caja no cambia de tamano */
  padding: calc(var(--space-4) - 1px);
  background-color: var(--color-brand-light);
}

.tipos__radio:focus-visible + .tipos__label {
  outline: 3px solid var(--color-focus);
  outline-offset: 2px;
}

/* -------------------------------------------------------------------------
   E5. PASO 2 — FORMULARIOS
   Los 21 estan en el HTML. Solo se ve el del tipo elegido, y se conmuta con
   una clase, nunca con style en linea.
   ------------------------------------------------------------------------- */
.formularios {
  min-height: 240px;
}

.formulario:not(.formulario--activo) {
  display: none;
}

.field__control--archivo {
  padding: var(--space-2);
  line-height: 1.6;
}

/* Campo con error de validacion. El borde es rojo Y el texto lo dice:
   nunca se comunica solo con color. */
.field__control[aria-invalid='true'] {
  border-color: var(--color-danger);
  border-width: 2px;
  padding: calc(var(--space-2) - 1px) calc(var(--space-3) - 1px);
}

/* Caja de avisos. Envuelve al .notice desde fuera para poder reservar su
   sitio sin tocar el propio aviso. */
.hueco-aviso {
  margin-bottom: var(--space-5);
}

.hueco-aviso--logo {
  min-height: 0;
  margin-bottom: 0;
}

.hueco-aviso__texto {
  margin: 0;
}

/* Grupo de iconos del aviso de legibilidad: los cuatro estan en el HTML y
   solo uno se ve. El hueco mide siempre lo mismo. */
.notice__iconos {
  display: flex;
  flex: 0 0 20px;
  width: 20px;
  height: 20px;
  margin-top: 2px;
}
.notice__iconos .notice__icon {
  margin-top: 0;
}

/* -------------------------------------------------------------------------
   E6. PASO 3 — REPARTO EN DOS COLUMNAS
   La vista previa va primero en el HTML (en movil se ve el codigo antes que
   los controles) y en escritorio se coloca a la derecha con `order`.
   ------------------------------------------------------------------------- */
.disenio {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-6);
  align-items: start;
}

@media (min-width: 1024px) {
  .disenio {
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  }
  .disenio__panel {
    order: 1;
  }
  .disenio__vista {
    order: 2;
  }
}

/* -------------------------------------------------------------------------
   E7. VISTA PREVIA Y DESCARGA
   ------------------------------------------------------------------------- */
/* Cabecera de la columna derecha. Mide lo mismo que la barra de pestanas de
   la columna izquierda (46 px de caja + 16 px de margen) para que las dos
   cajas grandes de debajo —los paneles y el marco de vista previa— empiecen a
   la misma altura. Medido antes del ajuste a 1440 px: el primer panel caia en
   y=586 y el marco en y=559, 27 px de desfase. */
.vista__titulo {
  display: flex;
  align-items: center;
  min-height: 46px;
  margin-bottom: var(--space-4);
  padding-bottom: var(--space-2);
  border-bottom: 1px solid var(--color-border);
  font-size: var(--size-lg);
}

/* Caja de altura FIJA. El lienzo cambia de proporcion al poner o quitar
   marco: si la altura no estuviese reservada aqui fuera, todo lo que hay
   debajo (aviso, botones, anuncio) saltaria en cada cambio. */
.vista__marco {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 380px;
  min-height: 380px;
  padding: var(--space-4);
  margin-bottom: var(--space-3);
  background-color: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
}

.vista__lienzo {
  display: block;
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  border-radius: var(--radius-sm);
}

.vista__pie {
  font-size: var(--size-xs);
  color: var(--color-text-soft);
  margin-bottom: var(--space-4);
}

/* Altura reservada: el texto del aviso cambia solo mientras el usuario
   escribe, sin que el usuario pulse nada. Sin reserva, saltaria. */
.vista__estado {
  min-height: 132px;
  margin-bottom: var(--space-5);
}

.vista__estado .button {
  margin-top: var(--space-3);
}

.descargas {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
}

.descargas__pie {
  font-size: var(--size-xs);
  color: var(--color-text-soft);
  margin-bottom: var(--space-5);
}

/* -------------------------------------------------------------------------
   E8. PESTANAS (DISENO / IA)
   ------------------------------------------------------------------------- */
.pestanas__lista {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  border-bottom: 1px solid var(--color-border);
  margin-bottom: var(--space-4);
}

.pestanas__tab {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  min-height: 44px;
  border: 0;
  border-bottom: 3px solid transparent;
  background-color: transparent;
  color: var(--color-text-muted);
  font-family: inherit;
  font-size: var(--size-sm);
  font-weight: 600;
  cursor: pointer;
}
.pestanas__tab:hover {
  color: var(--color-text);
}

.pestanas__tab--activa {
  color: var(--color-brand-dark);
  border-bottom-color: var(--color-brand);
}

.pestanas__icono {
  width: 18px;
  height: 18px;
  flex: 0 0 18px;
}

.pestanas__panel:not(.pestanas__panel--activo) {
  display: none;
}

.pestanas__panel code {
  font-family: var(--font-mono);
  font-size: 0.9em;
  padding: 1px 4px;
  border-radius: var(--radius-sm);
  background-color: var(--color-bg);
  border: 1px solid var(--color-border);
}

/* -------------------------------------------------------------------------
   E9. PANELES DESPLEGABLES DEL DISENO
   La altura se reserva en .panel (la caja de FUERA), nunca en el <details>:
   el navegador trata al <summary> de forma especial y ahi la reserva no se
   respeta.
   ------------------------------------------------------------------------- */
.panel {
  min-height: 60px;
  margin-bottom: var(--space-3);
}

.panel__detalle {
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background-color: var(--color-bg);
}

.panel__resumen {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4);
  min-height: 58px;
  font-weight: 600;
  cursor: pointer;
  list-style: none;
}
.panel__resumen::-webkit-details-marker {
  display: none;
}

.panel__icono {
  width: 20px;
  height: 20px;
  flex: 0 0 20px;
  color: var(--color-brand);
}

.panel__nombre {
  flex: 1 1 auto;
}

.panel__chevron {
  width: 20px;
  height: 20px;
  flex: 0 0 20px;
  color: var(--color-text-soft);
  transition: transform var(--dur-micro) var(--curva);
}
.panel__detalle[open] .panel__chevron {
  transform: rotate(180deg);
}

.panel__contenido {
  display: grid;
  gap: var(--space-4);
  padding: 0 var(--space-4) var(--space-4);
  border-top: 1px solid var(--color-border);
  padding-top: var(--space-4);
}

.panel__nota {
  font-size: var(--size-xs);
  color: var(--color-text-soft);
  margin: 0;
}

/* -------------------------------------------------------------------------
   E10. REJILLA DE OPCIONES CON MUESTRA GRAFICA
   ------------------------------------------------------------------------- */
.opciones {
  border: 0;
  margin: 0;
  padding: 0;
}

.opciones__leyenda {
  padding: 0;
  margin-bottom: var(--space-3);
  font-size: var(--size-sm);
  font-weight: 600;
  color: var(--color-text);
}

.opciones__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
  gap: var(--space-2);
  list-style: none;
  margin: 0;
  padding: 0;
}

.opciones__grid--marcos {
  grid-template-columns: repeat(auto-fill, minmax(116px, 1fr));
}

.opciones__item {
  position: relative;
  margin: 0;
}

.opciones__label {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  height: 100%;
  min-height: 92px;
  padding: var(--space-3) var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background-color: var(--color-bg);
  color: var(--color-text-muted);
  text-align: center;
  cursor: pointer;
}
.opciones__label:hover {
  border-color: var(--color-brand);
  color: var(--color-text);
}

.opciones__muestra {
  flex: 0 0 auto;
  color: var(--color-text);
}

.opciones__nombre {
  font-size: var(--size-xs);
  font-weight: 600;
  line-height: 1.3;
}

.opciones__radio:checked + .opciones__label {
  border-color: var(--color-brand);
  border-width: 2px;
  padding: calc(var(--space-3) - 1px) calc(var(--space-2) - 1px);
  background-color: var(--color-brand-light);
  color: var(--color-brand-dark);
}
.opciones__radio:checked + .opciones__label .opciones__muestra {
  color: var(--color-brand);
}

.opciones__radio:focus-visible + .opciones__label {
  outline: 3px solid var(--color-focus);
  outline-offset: 2px;
}

/* Variante en linea, para dos o tres opciones sin muestra grafica */
.opciones__linea {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
}

.opciones__radio-linea {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

/* -------------------------------------------------------------------------
   E11. SELECTORES DE COLOR
   ------------------------------------------------------------------------- */
.colores {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: var(--space-3);
}

/* Un elemento de rejilla nace con min-width: auto, o sea que NO puede
   encogerse por debajo de lo que mida su contenido. Los dos campos de
   archivo de este bloque (imagen de fondo, fondo animado) miden ~211 px por
   su boton "Seleccionar archivo" mas el nombre del fichero, contra columnas
   de ~181 px: se salian y se montaban encima del campo de al lado, con sus
   etiquetas y sus textos de ayuda superpuestos (Ceferin, 04/08/2026, con
   captura). Medido antes de arreglarlo: 18 px de solape a 1920 y 1440, 33 px
   a 768 y 43 px a 390. La regla va tambien a los hijos porque cada .field es
   a su vez una rejilla, y su columna interna se dimensionaba igual de ancha
   que el input. */
.colores > *,
.colores > * > * {
  min-width: 0;
}

/* ...pero encogerlos no bastaba (Ceferin, 05/08/2026, con captura): el boton
   nativo "Seleccionar archivo" no se puede partir, asi que en una columna de
   ~181 px se quedaba el boton y el nombre del fichero cortado en una letra
   ("Seleccionar archivo N..."). No es un problema de desbordamiento sino de
   sitio: estos campos no pintan nada compartiendo fila con dos selectores de
   color, que son diminutos. Ocupan la fila entera y caben de sobra.
   Lo mismo para los colores por ojo, que se quedaban apretados al lado de su
   propia casilla en vez de debajo. */
.colores > .field,
.colores > .colores-ojos {
  grid-column: 1 / -1;
}

.color {
  display: grid;
  gap: var(--space-2);
}

.color__label {
  font-size: var(--size-sm);
  font-weight: 600;
}

.color__control {
  width: 100%;
  height: 44px;
  min-height: 44px;
  padding: 2px;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius);
  background-color: var(--color-bg);
  cursor: pointer;
}

/* -------------------------------------------------------------------------
   E12. DESLIZADORES
   ------------------------------------------------------------------------- */
.rango {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.rango__control {
  flex: 1 1 auto;
  min-width: 0;
  height: 44px;
  accent-color: var(--color-brand);
  cursor: pointer;
}

.rango__valor {
  flex: 0 0 66px;
  text-align: right;
  font-size: var(--size-sm);
  font-variant-numeric: tabular-nums;
  color: var(--color-text-muted);
}

/* -------------------------------------------------------------------------
   E13. FICHA DEL LOGO
   Altura reservada: la miniatura aparece cuando el usuario sube el archivo,
   y sin reserva empujaria los controles de tamano hacia abajo.
   ------------------------------------------------------------------------- */
.logo-actual {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 64px;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background-color: var(--color-surface);
}

.logo-actual__imagen {
  width: 48px;
  height: 48px;
  flex: 0 0 48px;
  object-fit: contain;
  background-color: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
}

.logo-actual__texto {
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--size-sm);
  color: var(--color-text-muted);
  overflow-wrap: anywhere;
}

/* -------------------------------------------------------------------------
   19. PREGUNTAS SIEMPRE VISIBLES
   Sustituyen a los <details> en portada, paginas de tipo y preguntas
   frecuentes. Motivo, medido: con desplegables el documento crecia 147 px en
   las paginas de tipo y 2.230 px en la de preguntas al abrirlos, y el
   requisito es 0 px. Reservar la altura por fuera cumple el numero pero deja
   ese mismo hueco muerto con todo cerrado. Asi hay 0 px de desplazamiento,
   0 px de hueco, y las respuestas entran en el primer render.
   Los <details> se mantienen en el editor, que es donde hacen falta.
   ------------------------------------------------------------------------- */
.faq__item--abierto {
  padding: var(--space-4);
}

.faq__pregunta {
  font-size: var(--size-base);
  font-weight: 600;
  line-height: var(--line-tight);
  margin: 0 0 var(--space-2);
  color: var(--color-text);
}

.faq__item--abierto .faq__content {
  padding: 0;
  color: var(--color-text-muted);
}

/* -------------------------------------------------------------------------
   20. HUECOS DE IMAGEN — RETIRADO (pulido 07/2026)
   Aqui vivian las cajas punteadas .hueco-imagen ("Space for image"), que
   eran justo lo que delataba la web segun el feedback del cliente. Las
   sustituyen capturas reales del producto (.captura, bloque 29) e
   ilustraciones IA. Si algun hueco vuelve con las fotos del cliente,
   recuperar el bloque y el componente del historial: reservaba la altura
   con aspect-ratio 16/9 para que la foto no moviera nada al llegar.
   ------------------------------------------------------------------------- */

/* -------------------------------------------------------------------------
   21. CABECERA ILUSTRADA: TEXTO A LA IZQUIERDA, IMAGEN A LA DERECHA
   Medido a 1440 px: el texto ocupaba 686 px de los 1168 utiles y los otros
   482 px quedaban en blanco a la derecha, el 41 % de la franja. Ahora esa
   mitad la ocupa la imagen de ejemplo.
   Se usa en las 21 paginas de tipo y en /es-ES/tipos-de-qr/. Un hueco de
   imagen suelto debajo del texto deja el resto de la franja en blanco y se
   ve cojo; al lado del texto llena la fila y ademas se lee antes.
   Por debajo de 1024 px pasa a una columna y la imagen cae debajo del texto.
   ------------------------------------------------------------------------- */
.cabecera-ilustrada {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-6);
  align-items: center;
}

@media (min-width: 1024px) {
  .cabecera-ilustrada {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }
}

/* Sin min-height propio: el hueco que va dentro saca su alto del
   `aspect-ratio`, o sea desde el primer pintado y sin imagen cargada. Poner
   aqui un alto fijo aparte solo servia para que las dos medidas discrepasen
   en cuanto la columna no midiera exactamente 640 px. */
.cabecera-ilustrada__imagen {
  display: flex;
  align-items: center;
  justify-content: stretch;
}



/* La cabecera ilustrada ya separa sus dos columnas con el gap de la rejilla y
   deja su propio margen inferior: el margen del .section__head sumaba encima y
   descuadraba el centrado vertical del texto contra la imagen. */
.section__head--sin-margen {
  margin-bottom: 0;
}

.cabecera-ilustrada {
  margin-bottom: var(--space-6);
}


/* =========================================================================
   REDISENO 07/2026 — LANDING DE CONVERSION
   Bloques fusionados desde src/estilos/ en la fase de coherencia.
   Orden deliberado: v2 define tokens (--color-cta, --dur-*, --curva,
   --radius-xl, sombras) que consumen los bloques siguientes.
   ========================================================================= */

/* -------------------------------------------------------------------------
   22. SISTEMA DE DISENO v2 (era src/estilos/v2.css)
   ------------------------------------------------------------------------- */

/* Contexto (plan-rediseno.md, aprobado 29/07/2026):
   - Jorge: "la web es en sí una landing con un embudo de conversión",
     "cuanto menos scroll hagan los usuarios más convierten",
     "Las Negritas + Icono con unos contenedores más pequeños y compactos",
     "explicaciones concisas de como mucho 4-5 palabras".
   - Fondo blanco base se mantiene. Franjas suaves sí, tema oscuro no.
   - TODA animación vive dentro de @media (prefers-reduced-motion:
     no-preference). Fuera de ese bloque no hay ni transition ni animation.
   - CLS 0: todo lo que se rellena después reserva su altura
     (aspect-ratio en el móvil y en la demo, min-height en tarjetas).

   Bloques (BEM):
     1. Tokens v2 (aditivos sobre :root)
     2. .rejilla-tipos / .tarjeta-tipo   — selector denso de 21 tipos
     3. .telefono                        — marco de móvil (MarcoMovil.astro)
     4. .stepper                         — 3 pasos persistentes del editor
     5. .esquemas                        — 5 esquemas de color + color libre
     6. .cta                             — CTA jerarquizado con estados
     7. .franja                          — franjas de seccion con degradado suave
     8. .demo-qr                         — hueco reservado de la demo viva
     9. .check-exito                     — check que se dibuja (validación/pago)
    10. Movimiento: keyframes, .revela, transiciones y micro-animaciones
   ========================================================================= */

/* -------------------------------------------------------------------------
   1. TOKENS v2
   Aditivos: no redefinen nada de styles.css.
   El verde de conversión es la decisión "como la referencia o mejor" del
   plan (fase 1): la referencia usa un verde claro con texto blanco que NO
   cumple contraste; el nuestro (#047857 sobre blanco = 5,5:1) sí. Si en
   maqueta se decide CTA azul, está el modificador .cta--marca.
   ------------------------------------------------------------------------- */
:root {
  /* Acento de conversión (verde, AA sobre blanco) */
  --color-cta: #047857;
  --color-cta-dark: #065f46;
  --color-cta-light: #ecfdf5;

  /* Sombras más ricas que las de v1, para elevación en hover y para el
     móvil del preview. Mismo gris base (#111827) que --shadow. */
  --shadow-lg:
    0 4px 6px rgba(17, 24, 39, 0.05),
    0 10px 24px rgba(17, 24, 39, 0.08);
  --shadow-flotante:
    0 12px 20px rgba(17, 24, 39, 0.08),
    0 24px 48px rgba(17, 24, 39, 0.12);

  --radius-xl: 16px;
  /* Entre --radius (8) y --radius-lg (12): chips y piezas de UI del editor.
     Sin esta definicion, los var(--radius-md) de abajo caian a 0 (esquinas
     rectas) — detectado en la auditoria del 30/07. */
  --radius-md: 10px;

  /* Lenguaje de movimiento: dos duraciones y una curva, y de ahí no se
     sale. Micro (hover, foco) = rápida; entrada (reveals) = media. */
  --dur-micro: 160ms;
  --dur-entrada: 450ms;
  --curva: cubic-bezier(0.2, 0.8, 0.3, 1);

  /* Franjas suaves: degradado casi imperceptible que no rompe el fondo
     blanco base (regla viva del SETUP). */
  --franja-suave: linear-gradient(180deg, #ffffff 0%, #f4f7fe 55%, #ffffff 100%);
}

/* -------------------------------------------------------------------------
   2. SELECTOR DE TIPOS DENSO — .rejilla-tipos + .tarjeta-tipo
   La petición literal: "Las Negritas + Icono con unos contenedores más
   pequeños y compactos" y "explicaciones concisas de como mucho 4-5
   palabras". La rejilla mete el máximo de opciones above the fold:
   - a 390 px: 2 columnas de tarjetas de ~56 px de alto → 8-10 visibles.
   - a 1440 px: auto-fill con mínimo 168 px → 6-7 columnas.
   ------------------------------------------------------------------------- */
.rejilla-tipos {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
  /* Filas uniformes (31/07): TODAS las tarjetas con la misma altura, en
     los dos idiomas — la mas alta manda. */
  grid-auto-rows: 1fr;
  gap: var(--space-2);
}

@media (max-width: 480px) {
  .rejilla-tipos {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* La tarjeta es un enlace entero (o un label de radio en el editor):
   icono + nombre en negrita + detalle de 4-5 palabras. min-height fija
   la altura aunque el detalle ocupe 1 o 2 líneas: CLS 0 y rejilla pareja. */
.tarjeta-tipo {
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: var(--space-2);
  align-items: center;
  min-height: 56px;
  padding: var(--space-2) var(--space-3);
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  text-decoration: none;
  color: inherit;
  cursor: pointer;
}

.tarjeta-tipo:hover {
  border-color: var(--color-brand);
  box-shadow: var(--shadow-lg);
}

.tarjeta-tipo:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 2px;
}

.tarjeta-tipo__icono {
  grid-row: span 2;
  color: var(--color-brand);
}

.tarjeta-tipo__nombre {
  font-size: var(--size-sm);
  font-weight: 700;
  line-height: var(--line-tight);
  color: var(--color-text);
}

.tarjeta-tipo__detalle {
  font-size: var(--size-xs);
  line-height: var(--line-tight);
  color: var(--color-text-soft);
}

/* Estado seleccionado (en el paso 1 del editor la tarjeta envuelve un
   radio oculto; en la home es un enlace y no se usa). */
.tarjeta-tipo--activa,
.tarjeta-tipo:has(input:checked) {
  border-color: var(--color-brand);
  background: var(--color-brand-light);
  box-shadow: inset 0 0 0 1px var(--color-brand);
}

/* El radio vive DENTRO de la tarjeta pero no se ve; el foco del teclado
   se pinta sobre la tarjeta entera. */
.tarjeta-tipo__radio {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.tarjeta-tipo:has(.tarjeta-tipo__radio:focus-visible) {
  outline: 2px solid var(--color-focus);
  outline-offset: 2px;
}

/* -------------------------------------------------------------------------
   3. MARCO DE MÓVIL — .telefono (pareja de src/components/MarcoMovil.astro)
   Jorge: "el preview visual del movil es fundamental".
   El componente pinta un SVG propio (bisel, cámara, altavoz, botones) por
   ENCIMA del contenido, y el contenido del preview entra por slot en
   .telefono__pantalla. El aspect-ratio reserva la altura entera del
   aparato antes de que cargue nada: CLS 0.

   La posición sticky del preview NO va aquí: es decisión de la página del
   editor (excepción concedida por Jorge, documentada en el plan).
   ------------------------------------------------------------------------- */
.telefono {
  position: relative;
  width: min(300px, 100%);
  aspect-ratio: 320 / 650;
  margin-inline: auto;
  filter: drop-shadow(0 18px 28px rgba(17, 24, 39, 0.18));
}

/* El SVG del marco cubre todo y deja pasar los clics al contenido.
   overflow visible: los botones laterales del aparato estan dibujados
   FUERA del viewBox a proposito (sobresalen 3 unidades, como en un movil
   real); con el overflow hidden por defecto del SVG quedaban recortados
   2,4 px e invisibles (medido por verificar.mjs). */
.telefono__marco {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
  z-index: 2;
}

/* La pantalla: hueco interior alineado con el recorte del SVG
   (viewBox 320×650, bisel de 12 unidades → 3,75 % horizontal y
   1,846 % vertical). El radio interior del SVG es 34 unidades. */
.telefono__pantalla {
  position: absolute;
  inset: 1.85% 3.75%;
  overflow: hidden;
  border-radius: 10.6% / 5.23%;
  background: var(--color-bg);
  z-index: 1;
}

/* Chrome de movil real (30/07, noche): barra de estado + pildora de
   navegador, solo cuando MarcoMovil recibe la prop `navegador` (editor).
   Va POR ENCIMA del contenido (.prev es absolute): el scroll pasa por
   debajo, como en un navegador de verdad. */
.telefono__chrome {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 2;
  background: #ffffff;
  border-bottom: 1px solid var(--color-border);
  padding: 6px 14px 7px;
}

.telefono__estado {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 11px;
  font-weight: 600;
  color: #111827;
  /* hueco central para la camara perforada del marco */
  padding: 0 4px 5px;
}

.telefono__indicadores {
  display: inline-flex;
  align-items: center;
  gap: 3px;
}

.telefono__urlbar {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  height: 22px;
  border-radius: 999px;
  background: #f1f3f6;
  border: 1px solid var(--color-border);
  color: var(--color-text-soft);
  font-size: 10.5px;
  padding: 0 10px;
}

.telefono__url {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 85%;
}

/* Con chrome, el contenido arranca por debajo de las dos barras. */
.telefono--con-chrome .prev {
  padding-top: 24%;
}

/* Variante compacta para franjas de la home (solo se ve media pantalla). */
.telefono--recortado {
  aspect-ratio: 320 / 420;
}

.telefono--recortado .telefono__pantalla {
  inset: 2.86% 3.75%;
  border-radius: 10.6% 10.6% 0 0 / 8.1% 8.1% 0 0;
}

/* -------------------------------------------------------------------------
   4. STEPPER DE 3 PASOS — .stepper
   Como la referencia: barra persistente en el pie del editor con los tres
   pasos y las acciones Atrás/Siguiente. Va sticky al fondo del viewport
   DENTRO de las páginas del embudo (parte de la excepción al "sin sticky"
   documentada en el plan). Para usos sin fijar: .stepper--estatico.
   ------------------------------------------------------------------------- */
.stepper {
  position: sticky;
  bottom: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  min-height: 64px;
  padding: var(--space-2) var(--space-4);
  background: var(--color-bg);
  border-top: 1px solid var(--color-border);
  box-shadow: 0 -4px 12px rgba(17, 24, 39, 0.06);
}

.stepper--estatico {
  position: static;
  box-shadow: none;
}

.stepper__pasos {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  list-style: none;
  margin: 0;
  padding: 0;
}

.stepper__paso {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--size-sm);
  color: var(--color-text-soft);
}

/* Conector entre pasos: raya corta, no flecha, para no gastar iconos. */
.stepper__paso + .stepper__paso::before {
  content: '';
  display: block;
  width: 24px;
  height: 2px;
  border-radius: 1px;
  background: var(--color-border-strong);
}

.stepper__numero {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 2px solid var(--color-border-strong);
  font-size: var(--size-xs);
  font-weight: 700;
  color: var(--color-text-muted);
  background: var(--color-bg);
}

/* Paso actual: número en azul de marca, etiqueta en negrita. */
.stepper__paso--actual {
  color: var(--color-text);
  font-weight: 700;
}

.stepper__paso--actual .stepper__numero {
  border-color: var(--color-brand);
  background: var(--color-brand);
  color: #ffffff;
}

/* Paso completado: el número se sustituye por el icono "comprobar"
   (Phosphor, vía Icono.astro) que la página mete dentro de __numero. */
.stepper__paso--hecho .stepper__numero {
  border-color: var(--color-cta);
  background: var(--color-cta-light);
  color: var(--color-cta);
}

/* En pantallas estrechas las etiquetas de los pasos no actuales se ocultan
   (queda número + etiqueta del actual): la barra no crece ni empuja nada. */
@media (max-width: 640px) {
  .stepper__paso:not(.stepper__paso--actual) .stepper__etiqueta {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  /* Compacto de verdad (arreglo 30/07: el boton "Siguiente" salia CORTADO
     por la derecha en un movil real de 412px con Atras+Siguiente juntos):
     menos aire, conectores cortos, numeros de 26px, etiqueta activa en una
     linea con puntos suspensivos y "Atras" SOLO icono (font-size 0 esconde
     el texto en pantalla pero lo deja para el lector de pantalla). */
  .stepper {
    gap: var(--space-2);
    padding-inline: var(--space-2);
  }
  .stepper__pasos {
    gap: var(--space-1);
  }
  .stepper__paso {
    gap: var(--space-1);
  }
  .stepper__paso + .stepper__paso::before {
    width: 10px;
  }
  .stepper__numero {
    width: 26px;
    height: 26px;
  }
  .stepper__etiqueta {
    max-width: 22vw;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .stepper__acciones {
    flex: 0 1 auto;
    min-width: 0;
  }
  .stepper__acciones .cta {
    padding-inline: var(--space-3);
  }
  .stepper__acciones .cta--fantasma {
    font-size: 0;
    gap: 0;
    padding-inline: var(--space-2);
  }
}

@media (max-width: 480px) {
  .stepper__etiqueta {
    max-width: 15vw;
  }
  .stepper__acciones .cta {
    padding-inline: var(--space-2);
  }
  /* Movil pequeno de verdad (320-375px, medido): con el CTA de pago ya
     compactado (bloque 6) el hueco que falta lo da la propia franja de
     pasos. Se recorta un poco mas solo aqui: sin conector visual y
     numeros 4px mas chicos, el "1—2—3" sigue siendo legible. */
  .stepper__paso + .stepper__paso::before {
    display: none;
  }
  .stepper__numero {
    width: 22px;
    height: 22px;
  }
}

.stepper__acciones {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

/* -------------------------------------------------------------------------
   5. ESQUEMAS DE COLOR — .esquemas
   Paridad con el bloque "Appearance — Choose your color scheme" de la
   referencia (inventario.json): 5 esquemas predefinidos + color libre.
   Cada esquema pinta 3 colores (fondo / botón / contenido) en una muestra
   redonda partida en tres bandas. Los 5 esquemas son NUESTROS, definidos
   aquí (cero estilos en línea): el JS del editor lee el value del radio
   y aplica los mismos colores al preview.
   ------------------------------------------------------------------------- */
.esquemas {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}

.esquemas__opcion {
  position: relative;
  display: grid;
  justify-items: center;
  row-gap: var(--space-1);
  cursor: pointer;
}

/* El radio real, oculto pero accesible. */
.esquemas__radio {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Muestra: círculo de 44 px (tamaño mínimo táctil) con las tres bandas. */
.esquemas__muestra {
  display: block;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 2px solid var(--color-border);
  background: linear-gradient(
    135deg,
    var(--esquema-fondo, #ffffff) 0%,
    var(--esquema-fondo, #ffffff) 34%,
    var(--esquema-boton, #1a56db) 34%,
    var(--esquema-boton, #1a56db) 67%,
    var(--esquema-contenido, #111827) 67%,
    var(--esquema-contenido, #111827) 100%
  );
}

/* Los 5 esquemas. Solo variables: la muestra de arriba las consume y el
   editor puede leerlas también con getComputedStyle si le hace falta. */
.esquemas__opcion--clasico {
  --esquema-fondo: #ffffff;
  --esquema-boton: #1a56db;
  --esquema-contenido: #111827;
}

.esquemas__opcion--oceano {
  --esquema-fondo: #eff4fe;
  --esquema-boton: #1543ac;
  --esquema-contenido: #0f2a66;
}

.esquemas__opcion--bosque {
  --esquema-fondo: #ecfdf5;
  --esquema-boton: #047857;
  --esquema-contenido: #064e3b;
}

.esquemas__opcion--atardecer {
  --esquema-fondo: #fff7ed;
  --esquema-boton: #ea580c;
  --esquema-contenido: #7c2d12;
}

.esquemas__opcion--nocturno {
  --esquema-fondo: #111827;
  --esquema-boton: #1a56db;
  --esquema-contenido: #f9fafb;
}

/* Estados: seleccionado = aro azul; foco de teclado = outline estándar. */
.esquemas__radio:checked + .esquemas__muestra {
  border-color: var(--color-brand);
  box-shadow: 0 0 0 3px var(--color-brand-light), var(--shadow-sm);
}

.esquemas__radio:focus-visible + .esquemas__muestra {
  outline: 2px solid var(--color-focus);
  outline-offset: 2px;
}

.esquemas__nombre {
  font-size: var(--size-xs);
  color: var(--color-text-soft);
}

/* Muestra "y más": mismo círculo de 44 px que los esquemas de color, pero
   punteado y sin gradiente, para dejar claro que no es un esquema más sino
   un indicador de que hay más disponibles (ver nota bajo la lista). */
.esquemas__muestra--mas {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 2px dashed var(--color-border-strong);
  background: var(--color-surface-alt);
  color: var(--color-text-soft);
  font-size: var(--size-lg);
  font-weight: 700;
  line-height: 1;
}

/* Color libre: el input nativo de color, redondo y del mismo tamaño que
   las muestras para que lea como "una opción más". */
.esquemas__libre {
  width: 44px;
  height: 44px;
  padding: 0;
  border: 2px dashed var(--color-border-strong);
  border-radius: 50%;
  background: var(--color-bg);
  cursor: pointer;
}

.esquemas__libre::-webkit-color-swatch-wrapper {
  padding: 4px;
}

/* OJO: los dos pseudoelementos van en reglas SEPARADAS a propósito.
   Un selector no reconocido invalida el grupo entero, así que juntarlos
   dejaría la muestra cuadrada en los dos navegadores. */
.esquemas__libre::-webkit-color-swatch {
  border: none;
  border-radius: 50%;
}

.esquemas__libre::-moz-color-swatch {
  border: none;
  border-radius: 50%;
}

.esquemas__libre:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 2px;
}

/* -------------------------------------------------------------------------
   6. CTA JERARQUIZADO — .cta
   Jerarquía de tres niveles: primario (verde de conversión), --marca
   (azul, por si en maqueta se prefiere), --secundario (contorno) y
   --fantasma (texto). El primario es ÚNICO por vista: esa es la regla de
   jerarquía, no una clase.
   Nada de la ruta crítica espera a una animación: los estados cambian
   al instante; la transición suave solo existe con motion permitido
   (bloque 10).
   ------------------------------------------------------------------------- */
.cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: 48px;
  padding: var(--space-3) var(--space-5);
  border: 2px solid var(--color-cta);
  border-radius: var(--radius);
  background: var(--color-cta);
  color: #ffffff;
  font-family: var(--font-base);
  font-size: var(--size-base);
  font-weight: 700;
  line-height: var(--line-tight);
  text-decoration: none;
  cursor: pointer;
  /* El brillo de hover (bloque 10) se recorta aquí. */
  position: relative;
  overflow: hidden;
}

.cta:hover {
  background: var(--color-cta-dark);
  border-color: var(--color-cta-dark);
  box-shadow: var(--shadow-lg);
}

.cta:active {
  box-shadow: none;
}

.cta:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 2px;
}

.cta:disabled,
.cta--desactivado {
  background: var(--color-border);
  border-color: var(--color-border);
  color: var(--color-text-soft);
  cursor: not-allowed;
  box-shadow: none;
}

/* Variante azul de marca (decisión abierta de maqueta, plan fase 1). */
.cta--marca {
  background: var(--color-brand);
  border-color: var(--color-brand);
}

.cta--marca:hover {
  background: var(--color-brand-dark);
  border-color: var(--color-brand-dark);
}

/* Secundario: contorno. Acompaña al primario, nunca compite en color. */
.cta--secundario {
  background: var(--color-bg);
  border-color: var(--color-border-strong);
  color: var(--color-text);
}

.cta--secundario:hover {
  background: var(--color-surface);
  border-color: var(--color-text-muted);
  box-shadow: var(--shadow-sm);
}

/* Fantasma: solo texto, para "Back" y acciones terciarias. */
.cta--fantasma {
  background: transparent;
  border-color: transparent;
  color: var(--color-text-muted);
}

.cta--fantasma:hover {
  background: var(--color-surface);
  color: var(--color-text);
  box-shadow: none;
}

.cta--grande {
  min-height: 56px;
  padding: var(--space-4) var(--space-6);
  font-size: var(--size-lg);
  border-radius: var(--radius-lg);
}

.cta--bloque {
  display: flex;
  width: 100%;
}

/* Icono dentro del CTA (flecha, descarga…): hereda color; su empujón de
   hover está en el bloque 10. */
.cta__icono {
  flex: none;
}

/* -------------------------------------------------------------------------
   7. FRANJAS — .franja
   Franjas de sección con degradado suave (sin romper el blanco base).
   La antigua .franja-confianza (fila de confianza centrada) se retiro el
   1/08: sus 4 frases se movieron dentro de .portada-perso__lista, con el
   mismo estilo de icono+negrita que las funciones de personalizacion.
   ------------------------------------------------------------------------- */
.franja {
  padding-block: var(--space-7);
}

.franja--suave {
  background: var(--franja-suave);
}

.franja--borde {
  border-block: 1px solid var(--color-border);
}

/* -------------------------------------------------------------------------
   8. DEMO VIVA — .demo-qr (pareja de public/js/demo-qr.js)
   Caja CUADRADA reservada antes de que el JS pinte nada: si el JS no
   carga, queda una superficie suave del tamaño exacto (CLS 0 en ambos
   casos). El canvas que inyecta la librería se estira al hueco.
   ------------------------------------------------------------------------- */
.demo-qr {
  display: grid;
  place-items: center;
  width: min(280px, 100%);
  aspect-ratio: 1;
  margin-inline: auto;
  padding: var(--space-3);
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg);
}

.demo-qr canvas,
.demo-qr svg {
  display: block;
  max-width: 100%;
  height: auto;
}

/* -------------------------------------------------------------------------
   9. CHECK DE ÉXITO — .check-exito
   Círculo + check para "código legible" y "pago completado". Sin motion,
   se ve el estado final directamente; con motion, el trazo se dibuja
   (bloque 10). Se usa con un SVG propio de dos paths:
     <svg class="check-exito" viewBox="0 0 52 52" width="52" height="52">
       <circle class="check-exito__circulo" cx="26" cy="26" r="24"/>
       <path class="check-exito__marca" d="M14 27l8 8 16-17"/>
     </svg>
   ------------------------------------------------------------------------- */
.check-exito {
  display: block;
  color: var(--color-cta);
}

.check-exito__circulo {
  fill: var(--color-cta-light);
  stroke: currentColor;
  stroke-width: 2;
}

.check-exito__marca {
  fill: none;
  stroke: currentColor;
  stroke-width: 4;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* -------------------------------------------------------------------------
   10. MOVIMIENTO
   Regla de oro: TODO lo que se mueve vive aquí dentro. Fuera de este
   bloque los estados cambian en seco (perfectamente usable) y los
   .revela son visibles desde el primer pintado.
   Dos duraciones (--dur-micro, --dur-entrada), una curva (--curva).
   ------------------------------------------------------------------------- */
@media (prefers-reduced-motion: no-preference) {
  /* --- Keyframes ------------------------------------------------------- */

  /* Entrada estándar: aparecer subiendo un pelín. */
  @keyframes v2-aparecer {
    from {
      opacity: 0;
      transform: translateY(14px);
    }
    to {
      opacity: 1;
      transform: translateY(0);
    }
  }

  /* Brillo que barre el CTA primario al pasar el ratón. */
  @keyframes v2-brillo {
    from {
      transform: translateX(-120%) skewX(-18deg);
    }
    to {
      transform: translateX(220%) skewX(-18deg);
    }
  }

  /* Latido de atención, suave, para UN solo elemento por vista. */
  @keyframes v2-latido {
    0%,
    100% {
      transform: scale(1);
      box-shadow: 0 0 0 0 rgba(4, 120, 87, 0.35);
    }
    50% {
      transform: scale(1.02);
      box-shadow: 0 0 0 10px rgba(4, 120, 87, 0);
    }
  }

  /* El check de éxito se dibuja: primero el círculo, luego la marca. */
  @keyframes v2-trazo {
    to {
      stroke-dashoffset: 0;
    }
  }

  /* --- Transiciones de los componentes --------------------------------- */

  .tarjeta-tipo {
    transition:
      box-shadow var(--dur-micro) var(--curva),
      border-color var(--dur-micro) var(--curva),
      transform var(--dur-micro) var(--curva);
  }

  .tarjeta-tipo:hover {
    transform: translateY(-2px);
  }

  .cta {
    transition:
      background-color var(--dur-micro) var(--curva),
      border-color var(--dur-micro) var(--curva),
      box-shadow var(--dur-micro) var(--curva),
      transform var(--dur-micro) var(--curva);
  }

  .cta:hover {
    transform: translateY(-1px);
  }

  .cta:active {
    transform: translateY(0);
  }

  /* Brillo del primario: pseudoelemento que solo existe con motion. */
  .cta:not(.cta--secundario):not(.cta--fantasma)::after {
    content: '';
    position: absolute;
    inset: 0 auto 0 0;
    width: 40%;
    background: linear-gradient(
      90deg,
      rgba(255, 255, 255, 0) 0%,
      rgba(255, 255, 255, 0.25) 50%,
      rgba(255, 255, 255, 0) 100%
    );
    transform: translateX(-120%) skewX(-18deg);
    pointer-events: none;
  }

  .cta:not(.cta--secundario):not(.cta--fantasma):hover::after {
    animation: v2-brillo 650ms var(--curva);
  }

  /* La flecha del CTA se asoma hacia el destino. */
  .cta__icono {
    transition: transform var(--dur-micro) var(--curva);
  }

  .cta:hover .cta__icono {
    transform: translateX(3px);
  }

  .cta--late {
    animation: v2-latido 2.4s var(--curva) infinite;
  }

  .esquemas__muestra {
    transition:
      box-shadow var(--dur-micro) var(--curva),
      border-color var(--dur-micro) var(--curva),
      transform var(--dur-micro) var(--curva);
  }

  .esquemas__opcion:hover .esquemas__muestra {
    transform: scale(1.08);
  }

  .stepper__numero {
    transition:
      background-color var(--dur-entrada) var(--curva),
      border-color var(--dur-entrada) var(--curva),
      color var(--dur-entrada) var(--curva);
  }

  /* --- Reveals al hacer scroll ----------------------------------------- */

  /* Con soporte de scroll-driven animations, el reveal va atado a la
     entrada del elemento en el viewport (sin JS ni observers). */
  .revela {
    animation: v2-aparecer var(--dur-entrada) var(--curva) both;
    animation-timeline: view();
    animation-range: entry 0% entry 55%;
  }

  /* Escalonado para hijos de una rejilla/lista (hasta 6; del 7º en
     adelante comparten el retardo del 6º). Solo tiene efecto en el
     fallback temporal: con animation-timeline manda el scroll. */
  .revela--2 {
    animation-delay: 60ms;
  }
  .revela--3 {
    animation-delay: 120ms;
  }
  .revela--4 {
    animation-delay: 180ms;
  }
  .revela--5 {
    animation-delay: 240ms;
  }
  .revela--6 {
    animation-delay: 300ms;
  }

  /* Fallback (Safari y Firefox sin animation-timeline a fecha del plan):
     misma animación, disparada al cargar. Nada queda oculto esperando
     un scroll que la animación no puede escuchar. */
  @supports not (animation-timeline: view()) {
    .revela {
      animation: v2-aparecer var(--dur-entrada) var(--curva) both;
    }
  }

  /* --- Check de éxito dibujándose -------------------------------------- */

  .check-exito__circulo {
    stroke-dasharray: 151;
    stroke-dashoffset: 151;
    animation: v2-trazo 500ms var(--curva) forwards;
  }

  .check-exito__marca {
    stroke-dasharray: 36;
    stroke-dashoffset: 36;
    animation: v2-trazo 350ms var(--curva) 400ms forwards;
  }
}

/* -------------------------------------------------------------------------
   23. CABECERA: SELECTOR DE IDIOMA (era src/estilos/cabecera.css)
   ------------------------------------------------------------------------- */

.header__idioma {
  display: inline-block;
  padding: 0.35rem 0.6rem;
  border: 1px solid var(--color-border);
  border-radius: 6px;
  font-size: 0.85rem;
  font-weight: 600;
  text-decoration: none;
  color: inherit;
  white-space: nowrap;
}

.header__idioma:hover,
.header__idioma:focus-visible {
  border-color: currentColor;
}

/* Por debajo de 1024 px el idioma se muda al desplegable .header__menu
   (ver seccion 4): en la barra no queda sitio para el, y aqui gana por
   orden de cascada sobre el "display:none" que se pondria junto al resto
   de reglas de ese corte, por eso el override vive pegado a la regla base. */
@media (max-width: 1023px) {
  .header__idioma { display: none; }
}

/* En movil la cabecera guarda solo lo que convierte: logo, idioma y CTA.
   Aun asi, con las medidas de escritorio no caben (medido a 390 px: 38 px
   de desborde en EN y 56 en ES; el total en ES suma 461 px), asi que por
   debajo de 520 px se compactan los huecos y el CTA pierde el icono.
   Medido tras el ajuste: 0 px de desborde a 390 px en los dos idiomas.
   NOTA post-menu-movil: el idioma ya no esta en la barra por debajo de
   1024 px (esta arriba), asi que su regla de padding en este bloque quedo
   sin efecto visible; se deja porque no molesta y evita reabrir este bloque
   si el idioma volviera a la barra en el futuro. */
@media (max-width: 519px) {
  .header__inner {
    gap: var(--space-2);
  }

  .header__nav {
    gap: var(--space-2);
  }

  .header__logo {
    font-size: var(--size-base);
  }

  .header__idioma {
    padding: 0.35rem 0.45rem;
  }

  .header__nav .button--small {
    padding: var(--space-2) var(--space-3);
  }

  .header__nav .button--small .button__icon {
    display: none;
  }
}

/* -------------------------------------------------------------------------
   24. PAGINAS DE DOCUMENTO SIN PUBLICIDAD (era src/estilos/paginas-doc.css)
   ------------------------------------------------------------------------- */

.layout-doc--solo {
  grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 1024px) {
  .layout-doc--solo {
    /* centrado (31/07): una sola columna pegada a la izquierda dejaba
       medio ancho vacio a la derecha en FAQ y legales. */
    justify-content: center;
    grid-template-columns: minmax(0, var(--width-text));
    justify-content: start;
  }
}

/* -------------------------------------------------------------------------
   25. HOME DE CONVERSION (.portada-*) (era src/estilos/home.css)
   ------------------------------------------------------------------------- */

/* -------------------------------------------------------------------------
   HERO — .portada-hero
   ------------------------------------------------------------------------- */
.portada-hero {
  position: relative;
  padding-block: var(--space-6);
  border-bottom: 1px solid var(--color-border);
  background: var(--franja-suave);
}

/* Fondo de ambiente de TODA la seccion (peticion 30/07): panoramica de borde
   a borde del viewport, sin recuadro que se corte. La escena vive en la mitad
   derecha de la ilustracion (el titular necesita la izquierda limpia). Solo
   escritorio: en movil la demo no existe y el fold va limpio. */
.portada-hero__fondo {
  display: none;
}
@media (min-width: 1024px) {
  .portada-hero__fondo {
    display: block;
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center 40%;
  }
  .portada-hero > .container {
    position: relative;
    z-index: 1;
  }
}

.portada-hero__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-6);
  align-items: center;
}

@media (min-width: 1024px) {
  .portada-hero__grid {
    grid-template-columns: 1.15fr 0.85fr;
  }
}

.portada-hero__titulo {
  margin-bottom: var(--space-3);
  font-weight: 800;
  font-size: clamp(1.75rem, 6vw, 2.25rem);
}

@media (min-width: 1024px) {
  .portada-hero__titulo {
    font-size: 3rem;
    letter-spacing: -0.03em;
  }
}

/* Subtitular: el ángulo honesto contra la suscripción-trampa de la
   competencia. En negrita suave para que se lea como promesa, no como
   párrafo. */
.portada-hero__sub {
  font-size: var(--size-lg);
  font-weight: 600;
  color: var(--color-text-muted);
  max-width: 44ch;
  margin-bottom: var(--space-5);
}

.portada-hero__col-texto {
  position: relative;
}

/* Boton del hero (rehecho 1/08, 5a vuelta: "boton un poco mas pequeño,
   personaje un poco mas grande" — pedido explicito). Solo AQUI, dentro del
   hero: .cta--grande se usa tal cual en otras 3 zonas de la pagina
   (CTA final, checkout, pago) que no llevan mascota y no deben encogerse. */
.portada-hero__acciones .cta--grande {
  min-height: 48px;
  padding: var(--space-3) var(--space-5);
}

/* Mascota de movil (rehecha 1/08, 5a vuelta: nueva pose "codo arriba,
   mano en la cintura, sonriendo" — public/img/mascota/codo.png, generada
   y verificada con jsQR igual que el resto — apoyada en la esquina
   superior derecha del boton). Sigue siendo hija de
   .portada-hero__acciones (flex normal, flujo real, nunca
   position:absolute: no puede solaparse con nada ni salirse de pantalla).
   align-items:flex-end en vez de center: la mascota es mas alta que el
   boton (ya encogido) y queremos que el sobrante suba por ENCIMA del
   boton (asi el codo alzado queda a la altura de su esquina superior),
   nunca que sobresalga por abajo hacia la lista de garantias. El ancho de
   cada tramo es el espacio real medido con Playwright entre el boton (ya
   mas pequeño) y el borde del contenedor menos el gap de la fila, con
   margen de sobra. flex-wrap sigue de red de seguridad: si algun
   navegador mide el boton un poco distinto, la mascota pasa a la fila de
   abajo — nunca se recorta ni provoca scroll horizontal. Oculta en
   >=1024px, donde ya esta compuesta en la escena de escritorio
   (portada-hero__fondo).

   margin-top negativo (31/07 tarde, arreglo de hueco reportado): al ser la
   mascota mas alta que el boton, esa diferencia estiraba la fila entera
   (align-items:flex-end reparte el sobrante encima del boton, no de la
   mascota) y dejaba un hueco en blanco de hasta 47px entre el subtitulo y
   el boton — medido con Playwright contra carreterasnacionales.com/qr/es-ES/,
   frente a los 24px (var(--space-5)) que usa el resto de la pagina. El
   margin-top negativo saca a la mascota del calculo de alto de la fila sin
   moverla de sitio en el flujo (sigue siendo flujo real): la fila vuelve a
   medir lo que mide el boton, y la mascota sube visualmente lo mismo que
   antes por su propio margen en vez de por el estirón de la fila. Valores
   calculados para dejar >=8px libres entre el texto y la cabeza de la
   mascota en cada tramo (nunca solapar el subtitulo) y el hueco sobre el
   boton en 0-15px en vez de 23-31px. Re-verificar con Playwright si cambia
   el tamaño de la mascota o del boton. */
.portada-hero__mascota-movil {
  display: none;
}

@media (min-width: 360px) {
  .portada-hero__mascota-movil {
    display: block;
    width: 58px;
    height: auto;
    margin-top: -10px;
  }
}

@media (min-width: 375px) {
  .portada-hero__mascota-movil {
    width: 70px;
    margin-top: -16px;
  }
}

@media (min-width: 480px) {
  .portada-hero__mascota-movil {
    width: 78px;
    margin-top: -16px;
  }
}

@media (min-width: 1024px) {
  .portada-hero__mascota-movil {
    display: none;
  }
}

.portada-hero__acciones {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}

/* Boton centrado con la mascota, no a ras de sus pies (1/08, pedido
   explicito: "el boton esta muy abajo, subelo un poco y queda centrado").
   align-items:center ya reparte el sobrante de la mascota mitad arriba
   mitad abajo del CONTENEDOR flex, pero el contenedor no es el alto real
   de la mascota: su margin-top negativo (ver .portada-hero__mascota-movil)
   ya recorta ese alto para cerrar el hueco con el subtitulo, asi que el
   centro de la caja flex queda mas bajo que el centro real del dibujo.
   Ajuste medido con Playwright + analisis de pixel del PNG (padding
   transparente real: 2,7% arriba, 5,3% abajo del lienzo) contra
   carreterasnacionales.com/qr/es-ES/: sin este margen el boton quedaba
   3-8px mas bajo que el centro visual de la mascota en todos los anchos
   movil; con -7px el hueco por encima y por debajo del boton, medido
   contra los pixeles opacos reales del dibujo, queda igualado dentro de
   2 px. Solo hasta 1024px: la version de escritorio no lleva mascota al
   lado y no debe moverse. */
@media (min-width: 360px) and (max-width: 374.98px) {
  .portada-hero__acciones .cta--grande {
    margin-top: -9px;
  }
}

@media (min-width: 375px) and (max-width: 1023.98px) {
  .portada-hero__acciones .cta--grande {
    margin-top: -13px;
  }
}

/* Cuatro micro-garantías bajo el CTA: icono + frase corta, todo
   verificable. Rejilla fija 2x2 (31/07, antes 3 en flex-wrap): misma
   forma en movil y en escritorio, sin depender de donde rompa el wrap. */
.portada-hero__puntos {
  display: grid;
  grid-template-columns: repeat(2, auto);
  justify-content: start;
  gap: var(--space-2) var(--space-4);
  list-style: none;
  margin: 0;
  padding: 0;
}

.portada-hero__punto {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  font-size: var(--size-sm);
  color: var(--color-text-muted);
}

.portada-hero__punto-icono {
  color: var(--color-cta);
  flex: none;
}

/* La demo del móvil NO existe por debajo de 1024 px: en móvil el fold es
   titular + CTA + arranque del selector, que es lo que convierte. El canvas
   se sigue pintando oculto pero su rotación queda parada (demo-qr.js pausa
   fuera de viewport). */
.portada-hero__demo {
  display: none;
}

@media (min-width: 1024px) {
  .portada-hero__demo {
    display: block;
  }

  /* Tope de 260 px (más estrecho que el min(300px) por defecto de
     .telefono) para que a 1440×900 el hero mida ~620 px y el selector
     asome debajo. */
  .portada-hero__demo .telefono {
    width: min(260px, 100%);
  }
}

/* -------------------------------------------------------------------------
   PANTALLA DEL MÓVIL DEL HERO — .portada-demo
   Va dentro de <MarcoMovil>: fondo claro, el QR vivo centrado y una
   nota corta y honesta (el código es real y se puede escanear ya).
   ------------------------------------------------------------------------- */
/* Badge de verificacion del trailer (30/07): pildora verde que aparece
   sobre el QR ya validado. */
.demo-badge {
  position: absolute;
  left: 50%;
  bottom: 12%;
  transform: translateX(-50%) translateY(6px);
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--color-cta);
  color: #ffffff;
  font-size: 11px;
  font-weight: 700;
  white-space: nowrap;
  opacity: 0;
  visibility: hidden;
  z-index: 3;
  pointer-events: none;
}
.demo-badge--visible {
  opacity: 1;
  visibility: visible;
  transform: translateX(-50%) translateY(0);
}
@media (prefers-reduced-motion: no-preference) {
  .demo-badge { transition: opacity 0.25s ease, transform 0.25s ease; }
}

/* Capa "a donde lleva" del trailer de la demo (30/07): la landing real del
   tipo a pantalla completa del movil, con chip del tipo arriba. Vive DENTRO
   de .telefono__pantalla, asi hereda su recorte redondeado. La pinta y la
   conmuta public/js/demo-qr.js; sin JS no existe. */
.demo-destino {
  position: absolute;
  inset: 0;
  z-index: 2;
  background: var(--color-bg);
  opacity: 0;
  visibility: hidden;
}
/* La entrada desliza via keyframe, NO con transform en reposo: el estado
   oculto desplazado 14px se recortaba contra el overflow de la pantalla y
   verificar.mjs lo cazo (6 mediciones, 30/07 noche). */
.demo-destino.activo {
  opacity: 1;
  visibility: visible;
  animation: demo-destino-entra 300ms ease 1 both;
}

@keyframes demo-destino-entra {
  from { opacity: 0; transform: translateY(14px); }
  to { opacity: 1; transform: translateY(0); }
}
.demo-destino img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.demo-destino__chip {
  position: absolute;
  top: 4.5%;
  left: 50%;
  transform: translateX(-50%);
  padding: 4px 12px;
  border-radius: 999px;
  background: var(--color-brand);
  color: #fff;
  font-size: 12px;
  font-weight: 700;
  white-space: nowrap;
  box-shadow: var(--shadow-sm);
}
@media (prefers-reduced-motion: no-preference) {
  .demo-destino { transition: opacity 0.25s ease; }
}

.portada-demo {
  display: grid;
  justify-items: center;
  align-content: center;
  row-gap: var(--space-3);
  height: 100%;
  padding: var(--space-4);
  background: var(--color-surface-alt);
}

/* La caja de la demo (v2.css bloque 8) se encoge al ancho de la pantalla
   del teléfono. Reserva su cuadrado igualmente: CLS 0 con o sin JS. */
.portada-demo .demo-qr {
  width: min(190px, 100%);
  padding: var(--space-2);
}

.portada-demo__titulo {
  margin: 0;
  font-size: var(--size-sm);
  font-weight: 700;
  color: var(--color-text);
  text-align: center;
}

.portada-demo__nota {
  margin: 0;
  font-size: var(--size-xs);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-text-soft);
  text-align: center;
}

/* -------------------------------------------------------------------------
   SELECTOR DE TIPOS — .portada-selector
   La rejilla .rejilla-tipos y la tarjeta .tarjeta-tipo viven en v2.css;
   aquí solo el envoltorio de sección compacto y la limpieza del <ul>.
   ------------------------------------------------------------------------- */
.portada-selector {
  padding-block: var(--space-6);
}

.portada-selector__lista {
  list-style: none;
  margin: 0;
  padding: 0;
}

.portada-selector__lista > li {
  margin: 0;
}

/* El enlace-tarjeta no debe heredar el subrayado azul global. */
.portada-selector .tarjeta-tipo {
  text-decoration: none;
}

/* Slider horizontal SOLO EN MOVIL (peticion 31/07: "de 4 en 4, 2 arriba y
   2 abajo, deslizable con el dedo"). Solo esta lista via el compound
   selector .rejilla-tipos.portada-selector__lista: el paso 1 del editor
   comparte .rejilla-tipos pero no lleva esta clase, asi que sigue en
   rejilla normal. Snap nativo por scroll (sin JS): el dedo mueve el
   scroll y cada grupo de 4 encaja, exactamente como pidio el cliente.
   Las columnas se quedan 28px por debajo de la mitad exacta a proposito:
   ese hueco lo rellena un asomo de la tercera columna (peticion "que se
   sepa que se puede scrollear horizontal"), sin flechas ni dots — el
   propio recorte de la siguiente tarjeta es la pista, y desaparece solo
   al llegar al final real de la lista. */
@media (max-width: 640px) {
  .rejilla-tipos.portada-selector__lista {
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-template-rows: repeat(2, 1fr);
    grid-auto-columns: calc((100% - var(--space-2) - 28px) / 2);
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
  }

  /* La barra de scroll sobra: el gesto de deslizar ya avisa que hay mas. */
  .rejilla-tipos.portada-selector__lista {
    scrollbar-width: none;
  }
  .rejilla-tipos.portada-selector__lista::-webkit-scrollbar {
    display: none;
  }

  /* Encaja al principio de cada grupo de 4 (2 columnas): tarjeta 1, 5, 9... */
  .portada-selector__lista > li:nth-child(4n + 1) {
    scroll-snap-align: start;
  }
}

/* -------------------------------------------------------------------------
   FRANJA DE PERSONALIZACIÓN — .portada-perso
   Enseña lo que se puede tocar: lista compacta "icono + negrita, 4-5
   palabras" y los 5 esquemas de color de v2 como muestra ESTÁTICA
   (aquí no se elige nada; se elige en el editor).
   ------------------------------------------------------------------------- */
.portada-perso__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-5);
  align-items: center;
}

@media (min-width: 900px) {
  /* align-items: start (peticion 31/07: con "center" la lista de la
     izquierda, mas corta, quedaba flotando a media altura mientras la
     columna de esquemas se extendia arriba y abajo de ella — leia
     descuadrado). Ambas columnas arrancan ahora del mismo borde superior. */
  .portada-perso__grid {
    grid-template-columns: 1.2fr 0.8fr;
    align-items: start;
  }
}

.portada-perso__col-izquierda {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

@media (min-width: 900px) {
  /* La columna izquierda se estira a la altura de la fila (la marca la
     tarjeta de esquemas, mas alta) y centra su contenido dentro de ese
     alto (feedback 1/08: quedaba pegada arriba con un resto de espacio
     vacio abajo, sin centrar respecto al bloque de la derecha). */
  .portada-perso__col-izquierda {
    align-self: stretch;
    justify-content: center;
  }
}

.portada-perso__lista {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: var(--space-4) var(--space-3);
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Segunda rejilla apilada bajo OPCIONES (1/08): mismas clases .portada-
   perso__lista/__item que la de arriba —pedido explicito: "deja los
   estilos como las dos filas de arriba"— asi que solo hace falta el
   margen de separacion entre ambas. */
.portada-perso__lista--confianza {
  margin-top: var(--space-4);
}

/* 31/07 noche (peticion explicita): por debajo de 640px el auto-fill de
   arriba no cabe ni una columna de 220px, asi que OPCIONES y CONFIANZA
   caian en una sola columna larga de 12 filas apiladas. Se parten en dos
   MITADES LADO A LADO —6 arriba (OPCIONES) y 6 abajo (CONFIANZA) pasan a
   ser columna izquierda/columna derecha— en vez de una lista larga. Cada
   .portada-perso__lista pierde su propio auto-fill (ya no hace falta:
   la columna que le toca YA es su unica columna) y pasa a una sola pista
   para no repetir el grid dentro del grid. */
@media (max-width: 640px) {
  .portada-perso__col-izquierda {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: var(--space-4);
    align-items: start;
  }
  .portada-perso__lista {
    grid-template-columns: minmax(0, 1fr);
  }
  .portada-perso__lista--confianza {
    margin-top: 0;
  }
}

/* align-items: flex-start (no center) SOLO dentro del item, no en la
   lista: el grid deja el align-items por defecto (stretch), asi que
   todos los items de una fila comparten la misma altura (la del mas
   alto) y no quedan bordes inferiores irregulares (verificar.mjs lo
   detecto: filas de 23 y 36 px mezcladas al forzar "start" arriba).
   Con el item estirado a esa altura comun, flex-start hace que el
   icono case con la primera linea del texto tenga 1 o 2 lineas, en
   vez de centrarse contra el hueco extra de los items de 1 linea. */
.portada-perso__item {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  margin: 0;
  font-size: var(--size-sm);
  font-weight: 700;
  line-height: 1.3;
  color: var(--color-text);
}

.portada-perso__icono {
  flex: none;
  margin-top: 0.1em;
  color: var(--color-brand);
}

/* Tarjeta propia (1/08): antes era texto suelto junto a la lista y, al
   ser mas alta que la lista corta de 2 filas, la nota quedaba flotando
   sola en el hueco de abajo (feedback: "no me gusta nada", "distribuye
   bien esas cosas"). Con fondo, borde y padding propios lee como una
   pieza deliberada — mismo lenguaje pastel que el mosaico de arriba —
   en vez de una ocurrencia de ultima hora. */
.portada-perso__esquemas {
  display: grid;
  row-gap: var(--space-3);
  justify-items: start;
  align-content: start;
  padding: var(--space-4);
  background: var(--pulido-tinte);
  border-radius: var(--radius-xl);
}

@media (min-width: 900px) {
  .portada-perso__esquemas {
    justify-items: center;
    text-align: center;
  }
}

.portada-perso__esquemas-titulo {
  margin: 0;
  font-size: var(--size-sm);
  font-weight: 700;
  color: var(--color-text-muted);
}

/* Mensaje corto bajo los esquemas (1/08, simplificado tras feedback: el
   texto largo anterior sobraba). margin:0 a proposito: el espaciado ya
   lo da el row-gap del grid padre, doblarlo aqui era lo que abria el
   hueco de mas frente a los esquemas. */
.portada-perso__esquemas-nota {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  font-size: var(--size-sm);
  font-weight: 700;
  color: var(--color-brand-dark);
}

.portada-perso__esquemas-nota-icono {
  flex: none;
  color: var(--color-brand);
}

/* Muestra estática: sin radio no hay nada que pulsar. */
.portada-perso__esquemas .esquemas__opcion {
  cursor: default;
}

/* Movil estrecho (medido con Playwright: por debajo de 480px los 6
   circulos + sus 6 etiquetas no caben en una fila, y encogerlos obligaba a
   partir "Atardecer"/"Nocturno" en dos lineas con guion, feo y dificil de
   leer (feedback: "que los nombres no se corten"). En vez de eso, aqui SOLO
   en la muestra estatica de portada se pasa de una fila de 6 a 4 por fila
   (4 arriba, 2 abajo): flex-wrap en vez de grid a proposito, porque
   justify-content:center SI centra la fila incompleta de 2 como grupo
   (peticion literal: "centralo bien en el contenedor"); con grid esos 2
   se habrian quedado pegados a la izquierda bajo las columnas 1-2. El
   circulo se queda a su tamaño normal de 44px: medido que a 320px de
   ancho hay ~58px por elemento y la etiqueta mas larga (Atardecer) solo
   necesita ~56px, cabe sin cortarse. */
@media (max-width: 479px) {
  .portada-perso__esquemas .esquemas {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--space-4) var(--space-1);
  }

  /* -2px de margen aposta: sin el, a 320px de ancho el calculo cuadraba
     exacto (0 px de sobra) y el redondeo de subpixel tiraba la 4a columna
     a la fila siguiente (visto medido: salia 3+3 en vez de 4+2). */
  .portada-perso__esquemas .esquemas__opcion {
    flex: 0 1 calc(25% - var(--space-1) * 3 / 4 - 2px);
  }

  /* La frase larga bajo los esquemas dejaba "marca" sola en una segunda
     linea, descuadrada (feedback: "que sea solo una linea"). Se acorta
     el texto (misma promesa, sin "favoritos") y se reduce el tamaño de
     letra: medido que asi cabe en una sola linea desde 320px de ancho. */
  .portada-perso__esquemas-nota {
    font-size: var(--size-xs);
  }
}

/* -------------------------------------------------------------------------
   CTA FINAL — .portada-final
   ------------------------------------------------------------------------- */
.portada-final {
  text-align: center;
}

.portada-final__titulo {
  margin-bottom: var(--space-4);
}

/* Línea de precio bajo el CTA. El importe sale de PRECIO (textos.js),
   marcado como ejemplo hasta que Jorge confirme el definitivo. */
.portada-final__precio {
  margin: var(--space-3) 0 0;
  font-size: var(--size-sm);
  color: var(--color-text-muted);
}

/* -------------------------------------------------------------------------
   26. EDITOR v2 (era src/estilos/editor-v2.css)
   ------------------------------------------------------------------------- */

/* -------------------------------------------------------------------------
   1. ESTRUCTURA
   ------------------------------------------------------------------------- */
.editor-v2 {
  padding-block: var(--space-4) 0;
}

.editor-v2__cabecera {
  max-width: var(--width-text);
  margin-bottom: var(--space-4);
}

.editor-v2__lead {
  margin: 0;
  color: var(--color-text-muted);
}

.editor-v2__cuerpo {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-5);
  align-items: start;
  /* Hueco para la barra de vista previa + el stepper en móvil. */
  padding-bottom: 132px;
}

@media (min-width: 1024px) {
  .editor-v2__cuerpo {
    grid-template-columns: minmax(0, 1fr) 340px;
    gap: var(--space-6);
    padding-bottom: var(--space-6);
  }
}

.editor-v2__titulo-paso {
  font-size: var(--size-xl);
  margin-bottom: var(--space-2);
}

.editor-v2__lead-paso {
  margin-bottom: var(--space-4);
  color: var(--color-text-muted);
  font-size: var(--size-sm);
}

/* Familias de tipos del paso 1 (dinámicos / estáticos). */
.editor-v2__familia {
  border: 0;
  padding: 0;
  margin: 0 0 var(--space-5);
}

.editor-v2__leyenda {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
  font-size: var(--size-sm);
  font-weight: 700;
  color: var(--color-text-muted);
}

.editor-v2__leyenda-icono {
  color: var(--color-brand);
  flex: none;
}

/* La tarjeta de tipo del paso 1 necesita position para el radio absoluto. */
.editor-v2 .tarjeta-tipo {
  position: relative;
}

/* Subtítulo de acordeón: "Choose your color scheme" bajo el nombre. */
.panel__sub {
  display: block;
  font-size: var(--size-xs);
  font-weight: 400;
  color: var(--color-text-soft);
}

/* -------------------------------------------------------------------------
   2. COLUMNA DE VISTA PREVIA
   Escritorio: sticky bajo la cabecera. Móvil: barra fija sobre el stepper
   que NUNCA desaparece; el botón la expande y la contrae.
   ------------------------------------------------------------------------- */
.editor-v2__vista {
  position: sticky;
  top: var(--space-4);
}

.editor-v2__vista-boton {
  display: none;
}

.editor-v2__vista-cuerpo {
  display: block;
}

.editor-v2__telefono {
  width: min(260px, 100%);
}

.editor-v2__vista-pie {
  margin: var(--space-3) 0 var(--space-3);
  text-align: center;
  font-size: var(--size-xs);
  color: var(--color-text-soft);
}

/* Altura reservada del aviso de legibilidad: el texto cambia solo. */
.editor-v2__estado {
  min-height: 116px;
  margin-bottom: 0;
}

@media (max-width: 1023px) {
  /* La cola del formulario tiene que LIBRAR la barra de vista previa fija
     (45px sobre el stepper): sin este aire, el ultimo campo queda debajo
     y no se puede tocar (arreglo 30/07, movil real). */
  .editor-v2__panel {
    padding-bottom: 96px;
  }

  .editor-v2__vista {
    position: fixed;
    inset-inline: 0;
    /* top: auto es OBLIGATORIO: la regla base (escritorio sticky) pone
       top 16px, y un fixed con top Y bottom a la vez se estira de arriba
       abajo — panel blanco a pantalla completa tapando TODO el editor.
       Fallo real visto en el movil del cliente el 30/07. */
    top: auto;
    bottom: 64px; /* la altura mínima del stepper */
    z-index: 19;
    background: var(--color-bg);
    border-top: 1px solid var(--color-border);
    box-shadow: 0 -6px 16px rgba(17, 24, 39, 0.08);
  }

  .editor-v2__vista-boton {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    width: 100%;
    min-height: 44px;
    padding: var(--space-2) var(--space-4);
    border: 0;
    background: transparent;
    color: var(--color-text);
    font-family: var(--font-base);
    font-size: var(--size-sm);
    font-weight: 700;
    cursor: pointer;
  }

  .editor-v2__vista-boton:focus-visible {
    outline: 2px solid var(--color-focus);
    outline-offset: -2px;
  }

  .editor-v2__vista-boton-icono {
    color: var(--color-brand);
  }

  /* Contraída por defecto: solo la barra. Abierta: el móvil entero. */
  .editor-v2__vista-cuerpo {
    display: none;
  }

  .editor-v2--vista-abierta .editor-v2__vista-cuerpo {
    display: block;
    /* Tercer limite (01/08): el panel es fixed y crece hacia ARRIBA desde
       bottom:64px (el stepper). Con solo 70vh/640px, al abrirlo con la
       pagina arriba del todo (scroll 0) el panel se salia por encima de
       la cabecera Y del titulo "Create your QR code" + su miga de pan,
       cortandolos a la mitad (medido: 26 px de solape con el <h1> en un
       movil de 390x844). El tercer termino resta cabecera + miga + titulo
       + boton de la barra + margen (300px, medido con el <h1> real, no
       solo la cabecera) a la altura de la ventana: el panel nunca sube
       mas arriba de donde termina ese bloque fijo de cabecera. */
    max-height: min(70vh, 640px, calc(100vh - 300px));
    overflow-y: auto;
    padding: var(--space-3) var(--space-4) var(--space-4);
  }

  .editor-v2--vista-abierta .editor-v2__vista-boton-chevron {
    transform: rotate(180deg);
  }

  .editor-v2__telefono {
    width: min(220px, 70vw);
  }
}

/* -------------------------------------------------------------------------
   3. CONMUTADOR PÁGINA / CÓDIGO QR
   ------------------------------------------------------------------------- */
.vista-conmutador {
  display: flex;
  justify-content: center;
  gap: var(--space-1);
  margin-bottom: var(--space-3);
  padding: 3px;
  width: fit-content;
  margin-inline: auto;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 999px;
}

.vista-conmutador__boton {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-height: 32px;
  padding: 0 var(--space-3);
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--color-text-muted);
  font-family: var(--font-base);
  font-size: var(--size-xs);
  font-weight: 700;
  cursor: pointer;
}

.vista-conmutador__boton--activo {
  background: var(--color-bg);
  color: var(--color-text);
  box-shadow: var(--shadow-sm);
}

.vista-conmutador__boton:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 2px;
}

.vista-conmutador__icono {
  flex: none;
}

/* -------------------------------------------------------------------------
   4. MAQUETAS DE LA VISTA PREVIA (.prev y familias)
   Todo el marcado viene del servidor; editor-preview.js solo rellena texto
   y conmuta .oculto. Los colores del esquema "Appearance" entran por las
   variables --prev-fondo / --prev-acento / --prev-contenido que el JS pone
   en el contenedor (estado, no maquetación).
   ------------------------------------------------------------------------- */
.prev {
  position: absolute;
  inset: 0;
  overflow-y: auto;
  padding: 16% 8% 10%;
  background: var(--prev-fondo, #f8fafc);
  color: var(--prev-contenido, var(--color-text));
  font-size: 13px;
  line-height: 1.35;
}

.prev__panel {
  display: grid;
  justify-items: center;
  gap: var(--space-3);
  text-align: center;
}

/* Pantalla inicial, antes de elegir tipo. */
.prev-inicio {
  display: grid;
  justify-items: center;
  gap: var(--space-3);
  padding-top: 40%;
  color: var(--color-text-soft);
}

.prev-inicio__icono {
  color: var(--color-border-strong);
}

.prev-inicio__texto {
  margin: 0;
  font-size: 12px;
  max-width: 20ch;
}

/* Piezas comunes. */
.prev-boton {
  /* min-height 40px (01/08): el CTA estandar de mas de 20 plantillas
     (Play, Visit, Pay, Send...) medía ~28px de alto, por debajo del
     minimo tactil recomendado. inline-flex centra el texto dentro del
     alto nuevo sin tocar el padding-inline ni el tamano de fuente. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 40px;
  padding: 6px 16px;
  border-radius: 999px;
  background: var(--prev-acento, var(--color-brand));
  color: #ffffff;
  font-size: 12px;
  font-weight: 700;
}

.prev-titular {
  margin: 0;
  font-size: 14px;
  font-weight: 700;
  overflow-wrap: anywhere;
}

.prev-parrafo {
  margin: 0;
  font-size: 12px;
  overflow-wrap: anywhere;
}

.prev-nota {
  margin: 0;
  font-size: 11px;
  color: inherit;
  opacity: 0.7;
  overflow-wrap: anywhere;
}

/* Cabecera de ficha (vcard, negocio, social, apps). */
.prev-cabecera {
  display: grid;
  justify-items: center;
  gap: 6px;
  width: 100%;
}

.prev-cabecera__avatar {
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: var(--prev-acento, var(--color-brand));
  color: #ffffff;
  font-size: 18px;
  font-weight: 700;
}

.prev-cabecera__avatar--icono {
  background: var(--prev-acento, var(--color-brand));
}

/* Avatar con la imagen SUBIDA por el usuario (editor-preview.js la pinta
   como fondo via FileReader, peticion 30/07): cubre el circulo y esconde
   las iniciales o el icono de muestra. */
.prev-cabecera__avatar--subido {
  background-size: cover;
  background-position: center;
  color: transparent;
}

/* SIN FOTO en un panel con pagina real (05/08/2026): la foto ilustrada de
   muestra se esconde y salen las iniciales sobre el acento, que es JUSTO lo
   que hara la pagina /p/ (avatarConMonograma en el servidor). Las iniciales
   las pone editor-preview.js en data-inic. */
/* CINTA DE HONESTIDAD (06/08/2026): en los tipos que redirigen, la maqueta
   del movil es atrezzo — lo que se abre al escanear es la web de la persona
   o un dialogo del sistema. Va PEGADA arriba y por encima de todo, para que
   no se pueda confundir la maqueta con el resultado. */
.prev-aviso-real {
  position: sticky;
  top: 0;
  z-index: 3;
  display: flex;
  align-items: center;
  gap: 6px;
  margin: -8px 0 10px;
  padding: 6px 8px;
  border-radius: 8px;
  background: rgba(17, 24, 39, 0.86);
  color: #f9fafb;
  font-size: 10.5px;
  line-height: 1.25;
  text-align: left;
}
.prev-aviso-real__etiqueta {
  flex: none;
  padding: 1px 5px;
  border-radius: 4px;
  background: #f59e0b;
  color: #111827;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* Doble clase a proposito: las variantes --logo (linea ~8111) van despues
   en el fichero y con una sola clase ganarian el fondo blanco y el
   display:block del img. */
.prev-cabecera__avatar.prev-cabecera__avatar--sinfoto {
  background: var(--prev-acento, var(--color-brand));
  border: 0;
  padding: 0;
  overflow: hidden;
}
.prev-cabecera__avatar.prev-cabecera__avatar--sinfoto img {
  display: none;
}
.prev-cabecera__avatar.prev-cabecera__avatar--sinfoto::after {
  content: attr(data-inic);
  color: #ffffff;
  font-size: 18px;
  font-weight: 700;
}
.prev-cabecera__avatar--subido > * {
  visibility: hidden;
}

.prev-cabecera__titulo {
  margin: 0;
  font-size: 15px;
  font-weight: 700;
  overflow-wrap: anywhere;
}

.prev-cabecera__sub {
  margin: 0;
  font-size: 11px;
  opacity: 0.75;
  overflow-wrap: anywhere;
}

/* Filas de datos con icono (teléfono, correo, dirección...). */
.prev-filas {
  display: grid;
  gap: 8px;
  width: 100%;
  margin: 0;
  padding: 0;
  list-style: none;
  text-align: left;
}

.prev-filas__fila {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 10px;
  border-radius: var(--radius);
  background: rgba(17, 24, 39, 0.05);
  font-size: 11px;
  overflow-wrap: anywhere;
  min-width: 0;
}

.prev-filas__fila > span {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.prev-filas__icono {
  flex: none;
  color: var(--prev-acento, var(--color-brand));
}

/* Lista de botones (redes sociales, tiendas de apps). */
.prev-redes {
  display: grid;
  gap: 8px;
  width: 100%;
  margin: 0;
  padding: 0;
  list-style: none;
}

.prev-redes__red {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  border-radius: 999px;
  background: var(--prev-acento, var(--color-brand));
  color: #ffffff;
  font-size: 12px;
  font-weight: 700;
}

.prev-redes__punto {
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.7);
}

/* Lista de enlaces. */
.prev-enlaces {
  display: grid;
  gap: 8px;
  width: 100%;
  margin: 0;
  padding: 0;
  list-style: none;
}

.prev-enlaces__enlace {
  padding: 8px 12px;
  border: 1px solid var(--prev-acento, var(--color-brand));
  border-radius: var(--radius);
  color: var(--prev-acento, var(--color-brand));
  font-size: 11px;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Reproductores (vídeo y audio). */
.prev-player {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
}

.prev-player--video {
  aspect-ratio: 16 / 9;
  border-radius: var(--radius);
  background: #111827;
}

.prev-player--audio {
  padding: 12px;
  border-radius: var(--radius);
  background: rgba(17, 24, 39, 0.05);
}

/* Triángulo de reproducción: un borde, cero assets. */
.prev-player__play {
  width: 0;
  height: 0;
  border-style: solid;
  border-width: 10px 0 10px 16px;
  border-color: transparent transparent transparent #ffffff;
}

.prev-player__play--circulo {
  box-sizing: content-box;
  border-width: 7px 0 7px 11px;
  border-left-color: #ffffff;
  padding: 6px 5px 6px 8px;
  border-radius: 50%;
  background: var(--prev-acento, var(--color-brand));
}

.prev-player__barra {
  flex: 1;
  height: 4px;
  border-radius: 2px;
  background: var(--prev-acento, var(--color-brand));
  opacity: 0.5;
}

/* Documento PDF. */
.prev-doc {
  display: grid;
  place-items: center;
  width: 72px;
  height: 92px;
  border-radius: var(--radius);
  border: 1px solid var(--color-border-strong);
  background: #ffffff;
  color: #b91c1c;
}

/* Galería. */
.prev-galeria {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
  width: 100%;
  margin: 0;
  padding: 0;
  list-style: none;
}

.prev-galeria__foto {
  display: grid;
  place-items: center;
  aspect-ratio: 4 / 3;
  border-radius: var(--radius);
  background: rgba(17, 24, 39, 0.08);
  color: var(--color-text-soft);
}

/* Evento: la fecha en un dado. */
.prev-evento {
  display: grid;
  justify-items: center;
  min-width: 64px;
  border-radius: var(--radius);
  overflow: hidden;
  border: 1px solid var(--color-border-strong);
  background: #ffffff;
  color: #111827;
}

.prev-evento__dia {
  padding: 6px 12px 2px;
  font-size: 20px;
  font-weight: 700;
  line-height: 1;
}

.prev-evento__mes {
  width: 100%;
  padding: 2px 8px;
  background: var(--prev-acento, var(--color-brand));
  color: #ffffff;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* Opiniones: estrellas. */
.prev-estrellas {
  display: flex;
  gap: 4px;
  color: #d97706;
}

.prev-estrellas__estrella--vacia {
  opacity: 0.3;
}

/* Cupón. */
.prev-cupon {
  display: grid;
  justify-items: center;
  gap: 6px;
  width: 100%;
  padding: 14px 12px;
  border: 2px dashed var(--prev-acento, var(--color-brand));
  border-radius: var(--radius-lg);
  background: #ffffff;
  color: #111827;
}

.prev-cupon__titulo {
  margin: 0;
  font-size: 16px;
  font-weight: 700;
  overflow-wrap: anywhere;
}

.prev-cupon__etiqueta {
  margin: 0;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  opacity: 0.6;
}

.prev-cupon__codigo {
  margin: 0;
  padding: 4px 12px;
  border-radius: var(--radius);
  background: rgba(17, 24, 39, 0.08);
  font-family: var(--font-mono, monospace);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.1em;
  overflow-wrap: anywhere;
}

.prev-cupon__condiciones {
  margin: 0;
  font-size: 10px;
  opacity: 0.7;
  overflow-wrap: anywhere;
}

.prev-cupon__caducidad {
  margin: 0;
  font-size: 10px;
  font-weight: 700;
}

/* Navegador (url, url fija, youtube). */
.prev-navegador {
  display: flex;
  align-items: center;
  gap: 5px;
  width: 100%;
  padding: 6px 8px;
  border-radius: 999px;
  border: 1px solid var(--color-border);
  background: #ffffff;
}

.prev-navegador__punto {
  flex: none;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--color-border-strong);
}

.prev-navegador__barra {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 10px;
  color: var(--color-text-muted);
  text-align: left;
}

/* Esqueleto de página bajo el navegador. */
.prev-esqueleto {
  display: grid;
  gap: 8px;
  width: 100%;
}

.prev-esqueleto__bloque {
  height: 84px;
  border-radius: var(--radius);
  background: rgba(17, 24, 39, 0.08);
}

/* Variante de YouTube: el bloque se vuelve un reproductor oscuro. El
   triángulo se dibuja con dos pseudoelementos, sin assets. */
.prev-esqueleto--youtube .prev-esqueleto__bloque {
  position: relative;
  background: #111827;
}

.prev-esqueleto--youtube .prev-esqueleto__bloque::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  border-style: solid;
  border-width: 9px 0 9px 15px;
  border-color: transparent transparent transparent #ffffff;
}

.prev-esqueleto__linea {
  height: 8px;
  border-radius: var(--radius-sm);
  background: rgba(17, 24, 39, 0.1);
}

.prev-esqueleto__linea--corta {
  width: 60%;
}

/* Texto plano. */
.prev-texto {
  display: grid;
  justify-items: center;
  gap: 10px;
  width: 100%;
  padding: 14px 12px;
  border-radius: var(--radius-lg);
  background: rgba(17, 24, 39, 0.05);
}

.prev-texto__icono {
  color: var(--prev-acento, var(--color-brand));
}

.prev-texto__mensaje {
  margin: 0;
  font-size: 12px;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* Wifi. */
.prev-wifi {
  display: grid;
  justify-items: center;
  gap: 8px;
  padding-top: 20%;
}

.prev-wifi__icono {
  color: var(--prev-acento, var(--color-brand));
}

.prev-wifi__red {
  margin: 0;
  font-size: 15px;
  font-weight: 700;
  overflow-wrap: anywhere;
}

.prev-wifi__seguridad {
  margin: 0;
  font-size: 11px;
  opacity: 0.7;
}

/* Chat (SMS y WhatsApp). */
.prev-chat {
  display: grid;
  gap: 10px;
  width: 100%;
  justify-items: start;
}

.prev-chat__cabecera {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  width: 100%;
  margin: 0;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--color-border);
}

.prev-chat__app {
  font-size: 12px;
  font-weight: 700;
  color: var(--prev-acento, var(--color-brand));
}

.prev-chat__numero {
  font-size: 11px;
  opacity: 0.7;
  overflow-wrap: anywhere;
}

.prev-chat__burbuja {
  margin: 0;
  max-width: 90%;
  padding: 8px 12px;
  border-radius: 14px 14px 14px 4px;
  background: var(--prev-acento, var(--color-brand));
  color: #ffffff;
  font-size: 12px;
  text-align: left;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.prev-chat .prev-boton {
  justify-self: center;
}

/* Correo. */
.prev-email {
  display: grid;
  gap: 8px;
  width: 100%;
  text-align: left;
}

.prev-email__campo {
  display: flex;
  gap: 6px;
  margin: 0;
  padding: 7px 10px;
  border-radius: var(--radius);
  background: rgba(17, 24, 39, 0.05);
  font-size: 11px;
  min-width: 0;
}

.prev-email__campo > span:last-child {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.prev-email__etiqueta {
  flex: none;
  font-weight: 700;
  opacity: 0.6;
}

.prev-email__cuerpo {
  margin: 0;
  min-height: 56px;
  padding: 10px;
  border-radius: var(--radius);
  border: 1px solid var(--color-border);
  background: #ffffff;
  color: #111827;
  font-size: 11px;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.prev-email .prev-boton {
  justify-self: center;
}

/* -------------------------------------------------------------------------
   5. EL CÓDIGO QR DENTRO DEL MÓVIL
   ------------------------------------------------------------------------- */
.prev-qr {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 18% 10%;
  background: #f8fafc;
}

.prev-qr__lienzo {
  display: block;
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  border-radius: var(--radius-sm);
}

/* -------------------------------------------------------------------------
   6. AJUSTES PROPIOS DEL EDITOR
   ------------------------------------------------------------------------- */
/* Grupos de acciones dentro del stepper: los conmuta el mismo mecanismo
   de pasos ([data-paso] + .paso--activo) que las secciones. */
.stepper__grupo {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

/* En pantallas estrechas el CTA no necesita tanto relleno. */
@media (max-width: 640px) {
  .editor-v2 .cta {
    min-height: 44px;
    padding: var(--space-2) var(--space-4);
    font-size: var(--size-sm);
  }

  /* BUG real (01/08, movil real 320-412px): esta regla de arriba tiene la
     misma especificidad que la compactacion del stepper (bloque 4,
     arreglo 30/07) y aparece DESPUES en el archivo, asi que la pisaba por
     completo: "Atras" recuperaba su texto (font-size ya no en 0) y el CTA
     de pago volvia a un padding-inline de 16px por lado. Resultado medido:
     el boton "Download"/"Descargar" del paso 3 se salia de la pantalla
     entre 30 y 104px en los 35+ tipos y en los dos idiomas, sin scroll
     horizontal para alcanzarlo (verificar.mjs no lo ve: solo mide el paso 1
     por defecto). Estos compuestos, con una clase mas, ganan siempre pase
     lo que pase con el orden del archivo. */
  .editor-v2 .stepper__acciones .cta {
    padding-inline: var(--space-2);
    gap: var(--space-1);
  }
  .editor-v2 .stepper__acciones .cta--fantasma {
    font-size: 0;
    gap: 0;
    padding-inline: var(--space-2);
  }
}

/* El aviso de legibilidad dentro de la barra móvil no reserva tanto. */
@media (max-width: 1023px) {
  .editor-v2__estado {
    min-height: 0;
  }
}

/* -------------------------------------------------------------------------
   7. MOVIMIENTO — todo aquí dentro; fuera, los estados cambian en seco.
   ------------------------------------------------------------------------- */
@media (prefers-reduced-motion: no-preference) {
  .vista-conmutador__boton {
    transition:
      background-color var(--dur-micro) var(--curva),
      color var(--dur-micro) var(--curva),
      box-shadow var(--dur-micro) var(--curva);
  }

  .editor-v2__vista-boton-chevron {
    transition: transform var(--dur-micro) var(--curva);
  }

  .prev-boton,
  .prev-redes__red,
  .prev-cabecera__avatar {
    transition: background-color var(--dur-entrada) var(--curva);
  }

  .prev {
    transition:
      background-color var(--dur-entrada) var(--curva),
      color var(--dur-entrada) var(--curva);
  }
}

/* -------------------------------------------------------------------------
   27. PAGINA DE PAGO UNICO (.pago) (era src/estilos/pago.css)
   ------------------------------------------------------------------------- */

.pago {
  padding: var(--space-7) 0 var(--space-8);
}

.pago__titulo {
  text-align: center;
  margin-bottom: var(--space-3);
}

/* Subtitulo bajo el h1: el reclamo honesto del pago unico. */
.pago__reclamo {
  text-align: center;
  color: var(--color-text-muted, #4b5563);
  max-width: 34rem;
  margin: 0 auto var(--space-6);
}

/* Banner del modo demo. Es un .notice normal, solo se le da sitio. */
.pago__demo {
  max-width: 44rem;
  margin: 0 auto var(--space-5);
}

/* ── Estado "sin QR": corto y con una sola salida, el editor ───────────── */

.pago__vacio {
  max-width: 26rem;
  margin: 0 auto;
  text-align: center;
}

.pago__vacio-texto {
  margin-bottom: var(--space-5);
}

/* ── Panel de compra: QR a un lado, oferta al otro ─────────────────────── */

.pago__panel {
  display: grid;
  gap: var(--space-6);
  max-width: 52rem;
  margin: 0 auto;
  align-items: start;
}

@media (min-width: 720px) {
  .pago__panel {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr);
  }
}

/* Tarjeta del QR: el producto terminado, elevado como el movil del editor. */
.pago__qr {
  background: #ffffff;
  border: 1px solid var(--color-border, #e5e7eb);
  border-radius: var(--radius-xl, 16px);
  box-shadow: var(--shadow-lg);
  padding: var(--space-5);
}

/* Reserva el hueco del QR ANTES de que el JS pinte la imagen: sin salto. */
.pago__qr-marco {
  aspect-ratio: 1;
  display: grid;
  place-items: center;
}

.pago__qr-marco img {
  width: 100%;
  height: 100%;
  max-width: 256px;
  max-height: 256px;
  object-fit: contain;
}

.pago__qr-nota {
  margin: var(--space-4) 0 0;
  text-align: center;
  font-size: var(--size-sm, 0.875rem);
  color: var(--color-text-muted, #4b5563);
}

/* ── Oferta: lista de lo que incluye, precio y UN boton ────────────────── */

.pago__incluye {
  list-style: none;
  padding: 0;
  margin: 0 0 var(--space-5);
  display: grid;
  gap: var(--space-3);
}

.pago__incluye-item {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
}

.pago__incluye-icono {
  flex-shrink: 0;
  color: var(--color-cta);
  /* El icono mide 20 px: se alinea con la primera linea del texto. */
  margin-top: 2px;
}

.pago__precio {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  margin: 0 0 var(--space-1);
}

.pago__importe {
  font-size: 2.25rem;
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.02em;
}

.pago__precio-tipo {
  color: var(--color-text-muted, #4b5563);
}

/* La marca de "precio de ejemplo": visible a proposito mientras el cliente
   no confirme el definitivo. Se quita quitando el parrafo, no con CSS. */
.pago__precio-nota {
  margin: 0 0 var(--space-5);
  font-size: var(--size-sm, 0.875rem);
  color: var(--color-text-muted, #4b5563);
}

.pago__seguro {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  margin: var(--space-3) 0 0;
  font-size: var(--size-sm, 0.875rem);
  color: var(--color-text-muted, #4b5563);
}

.pago__error {
  margin-bottom: var(--space-4);
}

/* ── Exito: check, gracias y las descargas desbloqueadas ───────────────── */

.pago__exito {
  text-align: center;
}

.pago__exito-check {
  margin: 0 auto var(--space-4);
}

.pago__exito-mascota {
  display: block;
  width: 96px;
  height: auto;
  margin: 0 auto var(--space-3);
}

.pago__exito-titulo {
  margin-bottom: var(--space-2);
}

.pago__exito-texto {
  color: var(--color-text-muted, #4b5563);
  margin-bottom: var(--space-5);
}

.pago__descargas {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-3);
  margin-bottom: var(--space-3);
}

.pago__descargas-nota {
  font-size: var(--size-sm, 0.875rem);
  color: var(--color-text-muted, #4b5563);
  margin: 0;
}

/* ── Movimiento. TODO dentro del media: sin motion, estados en seco. ───── */

@media (prefers-reduced-motion: no-preference) {
  /* La tarjeta del QR entra con el mismo lenguaje que los reveals de v2. */
  .pago__qr {
    animation: v2-aparecer var(--dur-entrada) var(--curva) both;
  }

  .pago__panel > * + * {
    animation: v2-aparecer var(--dur-entrada) var(--curva) 80ms both;
  }
}

/* -------------------------------------------------------------------------
   28. PULIDO VISUAL 07/2026 — HOME (era src/estilos/pulido-home.css)
   ------------------------------------------------------------------------- */

/* =========================================================================
   PULIDO DE LA HOME (07/2026)

   Piel nueva de la portada EN (/) y ES (/es-ES/) tras el feedback del
   cliente ("la de qrcreator se ve hecha muy bonita, la nuestra se ve hecha
   con IA"). La estructura y los textos NO cambian; cambia la presentacion:

   1. Hero con titular a dos tonos (frase clave en azul), fondo tenido azul
      palidisimo y composicion en capas a la derecha: captura REAL del
      editor (public/img/producto/editor-paso3-qr.png) en tarjeta con sombra
      grande + el marco de movil con el QR vivo solapado en la esquina.
   2. Pasos 1-2-3 con las ilustraciones paso-N-recorte.jpg (estilo de la
      referencia: panel pastel azul) recortadas en circulo.
   3. Franja de personalizacion con la panoramica personalizacion.jpg.
   4. Ritmo de secciones: hero tenido -> tipos blanco -> pasos tenido ->
      personalizacion blanco -> FAQ en BANDA AZUL DE MARCA -> CTA blanco.
      La banda azul entera esta PERMITIDA como excepcion consciente a la
      regla del fondo blanco: la referencia del cliente la lleva y Jorge
      pidio algo "mas llamativo" (documentado en LEEME.md).
   5. Tarjetas sin borde duro: sombra suave en capas y hover con elevacion.

   Reglas de la casa que se respetan: BEM, cero estilos en linea, colores
   sobre las variables de :root, movimiento solo dentro de
   prefers-reduced-motion: no-preference, alturas reservadas (CLS 0).
   ========================================================================= */

:root {
  /* Tenido azul palidisimo de las secciones alternas del ritmo. Es el punto
     medio del degradado --franja-suave, aplicado plano. */
  --pulido-tinte: #f4f7fe;

  /* Sombras en capas para tarjetas SIN borde duro: una de contacto muy
     corta y una de ambiente amplia, con un matiz del azul de marca. */
  --pulido-sombra-tarjeta:
    0 1px 2px rgba(17, 24, 39, 0.05),
    0 6px 18px rgba(26, 86, 219, 0.08);
  --pulido-sombra-alzada:
    0 4px 10px rgba(17, 24, 39, 0.06),
    0 18px 40px rgba(26, 86, 219, 0.16);
}

/* -------------------------------------------------------------------------
   1. HERO — .portada-hero--pulido
   ------------------------------------------------------------------------- */

/* Fondo tenido plano (el degradado --franja-suave de antes volvia a blanco
   por abajo y el corte con el selector no se veia). Sin borde inferior:
   el cambio de color ya separa. */
.portada-hero--pulido {
  background: var(--pulido-tinte);
  border-bottom: 0;
}

/* Titular a dos tonos, como la referencia: la frase clave en azul de
   marca dentro de <span class="acento">. */
.portada-hero--pulido .acento {
  color: var(--color-brand);
}

/* A dos columnas casi parejas: la composicion de producto pesa mas que el
   movil solo de antes y merece su mitad. */
@media (min-width: 1024px) {
  .portada-hero--pulido .portada-hero__grid {
    grid-template-columns: 1.05fr 0.95fr;
  }
}

/* --- Composicion en capas de la derecha --------------------------------
   Captura real del editor en tarjeta con radio y sombra grande, y el
   marco de movil con el QR vivo solapado en la esquina inferior derecha.
   El movil va en absoluto: no empuja nada (CLS 0) y el hueco que asoma
   por abajo cabe en el padding de la seccion. */
.pulido-compo {
  position: relative;
}

.pulido-compo__editor {
  display: block;
  width: 100%;
  height: auto;
  background: var(--color-bg);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-flotante);
}

.pulido-compo__movil {
  position: absolute;
  right: -10px;
  bottom: -26px;
  width: 168px;
}

/* El tope de 260 px que el hero ponia al telefono no aplica dentro de la
   composicion: aqui manda el ancho de la capa. */
.portada-hero__demo.pulido-compo .telefono {
  width: 100%;
}

/* -------------------------------------------------------------------------
   2. RITMO DE SECCIONES
   .pulido-tinte pinta la seccion de pasos; la banda azul va en el punto 5.
   ------------------------------------------------------------------------- */
.pulido-tinte {
  background: var(--pulido-tinte);
}

/* -------------------------------------------------------------------------
   3. PASOS 1-2-3 — .pulido-paso
   Ilustraciones paso-N-recorte.jpg (516x516, recorte central de las
   paso-N.jpg 640x640 hecho por scripts/recortar-ilustraciones.mjs: el
   panel pastel llega al borde y el margen blanco queda fuera) en circulo.
   El recorte va en el FICHERO y no en un transform: scale del CSS porque
   un elemento escalado que desborda su caja cuenta como overflow
   desplazable y verificar.mjs lo media como contenido recortado (19,2 px).
   Numero del paso como insignia solapada.
   ------------------------------------------------------------------------- */
.pulido-paso {
  text-align: center;
}

.pulido-paso__vineta {
  position: relative;
  display: inline-block;
  margin-bottom: var(--space-4);
}

.pulido-paso__media {
  display: block;
  width: 160px;
  height: 160px;
  border-radius: 50%;
  overflow: hidden;
  background: #dce8fb;
  box-shadow: var(--pulido-sombra-tarjeta);
}

.pulido-paso__img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.pulido-paso .step__number {
  position: absolute;
  right: 0;
  bottom: 4px;
  margin: 0;
  /* Anillo del color del fondo tenido: separa la insignia del circulo. */
  box-shadow: 0 0 0 3px var(--pulido-tinte);
}

.pulido-paso .step__text {
  max-width: 30ch;
  margin-inline: auto;
}

.pulido-tinte__cta {
  margin-top: var(--space-8);
  text-align: center;
}

/* -------------------------------------------------------------------------
   4. FRANJA DE PERSONALIZACION — mosaico de QRs reales (31/07)
   Sustituye la foto unica de 4 estilos por 8 renders REALES capturados del
   propio editor (scripts/generar-mosaico.mjs, canvases validados con jsQR,
   no maquetas). aspect-ratio: 1200/420 es EL MISMO alto que tenia la caja
   de la foto anterior a proposito: mas variedad, mismo hueco en la pagina,
   CLS 0. Los 8 PNG son cuadrados (200x200); object-fit: contain los centra
   sin deformar dentro de cada celda rectangular.
   ------------------------------------------------------------------------- */
.pulido-perso__mosaico {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-template-rows: repeat(2, minmax(0, 1fr));
  gap: var(--space-2);
  margin: 0 0 var(--space-6);
  padding: var(--space-3);
  /* 1/08: 420 se quedaba corto para la etiqueta con texto mas grande
     (quedaba angosta). 460 le da aire arriba y abajo sin desbordar la
     franja. */
  aspect-ratio: 1200 / 460;
  background: var(--pulido-tinte);
  border-radius: var(--radius-xl);
  box-shadow: var(--pulido-sombra-tarjeta);
  list-style: none;
}

/* Cada pieza es imagen + etiqueta corta ("Con tu logo", "Marco
   personalizado"...): sin ella el mosaico era bonito pero mudo, no decia
   que se podia tocar en cada una (feedback 31/07). La etiqueta vive
   DENTRO de la pieza, no aparte, para no crecer el alto fijo del banner. */
.pulido-perso__mosaico-pieza {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  border-radius: var(--radius-md);
  overflow: hidden;
  background: #ffffff;
  box-shadow: var(--shadow-sm);
}

.pulido-perso__mosaico-pieza img {
  display: block;
  width: 100%;
  min-height: 0;
  flex: 1 1 auto;
  object-fit: contain;
}

/* Icono + texto en vez de solo texto (1/08): la primera version era gris
   plano y se perdia contra el resto de la pagina. Mismo lenguaje que
   OPCIONES/CONFIANZA (icono de marca + negrita), asi que casa con el
   resto en vez de leer como una nota aparte. */
.pulido-perso__mosaico-etiqueta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  flex: none;
  /* 1/08: 4px 3px quedaba muy angosto (feedback del cliente); con mas
     padding vertical y letra mas grande respira. Sin nowrap/ellipsis:
     si una etiqueta larga no cabe en una linea, pasa a dos en vez de
     cortarse con puntos suspensivos. */
  padding: 7px 6px;
  background: linear-gradient(180deg, #ffffff 0%, var(--pulido-tinte) 100%);
  border-top: 1px solid var(--color-border);
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.01em;
  line-height: 1.25;
  color: var(--color-text);
  text-align: center;
}

.pulido-perso__mosaico-etiqueta-icono {
  flex: none;
  color: var(--color-brand);
}

/* Pieza de IA: mismo formato pero con un acento propio (violeta), para que
   se note de un vistazo que es la pieza distinta del lote — sin decirlo
   con palabras raras, solo con color, como el resto del sistema. */
.pulido-perso__mosaico-pieza--ia .pulido-perso__mosaico-etiqueta {
  background: linear-gradient(180deg, #ffffff 0%, #f5f0fe 100%);
  color: #6d28d9;
}

.pulido-perso__mosaico-pieza--ia .pulido-perso__mosaico-etiqueta-icono {
  color: #9333ea;
}

/* A este ancho 4x2 celdas rectangulares quedan demasiado apretadas para
   que el patron del QR se lea; se pasa a cuadrados de verdad y se suelta
   el alto fijo (el banner crece un poco en movil, a proposito). */
@media (max-width: 640px) {
  .pulido-perso__mosaico {
    aspect-ratio: auto;
    gap: var(--space-1);
    padding: var(--space-2);
  }
  .pulido-perso__mosaico-pieza {
    aspect-ratio: 1;
  }
}

/* 31/07 (medido con getBoundingClientRect en 390px real): con 4 columnas
   fijas cada pieza quedaba en 78x78px, la etiqueta de dos palabras
   ("Logo + gradient", "AI artwork") se apretaba en una caja del tamano de
   un icono y el patron del QR era ilegible. Con 2 columnas cada pieza
   pasa a ~165px: el QR se lee y la etiqueta cabe en una linea. */
@media (max-width: 480px) {
  .pulido-perso__mosaico {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-rows: repeat(4, minmax(0, 1fr));
  }
}

/* -------------------------------------------------------------------------
   5. FAQ EN BANDA AZUL DE MARCA — .pulido-banda
   Fondo azul entero (excepcion consciente, ver cabecera), titulo y enlace
   en blanco, y las tarjetas de pregunta en blanco sin borde, con sombra.
   ------------------------------------------------------------------------- */
.pulido-banda {
  background: linear-gradient(180deg, var(--color-brand) 0%, var(--color-brand-dark) 100%);
}

.pulido-banda .section__head h2 {
  color: #ffffff;
}

.pulido-banda .faq__item--abierto {
  border-color: transparent;
  border-radius: var(--radius-lg);
  box-shadow: var(--pulido-sombra-tarjeta);
}

.pulido-banda .section__foot a {
  color: #ffffff;
}

/* El anillo de foco azul de la casa no se ve sobre la banda azul. */
.pulido-banda a:focus-visible {
  outline-color: #ffffff;
}

/* -------------------------------------------------------------------------
   6. TARJETAS DEL SELECTOR SIN BORDE DURO — .pulido-selector
   Borde transparente (el hueco del borde se conserva: ni un pixel de
   salto), sombra suave en capas y hover con elevacion. El foco de teclado
   sigue siendo el outline de la casa.
   ------------------------------------------------------------------------- */
.pulido-selector .tarjeta-tipo {
  border-color: transparent;
  box-shadow: var(--pulido-sombra-tarjeta);
}

.pulido-selector .tarjeta-tipo:hover {
  border-color: transparent;
  box-shadow: var(--pulido-sombra-alzada);
}

/* Movimiento solo con motion permitido; sin el, el hover cambia de sombra
   al instante y nada se desplaza. */
@media (prefers-reduced-motion: no-preference) {
  .pulido-selector .tarjeta-tipo {
    transition:
      box-shadow var(--dur-micro) var(--curva),
      transform var(--dur-micro) var(--curva);
  }

  .pulido-selector .tarjeta-tipo:hover {
    transform: translateY(-2px);
  }
}

/* -------------------------------------------------------------------------
   29. PULIDO VISUAL 07/2026 — RESTO DEL SITIO (era src/estilos/pulido-resto.css)
   ------------------------------------------------------------------------- */

/* =========================================================================
   PULIDO DEL RESTO DEL SITIO
   QR Creator / JR Netmedia — pulido visual 07/2026

   Contexto: feedback del cliente ("se ve hecha con IA") contra la
   referencia docs/espec/home-1440.jpg. Este fichero cubre lo que queda
   fuera de la portada: paginas de tipo (/generate/<slug>/ y
   /es-ES/generar/<slug>/), indices de tipos, pago y la piel del editor.

   Que cambia y por que:
     1. .captura            — capturas REALES de producto en las cabeceras
                              ilustradas, en tarjeta con sombra suave; fuera
                              las cajas punteadas de "Space for image", que
                              eran lo que delataba la web.
     2. .card               — tarjetas de tipo con sombra suave SIN borde
                              duro, como las de la referencia.
     3. .pago__*            — ilustracion de pago seguro junto a las
                              garantias y paneles con el acabado nuevo.
     4. .editor-v2 .panel   — solo piel: paneles del editor con sombra
                              suave en vez de borde. Nada estructural.

   Reglas de la casa: BEM, cero estilos en linea, toda transicion dentro
   de @media (prefers-reduced-motion: no-preference).
   ========================================================================= */

/* -------------------------------------------------------------------------
   1. CAPTURA DE PRODUCTO EN LA CABECERA ILUSTRADA
   Sustituye al hueco punteado (HuecoImagen) en las 42 paginas de tipo y en
   los dos indices de tipos. El <img> lleva width/height reales en el
   marcado: el navegador reserva la altura por aspect-ratio y el CLS es 0.
   ------------------------------------------------------------------------- */
.captura {
  display: block;
  max-width: 100%;
  height: auto;
  margin-inline: auto;
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-flotante);
  background: var(--color-bg);
}

/* Captura ancha (editor a pantalla completa, 2336x1360). En una columna
   comparte tope con el texto (--width-text), igual que hacia el hueco;
   en dos columnas llena su columna, que es el mismo criterio del anuncio
   de .layout-doc. */
.captura--panoramica {
  width: min(100%, var(--width-text));
}

@media (min-width: 1024px) {
  .cabecera-ilustrada__imagen > .captura--panoramica {
    width: 100%;
  }
}

/* Captura de movil: mas estrecha y centrada. El tope de 250 px la deja a
   la escala del movil del editor (.editor-v2__telefono, 260 px). */
.captura--movil {
  width: clamp(180px, 56%, 250px);
}

/* Ilustraciones que se integran con la pagina (peticion 30/07): fuera la
   tarjeta blanca con sombra; el fondo blanco del JPG se funde con el fondo
   de la seccion y solo "flota" el grafico. */
.captura--integrada {
  background: none;
  border-radius: 0;
  box-shadow: none;
}

/* Carta del tipo menu (lote 2, 30/07): secciones en versalitas y lineas
   "plato — precio" en pre-line (el JS mete saltos de linea reales). */
.prev-carta {
  padding: 0 var(--space-4) var(--space-4);
  text-align: left;
}
.prev-carta__seccion {
  margin: var(--space-3) 0 2px;
  font-size: var(--size-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--prev-acento, var(--color-brand));
}
.prev-carta__lineas {
  margin: 0;
  font-size: var(--size-sm);
  white-space: pre-line;
  color: var(--color-text);
}
.prev-carta__alergenos {
  margin: var(--space-3) 0 0;
  font-size: var(--size-xs);
  color: var(--color-text-soft);
}

/* Estrellas de la maqueta de resena: ambar, en fila. */
.prev-resena__estrellas {
  display: flex;
  gap: 2px;
  margin: var(--space-2) 0;
  color: #f59e0b;
}

/* Filas de colores por ojo (30/07): nombre + marco + punto. */
.colores-ojos {
  display: grid;
  gap: var(--space-2);
  margin-top: var(--space-2);
}
.colores-ojos__fila {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 44px 44px;
  align-items: center;
  gap: var(--space-2);
}
.colores-ojos__nombre {
  font-size: var(--size-sm);
  color: var(--color-text-muted);
}

/* Mosaico de QRs reales de la seccion de personalizacion (30/07). */
.mosaico-qr {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-3);
  list-style: none;
  margin: 0 0 var(--space-5);
  padding: 0;
}
@media (max-width: 640px) {
  .mosaico-qr { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.mosaico-qr__pieza {
  border-radius: var(--radius-md);
  overflow: hidden;
  border: 1px solid var(--color-border);
  background: #ffffff;
  box-shadow: var(--shadow-sm);
}
.mosaico-qr__pieza img {
  display: block;
  width: 100%;
  height: auto;
}

/* Tarjetas del indice de sectores (30/07): ilustracion arriba, texto abajo. */
.card--sector { padding: 0; overflow: hidden; }
.card--sector .card__foto {
  width: 100%;
  height: auto;
  display: block;
  aspect-ratio: 3 / 2;
  object-fit: cover;
}
.card--sector .card__title { margin: var(--space-3) var(--space-4) 0; }
.card--sector .card__text { margin: var(--space-1) var(--space-4) var(--space-4); }

/* Barra deshacer/rehacer del paso Diseno (30/07). */
.diseno-historial {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
}

/* Plantillas 1-clic del editor (30/07): rejilla de combos con miniatura.
   Cada muestra pinta los dos colores dominantes de su plantilla. */
.plantillas {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
  gap: var(--space-2);
}
.plantillas__opcion {
  display: grid;
  justify-items: center;
  gap: 6px;
  padding: var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-bg);
  cursor: pointer;
  font-family: var(--font-base);
}
.plantillas__opcion:hover {
  border-color: var(--color-brand);
}
.plantillas__opcion:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 2px;
}
.plantillas__muestra {
  width: 40px;
  height: 40px;
  border-radius: var(--radius-md);
  border: 1px solid var(--color-border);
  background: #ffffff;
}
.plantillas__nombre {
  font-size: var(--size-xs);
  color: var(--color-text);
  text-align: center;
}
.plantillas__muestra--clasica { background: linear-gradient(135deg, #111827 55%, #ffffff 55%); }
.plantillas__muestra--oceano { background: linear-gradient(135deg, #1a56db 55%, #0e7490 55%); }
.plantillas__muestra--bosque { background: linear-gradient(135deg, #065f46 55%, #ecfdf5 55%); }
.plantillas__muestra--atardecer { background: linear-gradient(135deg, #d97706 55%, #b91c1c 55%); }
.plantillas__muestra--nocturna { background: linear-gradient(135deg, #111827 55%, #4b5563 55%); }
.plantillas__muestra--tinta { background: linear-gradient(135deg, #0f2a66 55%, #eff4fe 55%); }
.plantillas__muestra--corazones { background: linear-gradient(135deg, #b91c1c 55%, #fee2e2 55%); }
.plantillas__muestra--estrellas { background: linear-gradient(135deg, #b45309 55%, #fffbeb 55%); }
.plantillas__muestra--floral { background: linear-gradient(135deg, #047857 55%, #d1fae5 55%); }
.plantillas__muestra--scanme { background: linear-gradient(180deg, #ffffff 62%, #1a56db 62%); border-color: #1a56db; }
.plantillas__muestra--carta { background: linear-gradient(180deg, #ffffff 62%, #047857 62%); border-color: #047857; }
.plantillas__muestra--vip { background: linear-gradient(180deg, #fffbeb 62%, #b45309 62%); border-color: #b45309; }

/* Biblioteca de logos precargados del editor (30/07). */
.logos-biblio {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(44px, 1fr));
  gap: var(--space-2);
}
.logos-biblio__opcion {
  display: grid;
  place-items: center;
  min-height: 44px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-bg);
  color: var(--color-text);
  cursor: pointer;
}
.logos-biblio__opcion:hover {
  border-color: var(--color-brand);
  color: var(--color-brand);
}
.logos-biblio__opcion:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 2px;
}

/* Direccion de cartera en el panel cripto: monoespaciada y partida donde
   haga falta (una direccion BTC no cabe entera en una linea del movil). */
.prev-cripto__direccion {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: var(--size-sm);
  word-break: break-all;
  max-width: 100%;
}

/* -------------------------------------------------------------------------
   2. TARJETAS DE TIPO CON SOMBRA SUAVE, SIN BORDE DURO
   La referencia eleva sus tarjetas con sombra difusa y sin contorno. El
   borde se queda transparente (no a 0) para que la caja mida lo mismo y
   nada se desplace. .card solo se usa en los indices de tipos y en los
   relacionados de las paginas de tipo: no pisa nada fuera de este pulido.

   Los selectores compuestos (.card-grid .card, .pago .pago__qr,
   .editor-v2 .panel...) vienen de cuando este bloque vivia en un fichero
   aparte y necesitaba ganar la cascada; se conservan porque tambien
   protegen frente a reordenaciones futuras del fichero.
   ------------------------------------------------------------------------- */
.card-grid .card {
  border-color: transparent;
  box-shadow: var(--shadow-lg);
}

.card-grid .card:hover {
  border-color: transparent;
  box-shadow: var(--shadow-flotante);
}

/* -------------------------------------------------------------------------
   3. PAGO: ILUSTRACION DE PAGO SEGURO + ACABADO DE PANELES
   ------------------------------------------------------------------------- */

/* Fila garantias + ilustracion. En pantallas estrechas la ilustracion
   encoge antes que bajar: la lista es lo que tiene que leerse. */
.pago__garantias {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  margin-bottom: var(--space-5);
}

.pago__garantias > .pago__incluye {
  flex: 1 1 auto;
  margin-bottom: 0;
}

.pago__garantias-img {
  flex: none;
  width: 132px;
  height: 132px;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}

@media (max-width: 479px) {
  .pago__garantias-img {
    width: 104px;
    height: 104px;
  }
}

/* La oferta pasa de flotar sobre el fondo a ser un panel como el del QR:
   misma familia que la tarjeta de enfrente, sombra suave y sin borde. */
.pago__oferta {
  padding: var(--space-5);
  background: var(--color-bg);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg);
}

/* La tarjeta del QR pierde el borde duro: la sombra ya la separa. */
.pago .pago__qr {
  border-color: transparent;
}

/* -------------------------------------------------------------------------
   4. PIEL DEL EDITOR: PANELES CON SOMBRA EN VEZ DE BORDE
   Solo apariencia. La estructura, los acordeones y el stepper no se tocan.
   ------------------------------------------------------------------------- */
.editor-v2 .panel__detalle {
  border-color: transparent;
  box-shadow: var(--shadow);
}

/* ARREGLO medido (29/07/2026, en el build v=8 servido en local): dentro de
   la vista previa del movil, `.oculto { display:none }` esta declarado ANTES
   que `.prev__panel { display:grid }` y `.prev-qr { display:grid }` mas
   arriba en este fichero, asi que a igualdad de especificidad ganaba el
   grid: los 19 paneles se apilaban visibles y la vista del QR
   (position:absolute) tapaba SIEMPRE la maqueta de pagina — el conmutador
   Page/QR no cambiaba nada. Con la clase doble (0,2,0) el oculto gana este
   la regla donde este; se deja asi a proposito, como cinturon frente a
   reordenaciones. */
.prev__panel.oculto,
.prev-qr.oculto {
  display: none;
}

/* -------------------------------------------------------------------------
   MOVIMIENTO. Todo aqui dentro; sin motion los estados cambian en seco.
   ------------------------------------------------------------------------- */
@media (prefers-reduced-motion: no-preference) {
  .card-grid .card,
  .pago__garantias-img {
    transition: box-shadow var(--dur-micro) var(--curva);
  }
}

/* =========================================================================
   PARIDAD 07/2026 — fusionado de src/estilos/ (fase final)
   Bloques: campos nuevos del paso 2 (horario, lista de enlaces, aviso de
   formato), piezas nuevas del preview (categorias de opiniones, cupon) y
   selector de marcos por categorias. BEM, cero estilos en linea.
   ========================================================================= */

/* ── Horario semanal ───────────────────────────────────────────────────── */

.horario {
  border: 0;
  padding: 0;
  margin: 0;
  min-inline-size: 0;
}

.horario__dia {
  display: grid;
  grid-template-columns: minmax(7.5rem, 1fr) auto auto auto;
  align-items: center;
  gap: var(--space-2, 0.5rem);
  padding-block: var(--space-1, 0.25rem);
}

.horario__marca {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2, 0.5rem);
  min-width: 0;
}

.horario__nombre {
  font-size: var(--size-sm, 0.875rem);
  color: var(--color-text, #111827);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.horario__hora {
  width: 6.75rem;
  min-height: 2.25rem;
}

.horario__sep {
  color: var(--color-text-soft, #6b7280);
}

/* En pantallas estrechas las horas bajan a su propia línea. */
@media (max-width: 420px) {
  .horario__dia {
    grid-template-columns: auto auto auto;
  }

  .horario__marca {
    grid-column: 1 / -1;
  }
}

/* ── Lista de enlaces (etiqueta + URL) ─────────────────────────────────── */

.lista-enlaces {
  border: 0;
  padding: 0;
  margin: 0;
  min-inline-size: 0;
}

.lista-enlaces__fila {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr);
  gap: var(--space-2, 0.5rem);
  margin-block-end: var(--space-2, 0.5rem);
}

@media (max-width: 480px) {
  .lista-enlaces__fila {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* ── Aviso de formato (validación suave, nunca bloquea) ────────────────── */

.field__error {
  margin: var(--space-1, 0.25rem) 0 0;
  font-size: var(--size-xs, 0.75rem);
  line-height: var(--line-base, 1.55);
  color: var(--color-danger, #b91c1c);
}

/* ── Estado del fondo animado (GIF/vídeo): leyendoFotogramas/ok/error ──── */

.field__estado {
  margin: var(--space-1) 0 0;
  font-size: var(--size-xs);
  line-height: 1.5;
  color: var(--color-text-soft);
}
.field__estado--error {
  color: var(--color-danger);
  font-weight: 600;
}
.field__estado--ok {
  color: var(--color-success);
}

/* ── Opiniones: categorías a valorar ───────────────────────────────────── */

.prev-categorias {
  display: grid;
  gap: 6px;
  width: 100%;
  margin: 0;
  padding: 0;
  list-style: none;
}

.prev-categorias__categoria {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  min-width: 0;
  padding: 6px 10px;
  border-radius: var(--radius);
  background: rgba(17, 24, 39, 0.05);
  font-size: 11px;
  text-align: left;
}

.prev-categorias__nombre {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 600;
}

.prev-categorias__estrellas {
  display: flex;
  flex: none;
  gap: 4px;
  color: #d97706;
}

/* Objetivo tactil (01/08): el glifo de 12px era el control activo mas
   pequeno de las 36 plantillas (hay que tocar una estrella concreta para
   puntuar). Sin espacio para las 40-44px recomendadas en una fila de 5
   estrellas x 3 categorias, se sube lo que cabe sin que se toquen entre
   si: icono el doble de grande y mas separacion. */
.prev-categorias__estrellas svg {
  width: 16px;
  height: 16px;
}

.prev-categorias__estrella--vacia {
  opacity: 0.3;
}

/* ── Cupón: empresa, insignia y descripción ────────────────────────────── */

.prev-cupon__empresa {
  margin: 0;
  font-size: 10px;
  font-weight: 600;
  opacity: 0.6;
  overflow-wrap: anywhere;
}

.prev-cupon__insignia {
  margin: 0;
  padding: 2px 10px;
  border-radius: 999px;
  background: var(--prev-acento, var(--color-brand));
  color: #ffffff;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.prev-cupon__descripcion {
  margin: 0;
  font-size: 11px;
  overflow-wrap: anywhere;
}

/* ── "Sin marco", fijo fuera del filtro ────────────────────────────────── */

.opciones--sin-marco {
  margin-bottom: var(--space-3, 0.75rem);
}

/* La tarjeta de "Sin marco" no necesita ocupar toda la rejilla */
.opciones--sin-marco .opciones__grid--marcos {
  grid-template-columns: repeat(auto-fill, minmax(116px, 1fr));
}

/* ── Chips de categoría con contador ───────────────────────────────────── */

.marcos-filtro {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2, 0.5rem);
  margin-bottom: var(--space-4, 1rem);
}

.marcos-filtro__chip {
  appearance: none;
  border: 1px solid var(--color-border, #e5e7eb);
  border-radius: 999px;
  background-color: var(--color-bg, #ffffff);
  color: var(--color-text-muted, #4b5563);
  font: inherit;
  font-size: var(--size-xs, 0.75rem);
  font-weight: 600;
  line-height: 1;
  padding: 0.5rem 0.75rem;
  cursor: pointer;
}

.marcos-filtro__chip:hover {
  border-color: var(--color-brand, #1a56db);
  color: var(--color-text, #111827);
}

.marcos-filtro__chip:focus-visible {
  outline: 3px solid var(--color-focus, #1a56db);
  outline-offset: 2px;
}

.marcos-filtro__chip--activo {
  border-color: var(--color-brand, #1a56db);
  background-color: var(--color-brand-light, #eff4fe);
  color: var(--color-brand-dark, #1543ac);
}

/* Los grupos filtrados se ocultan con [hidden] desde /js/editor.js; el
   atributo ya oculta por defecto, esto solo blinda ante display propios. */
.opciones[data-marcos-cat][hidden] {
  display: none;
}


/* -------------------------------------------------------------------------
   30. AJUSTES DE LA REVISION DEL 30/07 (feedback del cliente, uno a uno)
   ------------------------------------------------------------------------- */

/* (9b) Topos de lista visibles junto a las tarjetas del editor: fuera. */
.rejilla-tipos { list-style: none; padding-left: 0; }
.rejilla-tipos > li { margin: 0; list-style: none; }

/* (1)(9a) "Todas deben tener la misma altura": la rejilla estira las celdas,
   el titulo reserva UNA linea y la descripcion exactamente DOS. Vale para la
   home y para el paso 1 del editor, que comparten clases. */
.rejilla-tipos { align-items: stretch; }
.rejilla-tipos > li > .tarjeta-tipo { height: 100%; }
.tarjeta-tipo__nombre { display: block; min-height: 1.35em; }
.tarjeta-tipo__detalle {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: calc(1.45em * 2);
}

/* (2) Los tres pasos con DOS lineas de descripcion reservadas: la base de
   los tres bloques queda alineada aunque un texto parta distinto. */
.step__text { min-height: calc(1.55em * 2); }

/* (4) Hover de botones: la regla global de enlaces (a:hover azul) pisaba el
   color del texto de los CTA que son <a>. Color explicito en todos los
   estados, con la especificidad de elemento+clase para ganar siempre.
   Excluidas las variantes que ya fijan su propio color (fantasma,
   secundario, desactivado): si no, esta regla las gana por especificidad
   y deja texto blanco sobre fondo blanco/transparente (boton "Atras"
   invisible, arreglo 31/07). */
a.cta:not(.cta--fantasma):not(.cta--secundario):not(.cta--desactivado),
a.cta:not(.cta--fantasma):not(.cta--secundario):not(.cta--desactivado):hover,
a.cta:not(.cta--fantasma):not(.cta--secundario):not(.cta--desactivado):focus-visible,
a.cta:not(.cta--fantasma):not(.cta--secundario):not(.cta--desactivado):active,
button.cta:not(.cta--fantasma):not(.cta--secundario):not(.cta--desactivado),
button.cta:not(.cta--fantasma):not(.cta--secundario):not(.cta--desactivado):hover { color: #ffffff; }
a.button--secondary:hover { color: var(--color-brand-dark); }

/* (6) Los dos bloques explicativos (dinamico/estatico) a la misma altura:
   texto con tres lineas reservadas. Se aplica con .pareja-bloques en el ul. */
.pareja-bloques .feature__text { min-height: calc(1.55em * 3); }

/* Correccion optica (feedback 30/07): el glifo de Phosphor lleva ~15% de
   aire interno, asi que el icono parecia sangrado respecto al titulo y al
   texto de debajo. Se compensa lo justo para alinear el TRAZO con el texto. */
.pareja-bloques .feature__icon { margin-inline-start: -4px; }

/* Comparativa dinamico/estatico centrada (feedback 30/07: media pantalla
   vacia a la derecha). Solo esta seccion: las paginas de documento siguen
   con su columna alineada a la izquierda. */
.seccion-comparativa .section__head { text-align: center; }
.seccion-comparativa .section__foot { display: flex; justify-content: center; }
@media (min-width: 1024px) {
  .seccion-comparativa .layout-doc--solo {
    grid-template-columns: minmax(0, 860px);
    justify-content: center;
  }
}

/* (5) Imagen de cabecera de /tipos-de-qr/: la ilustracion sin texto ocupa
   su caja con la proporcion real (1100x614) y sombra suave. */
.cabecera-ilustrada__imagen > .ilustracion-tarjeta {
  width: 100%;
  height: auto;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-flotante);
}

/* (8) Secciones de tipo sin lateral de anuncio: nada de columna vacia.
   La naturaleza va a dos columnas con el AVISO como tarjeta lateral (contenido
   real, no relleno) y las preguntas a rejilla de dos columnas. */
.doc-flujo { display: grid; gap: var(--space-5); align-items: start; }
@media (min-width: 1024px) {
  .doc-flujo { grid-template-columns: minmax(0, 1fr) 340px; }
}
.doc-flujo__aviso { margin: 0; }
.doc-flujo__aviso .notice { height: 100%; }

.faq--dos { display: grid; gap: var(--space-3); }
@media (min-width: 1024px) {
  .faq--dos { grid-template-columns: 1fr 1fr; align-items: stretch; }
  .faq--dos .faq__item { height: 100%; margin: 0; }
}

/* El grid quita el margin-bottom de .faq__item en escritorio, asi que sin
   esto el parrafo de enlaces generales queda pegado a la ultima pregunta. */
.faq--dos + .texto-suave { margin-top: var(--space-4); }

/* (hero v3) El movil vivo protagonista. El ambiente lo pinta el fondo de la
   SECCION (.portada-hero__fondo, peticion 30/07 de que la imagen ocupe toda
   la seccion); esta caja solo centra el telefono y manda en la altura. */
/* OJO: sin `display` en la base. La demo entera va display:none por debajo
   de 1024 px (.portada-hero__demo) y un display aqui, que queda despues en
   el archivo, la resucitaria como franja vacia en movil. */
.compo-v3 {
  position: relative;
  padding: var(--space-5) var(--space-4);
}
@media (min-width: 1024px) {
  .compo-v3 {
    display: flex;
    align-items: center;
    justify-content: center;
  }
}
/* Ancho FIJO en el envoltorio: .telefono mide `min(260px, 100%)` y ese 100%
   necesita un padre con ancho definido — si el padre lo saca del contenido,
   el circulo se resuelve a 0 y el telefono desaparece. */
.compo-v3__movil {
  position: relative;
  z-index: 1;
  width: min(260px, 100%);
}

/* Micro-flotacion del movil del hero (30/07): 3px en 6s, solo si el
   usuario no pide movimiento reducido. La sombra de contacto eliptica va
   en un ::after para que el telefono deje de "flotar sin peso". */
@media (prefers-reduced-motion: no-preference) {
  @keyframes compo-flotar {
    0%, 100% { transform: translateY(0); }
    50% { transform: translateY(-3px); }
  }
  .compo-v3__movil .telefono {
    animation: compo-flotar 6s ease-in-out infinite;
  }
}
.compo-v3__movil::after {
  content: '';
  position: absolute;
  left: 50%;
  bottom: -14px;
  width: 70%;
  height: 16px;
  transform: translateX(-50%);
  border-radius: 50%;
  background: radial-gradient(ellipse at center, rgba(17, 24, 39, 0.18) 0%, rgba(17, 24, 39, 0) 70%);
  pointer-events: none;
}

/* El claro (resplandor) de la panoramica queda a la DERECHA del centro de la
   columna a partir de ~1280 px: el movil se corre hacia el, proporcional al
   ancho (0 a 1280px, ~64px a 1920px), para ocupar su sitio en la escena.
   transform: no mueve el layout, asi que no puede crear desbordes. */
@media (min-width: 1280px) {
  /* Pendiente 0.21 (2a vuelta 30/07: con 0.1 el movil seguia pisando el
     soporte a 1920). A 1440 da ~34px y a 1920 ~134px, que deja el movil
     sobre el claro, pasado el soporte. */
  .compo-v3__movil {
    transform: translateX(clamp(0px, calc((100vw - 1280px) * 0.21), 145px));
  }
}
@media (min-width: 1600px) {
  .compo-v3__movil {
    width: min(290px, 100%);
  }
  /* Acompaña al envoltorio: sin esto, el tope de 260px de
     .portada-hero__demo .telefono se comeria el crecimiento. */
  .compo-v3 .telefono {
    width: min(290px, 100%);
  }
}

/* -------------------------------------------------------------------------
   31. PRUEBA SOCIAL DEL HERO (feedback 30/07): caritas redondas solapadas
   + valoracion. Sin cifra inventada de clientes: la referencia pone un
   "45.817 tests completados hoy" a fuego y es justo lo que no copiamos.
   ------------------------------------------------------------------------- */
.prueba-social {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-5);
  flex-wrap: wrap;
}

.prueba-social__caras {
  display: flex;
  list-style: none;
  margin: 0;
  padding: 0;
}

.prueba-social__cara {
  width: 40px;
  height: 40px;
  margin: 0 0 0 -12px;              /* solape */
  border-radius: 50%;
  border: 2px solid var(--color-bg);
  overflow: hidden;
  background: var(--color-surface);
  box-shadow: var(--shadow-sm);
}
.prueba-social__cara:first-child { margin-left: 0; }
.prueba-social__cara img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.prueba-social__texto {
  margin: 0;
  font-size: var(--size-sm);
  color: var(--color-text-muted);
  line-height: 1.3;
}

.prueba-social__estrellas {
  display: inline-flex;
  align-items: center;
  color: #f59e0b;                  /* ambar de valoracion */
}
.prueba-social__estrella { fill: currentColor; }

/* -------------------------------------------------------------------------
   32. SECCION DE IA (feedback 30/07). Nuestro angulo honesto: la referencia
   genera QR con IA que no escanean; los nuestros se validan antes de
   descargar. Las piezas de la galeria son QR artisticos DECORATIVOS.
   ------------------------------------------------------------------------- */
/* Mas aire que el resto de section--tight (31/07: la galeria a dos filas
   quedaba muy pegada a las franjas vecinas). Solo esta seccion: no toca
   el resto de .section--tight de la pagina. */
/* padding-top reducido en movil (31/07 tarde, feedback cliente): el aire
   extra de space-8 solo hace falta ARRIBA en el layout de dos columnas
   (>=1024px); en movil, apilado, ese mismo aire caia entero encima de la
   insignia "Beta" y se veia como un salto excesivo antes del texto. Abajo
   se mantiene space-8 en todos los anchos por la galeria a dos filas. */
.seccion-ia { padding-top: var(--space-6); padding-bottom: var(--space-8); }
.seccion-ia__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-6);
  align-items: center;
}
@media (min-width: 1024px) {
  .seccion-ia { padding-top: var(--space-8); }
  /* Invertido (peticion 30/07): galeria a la IZQUIERDA y texto a la
     derecha. En movil se apila y manda el orden del HTML (texto primero,
     que es lo que vende). */
  .seccion-ia__grid { grid-template-columns: 1fr 1fr; }
  .seccion-ia__texto { order: 2; }
  .seccion-ia__galeria { order: 1; }
}

.seccion-ia__insignia {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  margin: 0 0 var(--space-3);
  padding: 4px var(--space-3);
  border-radius: 999px;
  font-size: var(--size-xs);
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-brand-dark);
  background: var(--color-brand-light);
}
.seccion-ia__insignia-icono { color: var(--color-brand); }

.seccion-ia__lead {
  color: var(--color-text-muted);
  font-size: var(--size-lg);
  margin-bottom: var(--space-4);
}

.seccion-ia__puntos {
  list-style: none;
  margin: 0 0 var(--space-5);
  padding: 0;
  display: grid;
  gap: var(--space-2);
}
.seccion-ia__puntos li {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  font-size: var(--size-sm);
  color: var(--color-text);
}
.seccion-ia__punto-icono { color: var(--color-success); flex: 0 0 auto; }

/* Galeria: piezas artisticas solapadas en filas de tres, con la del centro
   de cada fila elevada. flex-wrap en vez de anchos fijos por breakpoint:
   30% x 3 + huecos siempre supera el 100% del contenedor con la 4a pieza,
   así que envuelve sola a cualquier ancho (evita la trampa @media vs
   contenedor real del SETUP). */
.seccion-ia__galeria {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-5) var(--space-3);
}
.seccion-ia__pieza {
  margin: 0;
  width: 30%;
  max-width: 200px;
  aspect-ratio: 1;
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-flotante);
}
.seccion-ia__pieza:nth-child(3n+2) { transform: scale(1.12); z-index: 2; }
.seccion-ia__pieza:nth-child(3n+1) { transform: rotate(-4deg); }
.seccion-ia__pieza:nth-child(3n) { transform: rotate(4deg); }
.seccion-ia__pieza img { width: 100%; height: 100%; object-fit: cover; display: block; }

@media (prefers-reduced-motion: reduce) {
  .seccion-ia__pieza { transform: none !important; }
}

/* -------------------------------------------------------------------------
   33. EXPLORADOR DE TIPOS (feedback 30/07): lista de tipos + movil con el
   preview del elegido + ficha con CTA. Solo el activo se muestra; el resto
   se apila oculto pero con su hueco reservado (CLS 0). public/js/
   explorador-tipos.js conmuta; sin JS se ve el primero.
   ------------------------------------------------------------------------- */
.explorador__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-5);
  align-items: center;
}
@media (min-width: 900px) {
  /* Reparto 30/07 (2a vuelta): la ficha va en columna FIJA de 260px, con su
     borde derecho clavado al del container — el mismo que cierra la rejilla
     de tarjetas de arriba, que es la alineacion que pidio el cliente. La
     lista absorbe el resto y el telefono queda mas a la derecha. */
  /* Ficha a 200px (3a vuelta 30/07): con 260 le sobraba aire interno a la
     izquierda del contenido (que va anclado a la derecha) y el telefono
     parecia descentrado; a 200 el aire visual de ambos lados queda a la par
     y el borde derecho sigue clavado al de las tarjetas de arriba. */
  .explorador__grid {
    grid-template-columns: minmax(0, 1fr) minmax(220px, 260px) minmax(0, 200px);
    column-gap: var(--space-6);
  }
  /* Contenido de la ficha alineado a la IZQUIERDA (peticion 30/07, 2a
     vuelta: primero pidio anclarla al borde derecho, luego el texto en
     bloque a la izquierda). La COLUMNA sigue pegada al borde del container
     — el mismo que cierra las tarjetas de arriba — y dentro el icono, el
     titulo, el texto y el boton comparten eje izquierdo. */
}

.explorador__lista {
  border: 0;
  margin: 0;
  padding: 0;
  display: grid;
  /* minmax(0,1fr): sin el minimo a 0, el nombre mas largo fuerza el ancho
     de la columna y en movil la segunda se sale del viewport (cazado a la
     vista en la revision del 31/07 — verificar no lo midio porque el
     desborde quedaba recortado por un padre). */
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--space-2);
}

/* 30 tipos SIN scroll (31/07, feedback): tercera columna en escritorio y
   botones compactos — 10 filas que quedan a la altura del movil. */
@media (min-width: 900px) {
  .explorador__lista {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .explorador__opcion {
    padding: var(--space-2) 10px;
  }
}

.explorador__opcion-nombre {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Selector movil (peticion 31/07: la rejilla de 30 tarjetas obligaba a
   hacer scroll antes de llegar al movil con la preview). Un <select>
   nativo sustituye la rejilla SOLO en movil; en escritorio sigue la
   rejilla de tarjetas de siempre. */
.explorador__selector { display: none; }
@media (max-width: 899px) {
  .explorador__lista { display: none; }
  .explorador__selector {
    display: block;
    margin-bottom: var(--space-4);
  }
}

.explorador__opcion {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  cursor: pointer;
  font-size: var(--size-sm);
  font-weight: 600;
  background: var(--color-bg);
  transition: border-color var(--dur-micro) var(--curva), background var(--dur-micro) var(--curva);
}
.explorador__opcion:hover { border-color: var(--color-brand); }
.explorador__opcion-icono { color: var(--color-brand); flex: 0 0 auto; }
.explorador__opcion:has(.explorador__radio:checked) {
  border-color: var(--color-brand);
  background: var(--color-brand-light);
  color: var(--color-brand-dark);
}
.explorador__opcion:has(.explorador__radio:focus-visible) {
  outline: 3px solid var(--color-focus);
  outline-offset: 2px;
}

/* Movil central: la pantalla apila los previews; solo .activo se ve.
   Las capturas son SOLO la pantalla (481x1017, mismo aspecto que el hueco
   del marco): llenan el hueco con cover. Capturar el telefono entero daba
   un movil dentro de un movil (defecto del 30/07). */
.explorador__telefono { display: flex; justify-content: center; width: 100%; }
.explorador__pantalla {
  position: relative;
  width: 100%;
  height: 100%;
}
.explorador__preview {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  visibility: hidden;
}
.explorador__preview.activo { opacity: 1; visibility: visible; }

/* Fichas: apiladas, solo la activa visible; el contenedor reserva alto. */
.explorador__fichas { position: relative; min-height: 220px; }
.explorador__ficha {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-2);
  opacity: 0;
  visibility: hidden;
}
.explorador__ficha.activo { opacity: 1; visibility: visible; position: relative; }
.explorador__ficha-icono { color: var(--color-brand); }
.explorador__ficha-titulo { margin: 0; font-size: var(--size-xl); }
/* Texto a 2 lineas SIEMPRE (31/07: se usaba tipo.resumen, el mismo de 4-5
   palabras de la rejilla densa de arriba — demasiado corto para esta
   columna con aire). Ahora es tipo.descripcion (la frase completa),
   recortada por CSS: mismo patron que .card__titulo del SETUP del cliente
   (line-clamp + min-height reservado), asi la ficha mide igual pase lo que
   pase con la longitud real del texto de cada tipo. */
.explorador__ficha-texto {
  margin: 0 0 var(--space-3);
  color: var(--color-text-muted);
  font-size: var(--size-sm);
  line-height: 1.35;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: calc(1.35em * 2);
}

@media (prefers-reduced-motion: no-preference) {
  .explorador__preview,
  .explorador__ficha {
    transition: opacity 0.22s ease, transform 0.22s ease;
    transform: translateY(6px);
  }
  .explorador__preview.activo,
  .explorador__ficha.activo {
    transform: translateY(0);
  }
}

/* -------------------------------------------------------------------------
   34. FOTOS DE MARCA EN LOS PREVIEWS (feedback 30/07: "nuestros previews
   deben ser mejores que los de qrcreator"). La referencia ensena una foto
   de producto en la mini-landing (su "Palacio de la Pizza"); aqui igual o
   mejor. Fotos de muestra generadas con la API del cliente; se sustituiran
   por las que suba el usuario cuando exista el backend de ficheros.
   ------------------------------------------------------------------------- */

/* Galeria con fotos reales en vez de iconos grises. */
.prev-galeria--foto .prev-galeria__foto {
  padding: 0;
  overflow: hidden;
  background: none;
}
.prev-galeria--foto .prev-galeria__foto img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Portada de PDF: foto arriba, no un icono de documento suelto. */
.prev-doc--foto {
  width: 100%;
  height: 96px;
  padding: 0;
  border-radius: var(--radius);
  overflow: hidden;
}
.prev-doc--foto img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Miniatura de video con la foto detras del boton de play. */
.prev-player--foto { position: relative; overflow: hidden; }
.prev-player--foto img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.prev-player--foto .prev-player__play { position: relative; z-index: 1; }
.prev-player--foto::after {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(17, 24, 39, 0.28);   /* velo para que el play resalte */
}
.prev-player--foto .prev-player__play { z-index: 2; }

/* Portada de la ficha de negocio: banda de foto arriba del avatar. */
.prev-portada {
  width: calc(100% + 2 * var(--space-4));
  margin: calc(-1 * var(--space-4)) calc(-1 * var(--space-4)) var(--space-2);
  height: 84px;
  overflow: hidden;
}
.prev-portada img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* =========================================================================
   PREVIEWS DE MINI-LANDING, TANDA 2 (30/07/2026, noche)
   Tras recorrer la referencia y QRCodeChimp/Linktree (docs/
   mejoras-previews.md): chrome de movil ya en .telefono__chrome (bloque
   22); aqui van las piezas por tipo. Todas respetan las variables del
   bloque "Aspecto" (--prev-fondo / --prev-acento / --prev-contenido).
   ========================================================================= */

/* La utilidad .oculto pierde contra reglas posteriores de la misma
   especificidad (la trampa del panel fantasma del checkout): compuestos
   explicitos para todas las piezas nuevas con display propio. */
.prev-horario__dia.oculto,
.prev-enlaces__enlace.oculto,
.prev-galeria__foto.oculto,
.prev-categorias__categoria.oculto,
.prev-carta__fila.oculto,
.prev-filas__fila.oculto,
.prev-boton.oculto,
.prev-multi__regla.oculto,
/* 05/08/2026, sinceridad del preview: estas piezas tambien se ocultan por
   JavaScript cuando el campo esta vacio (la pagina real no las inventa), y
   todas declaran display propio mas abajo. */
.prev-seccion.oculto,
.prev-portada.oculto,
.prev-cabecera__avatar.oculto,
.prev-carta__grupo.oculto,
.prev-redes__red.oculto,
.prev-faq__par.oculto,
.prev-tiendas__insignia.oculto,
/* La cinta de honestidad declara display:flex mas abajo: sin este compuesto
   se quedaba visible (con solo la palabra "Ejemplo") en los tipos que SI
   enseñan su pagina real. Tercera vez que muerde la misma trampa hoy. */
.prev-aviso-real.oculto {
  display: none;
}

/* Filas etiquetadas (vcard, evento): etiqueta pequena arriba y valor como
   enlace, el patron de la referencia. */
.prev-filas--etiquetadas .prev-filas__fila {
  align-items: flex-start;
}

.prev-filas__dato {
  display: grid;
  gap: 1px;
  min-width: 0;
  text-align: left;
}

.prev-filas__etiqueta {
  font-size: 9.5px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  opacity: 0.55;
}

.prev-filas__valor {
  color: var(--prev-acento, var(--color-brand));
  font-weight: 600;
  overflow-wrap: anywhere;
}

/* Tarjeta de horario por dias (negocio). */
.prev-horario {
  width: 100%;
  display: grid;
  gap: 6px;
  padding: 10px 12px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: #ffffff;
  color: #111827;
  text-align: left;
}

.prev-horario__titulo {
  margin: 0;
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  font-weight: 700;
}

.prev-horario__dias {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 3px;
}

.prev-horario__dia {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  font-size: 11px;
}

.prev-horario__horas {
  color: var(--prev-acento, var(--color-brand));
  font-weight: 600;
  white-space: nowrap;
}

.prev-horario__muestra {
  margin: 0;
  font-size: 11px;
  opacity: 0.7;
}

/* Redes: fila blanca con insignia del color de la marca (antes, pildora
   de acento con punto — no se reconocia la red de un vistazo). */
.prev-redes__red {
  background: #ffffff;
  color: #111827;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  font-weight: 600;
}

/* Colores de marca por red (los style= inline los veta la comprobacion
   estatica). */
.prev-redes__insignia--instagram { background: #e1306c; }
.prev-redes__insignia--facebook { background: #1877f2; }
.prev-redes__insignia--x { background: #111827; }
.prev-redes__insignia--tiktok { background: #111827; }
.prev-redes__insignia--linkedin { background: #0a66c2; }
.prev-redes__insignia--youtube { background: #ff0000; }
/* 05/08/2026, revision exhaustiva: estas tres redes existian en los
   formularios y en seccionRedes() pero no tenian regla de color -- la
   insignia salia como letra blanca sobre nada, tanto en el preview como en
   la pagina /p/. Colores de marca oficiales. */
.prev-redes__insignia--threads { background: #111827; }
.prev-redes__insignia--discord { background: #5865f2; }
.prev-redes__insignia--twitch { background: #9146ff; }

.prev-redes__insignia {
  width: 22px;
  height: 22px;
  flex-shrink: 0;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: #ffffff;
}

/* Insignias de tienda (apps): rectangulo oscuro como las de verdad. */
.prev-tiendas {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 8px;
  width: 100%;
  justify-items: center;
}

.prev-tiendas__insignia {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-width: 156px;
  padding: 7px 14px;
  border-radius: var(--radius);
  background: #111827;
  color: #ffffff;
  font-size: 11px;
  font-weight: 600;
}

/* Reproductor de audio con caratula. */
.prev-audio {
  position: relative;
  width: 100%;
  display: grid;
  justify-items: center;
  gap: 8px;
  padding: 14px 12px 12px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: #ffffff;
  color: #111827;
}

.prev-audio__acciones {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 2; /* BUG real (01/08): .prev-portada gano position:relative
    despues (scrim de fotos hero) y, sin z-index, dos positioned con
    z-index:auto pintan por orden de DOM: la caratula (que tambien lleva
    .prev-portada) quedaba encima y tapaba el icono de descargar, el mas
    cercano al solape. Con z-index explicito los iconos ganan siempre,
    pase lo que pase con el orden del DOM o con .prev-portada. */
  display: flex;
  gap: 8px;
  color: var(--prev-acento, var(--color-brand));
}

.prev-audio__caratula {
  /* margin 0: anula el sangrado negativo de la base .prev-portada */
  margin: 0;
  width: 96px;
  height: 96px;
  border-radius: var(--radius-md);
  overflow: hidden;
  box-shadow: var(--shadow);
}

.prev-audio__reproductor {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
}

.prev-audio__progreso {
  flex: 1;
  height: 4px;
  border-radius: 999px;
  background: rgba(17, 24, 39, 0.12);
  overflow: hidden;
}

.prev-audio__avance {
  display: block;
  width: 22%;
  height: 100%;
  border-radius: 999px;
  background: var(--prev-acento, var(--color-brand));
}

.prev-audio__tiempo {
  font-size: 10px;
  opacity: 0.7;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* Linea de empresa sobre el titular (video) y banda de cabecera (pdf). */
.prev-firma {
  margin: 0;
  font-size: 11px;
  font-weight: 600;
  opacity: 0.7;
}

.prev-banda {
  margin: 0 0 2px;
  width: 100%;
  padding: 8px 10px;
  border-radius: var(--radius);
  background: rgba(17, 24, 39, 0.05);
  font-size: 12px;
  font-weight: 700;
}

/* Enlaces como tarjeta con miniatura (patron Linktree). */
.prev-enlaces__enlace {
  display: flex;
  align-items: center;
  gap: 8px;
  text-align: left;
  background: #ffffff;
}

.prev-enlaces__mini {
  width: 24px;
  height: 24px;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 6px;
  background: var(--prev-acento, var(--color-brand));
  color: #ffffff;
  font-size: 12px;
  font-weight: 700;
}

.prev-enlaces__texto {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Galeria en carrusel: central alzada, laterales asomando. */
.prev-galeria--carrusel {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  width: 100%;
  overflow: hidden;
  padding: 6px 0;
}

.prev-galeria--carrusel .prev-galeria__foto {
  border-radius: var(--radius-md);
  overflow: hidden;
}

.prev-galeria__foto--lado {
  width: 20%;
  aspect-ratio: 3 / 4;
  flex-shrink: 0;
  opacity: 0.85;
}

.prev-galeria__foto--centro {
  width: 52%;
  aspect-ratio: 3 / 4;
  flex-shrink: 0;
  box-shadow: var(--shadow-lg);
}

.prev-galeria--carrusel .prev-galeria__foto img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Cuadro de comentario simulado (opiniones). */
.prev-comentario {
  width: 100%;
  min-height: 54px;
  padding: 10px 12px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: #ffffff;
  text-align: left;
}

.prev-comentario__marcador {
  margin: 0;
  font-size: 11px;
  color: var(--color-text-soft);
}

/* Cupon: foto promocional a sangre y muescas de troquel a media altura. */
.prev-cupon {
  position: relative;
  overflow: hidden;
}

.prev-cupon__foto {
  width: calc(100% + 24px);
  height: 72px;
  margin: -14px -12px 4px;
}

.prev-cupon__foto img {
  display: block;
  width: 100%;
  height: 72px;
  object-fit: cover;
}

/* Tarjeta solida: el borde discontinuo perimetral de v1 + la foto a
   sangre quedaba sucio. El troquel vive en la linea del codigo. */
.prev-cupon {
  border: 1px solid var(--color-border);
  box-shadow: var(--shadow);
}

.prev-cupon__etiqueta {
  position: relative;
  width: calc(100% + 24px);
  margin: 6px -12px 0;
  padding-top: 10px;
  border-top: 2px dashed var(--prev-acento, var(--color-brand));
}

.prev-cupon__etiqueta::before,
.prev-cupon__etiqueta::after {
  content: '';
  position: absolute;
  top: -9px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--prev-fondo, #f8fafc);
  border: 1px solid var(--color-border);
}

.prev-cupon__etiqueta::before { left: -8px; }
.prev-cupon__etiqueta::after { right: -8px; }

/* Wifi como dialogo del sistema. */
.prev-wifi--dialogo {
  width: 100%;
  margin-top: 14%;
  padding: 18px 14px 14px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: #ffffff;
  color: #111827;
  box-shadow: var(--shadow-lg);
}

.prev-wifi__pregunta {
  margin: 0;
  font-size: 14px;
  font-weight: 700;
  text-align: center;
  overflow-wrap: anywhere;
}

.prev-wifi__botones {
  display: flex;
  gap: 8px;
  width: 100%;
  margin-top: 4px;
}

.prev-wifi__boton {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 40px;
  text-align: center;
  padding: 8px 6px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 700;
}

.prev-wifi__boton--secundario {
  border: 1px solid var(--prev-acento, var(--color-brand));
  color: var(--prev-acento, var(--color-brand));
  background: #ffffff;
}

.prev-wifi__boton--primario {
  background: var(--prev-acento, var(--color-brand));
  color: #ffffff;
}


/* Linea de escaneo del trailer (30/07 noche): barrido vertical sobre el QR
   antes del badge, la "captura" de camara que precede al salto a la
   mini-landing. Solo se anima via .demo-escaner--activo (el JS respeta
   prefers-reduced-motion). */
.demo-escaner {
  position: absolute;
  left: 8%;
  right: 8%;
  top: 12%;
  height: 3px;
  border-radius: 999px;
  background: linear-gradient(
    90deg,
    transparent,
    var(--color-cta, #047857) 25%,
    var(--color-cta, #047857) 75%,
    transparent
  );
  box-shadow: 0 0 14px rgba(4, 120, 87, 0.5);
  opacity: 0;
  z-index: 1;
  pointer-events: none;
}

.demo-escaner--activo {
  animation: demo-escaneo 650ms ease-in-out 200ms 1 both;
}

@keyframes demo-escaneo {
  0% { top: 12%; opacity: 0; }
  12% { opacity: 1; }
  88% { opacity: 1; }
  100% { top: 86%; opacity: 0; }
}


/* =========================================================================
   PREVIEWS, TANDA 4 (31/07): fuera el blanco vacio.
   - Paneles cortos centrados en vertical (min-height 100% del area util).
   - Carta como tarjetas con filas nombre····precio (puntos de guia).
   ========================================================================= */

.prev__panel {
  min-height: 100%;
  align-content: center;
}

/* Carta rediseñada. */
.prev-carta {
  width: 100%;
  display: grid;
  gap: var(--space-2);
}

.prev-carta__grupo {
  width: 100%;
  padding: 10px 12px 12px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: #ffffff;
  color: #111827;
  text-align: left;
}

.prev-carta__seccion {
  margin: 0 0 6px;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--prev-acento, var(--color-brand));
}

.prev-carta__lista {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 5px;
}

.prev-carta__fila {
  display: flex;
  align-items: baseline;
  gap: 6px;
  font-size: 12px;
}

.prev-carta__nombre {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.prev-carta__puntos {
  flex: 1;
  min-width: 12px;
  border-bottom: 2px dotted rgba(17, 24, 39, 0.18);
  transform: translateY(-3px);
}

.prev-carta__precio {
  font-weight: 700;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.prev-carta__alergenos {
  margin: 2px 0 0;
  padding: 6px 10px;
  border-radius: 999px;
  background: rgba(17, 24, 39, 0.05);
  font-size: 10.5px;
  text-align: center;
}


/* Tarjetas de campos de las paginas de tipo (31/07): misma altura en
   ambos idiomas — la rejilla uniforma las filas. */
.campos {
  grid-auto-rows: 1fr;
}

/* =========================================================================
   DESTINOS DE ACCION DIRECTA, TANDA 5 (31/07): maquetas con contenido.
   ========================================================================= */

/* Maqueta de web (tipo URL / URL fija / multi-URL). */
.prev-web {
  width: 100%;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: #ffffff;
  color: #111827;
  overflow: hidden;
  display: grid;
  justify-items: center;
  gap: 6px;
  padding-bottom: 14px;
}

.prev-web__nav {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
}

.prev-web__logo {
  width: 18px;
  height: 18px;
  border-radius: 6px;
  background: var(--prev-acento, var(--color-brand));
}

.prev-web__menu {
  width: 26px;
  height: 5px;
  border-radius: 999px;
  background: rgba(17, 24, 39, 0.14);
}

.prev-web__menu:first-of-type { margin-left: auto; }

.prev-web__hero {
  width: 100%;
  height: 92px;
  overflow: hidden;
}

.prev-web__hero img { width: 100%; height: 100%; object-fit: cover; display: block; }

.prev-web__titulo {
  margin: 4px 0 0;
  font-size: 14px;
  font-weight: 700;
}

.prev-web__texto {
  margin: 0;
  padding: 0 14px;
  font-size: 11px;
  opacity: 0.75;
}

/* Pagina de video (YouTube). */
.prev-canal {
  width: 100%;
  /* max-width + minimos a 0: sin esto la fila nowrap (nombre + boton)
     infla la columna del panel y el video se sale del movil (visto en la
     captura de YouTube, 31/07). */
  max-width: 100%;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: #ffffff;
  color: #111827;
  font-size: 11px;
}

.prev-canal__avatar {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--prev-acento, var(--color-brand));
  color: #ffffff;
  flex-shrink: 0;
}

.prev-canal__nombre {
  flex: 1;
  min-width: 0;
  font-weight: 700;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.prev-canal__accion {
  margin-left: auto;
  padding: 4px 10px;
  border-radius: 999px;
  background: #111827;
  color: #ffffff;
  font-weight: 700;
  font-size: 10px;
  white-space: nowrap;
}

/* Tarjeta de canal / grupo (Telegram, grupo de WhatsApp). */
.prev-canalMsg {
  width: 100%;
  display: grid;
  justify-items: center;
  gap: 6px;
  padding: 18px 14px 14px;
  border-radius: var(--radius-lg);
  color: #111827;
}

.prev-canalMsg--telegram { background: #e7f3fb; }
.prev-canalMsg--whatsapp { background: #e9f8ef; }

.prev-canalMsg__avatar {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: #ffffff;
}

.prev-canalMsg--telegram .prev-canalMsg__avatar { background: #2aabee; }
.prev-canalMsg--whatsapp .prev-canalMsg__avatar { background: #25d366; }
.prev-canalMsg--messenger .prev-canalMsg__avatar { background: #0084ff; }
.prev-canalMsg--instagram .prev-canalMsg__avatar { background: #e1306c; }
.prev-canalMsg--videollamada .prev-canalMsg__avatar { background: var(--color-brand); }
.prev-canalMsg--reserva .prev-canalMsg__avatar { background: var(--color-success); }

.prev-canalMsg__nombre {
  margin: 2px 0 0;
  font-size: 15px;
  font-weight: 700;
}

.prev-canalMsg__detalle {
  margin: 0;
  font-size: 11px;
  opacity: 0.65;
}

.prev-canalMsg__boton {
  margin-top: 6px;
  padding: 7px 18px;
  border-radius: 999px;
  color: #ffffff;
  font-size: 12px;
  font-weight: 700;
}

.prev-canalMsg--telegram .prev-canalMsg__boton { background: #2aabee; }
.prev-canalMsg--whatsapp .prev-canalMsg__boton { background: #1faa55; }
.prev-canalMsg--messenger .prev-canalMsg__boton { background: #0084ff; }
.prev-canalMsg--instagram .prev-canalMsg__boton { background: #e1306c; }
.prev-canalMsg--videollamada .prev-canalMsg__boton { background: var(--color-brand); }
.prev-canalMsg--reserva .prev-canalMsg__boton { background: var(--color-success); }

.prev-canalMsg__nota {
  margin: 2px 0 0;
  font-size: 10px;
  opacity: 0.6;
}

/* Lista de musica (Spotify). */
.prev-lista-musica {
  width: 100%;
  border-radius: var(--radius-lg);
  background: #111827;
  color: #f9fafb;
  padding: 12px;
  display: grid;
  gap: 10px;
  text-align: left;
}

.prev-lista-musica__cabecera {
  display: flex;
  align-items: center;
  gap: 10px;
}

.prev-lista-musica__caratula {
  width: 52px;
  height: 52px;
  border-radius: var(--radius);
  overflow: hidden;
  flex-shrink: 0;
}

.prev-lista-musica__caratula img { width: 100%; height: 100%; object-fit: cover; display: block; }

.prev-lista-musica__datos { display: grid; gap: 2px; min-width: 0; }

.prev-lista-musica__nombre {
  font-size: 13px;
  font-weight: 700;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.prev-lista-musica__detalle { font-size: 10.5px; opacity: 0.7; }

.prev-lista-musica__play {
  margin-left: auto;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: #1ed760;
  color: #111827;
  flex-shrink: 0;
}

.prev-lista-musica__pistas {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 8px;
}

.prev-lista-musica__pista {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 10.5px;
}

.prev-lista-musica__num { opacity: 0.6; width: 10px; }

.prev-lista-musica__lineas {
  flex: 1;
  display: grid;
  gap: 3px;
}

.prev-lista-musica__lineas span {
  display: block;
  height: 5px;
  border-radius: 999px;
  background: rgba(249, 250, 251, 0.25);
}

.prev-lista-musica__lineas span:last-child { width: 55%; background: rgba(249, 250, 251, 0.14); }

.prev-lista-musica__dur { opacity: 0.6; font-variant-numeric: tabular-nums; }

/* Mapa dibujado (ubicacion). */
.prev-mapa {
  position: relative;
  width: 100%;
  height: 130px;
  border-radius: var(--radius-lg);
  background: #e8f0e5;
  overflow: hidden;
  border: 1px solid var(--color-border);
}

.prev-mapa__via {
  position: absolute;
  background: #ffffff;
}

.prev-mapa__via--h1 { left: 0; right: 0; top: 34%; height: 12px; transform: rotate(-4deg); }
.prev-mapa__via--h2 { left: 0; right: 0; top: 68%; height: 8px; transform: rotate(3deg); }
.prev-mapa__via--v1 { top: 0; bottom: 0; left: 26%; width: 9px; transform: rotate(6deg); }
.prev-mapa__via--v2 { top: 0; bottom: 0; left: 70%; width: 7px; transform: rotate(-5deg); }

.prev-mapa__pin {
  position: absolute;
  left: 50%;
  top: 42%;
  transform: translate(-50%, -60%);
  width: 34px;
  height: 34px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--prev-acento, var(--color-brand));
  color: #ffffff;
  box-shadow: var(--shadow-lg);
}

/* Icono de app de muestra (apps): cuadrado degradado como uno real. */
.prev-cabecera__avatar--app {
  border-radius: 22%;
  background: linear-gradient(135deg, var(--prev-acento, var(--color-brand)), #7c3aed);
  color: #ffffff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* Ficha del explorador CENTRADA bajo el movil en pantallas estrechas
   (peticion 31/07: en movil quedaba pegada a la izquierda). */
@media (max-width: 899px) {
  .explorador__ficha {
    /* la ficha es flex-column: align-items, no justify-items */
    align-items: center;
    text-align: center;
  }
}


/* FAQ plegada por defecto (31/07, peticion): el summary es la pregunta
   entera, con chevron que gira al abrir. data-plegado-real marca los
   acordeones INTENCIONADOS: crecer al abrirlos es su funcion (la suite
   los respeta y no los cuenta como layout shift). */
.faq__resumen {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.faq__resumen::-webkit-details-marker { display: none; }

.faq__resumen::after {
  content: '';
  width: 9px;
  height: 9px;
  flex-shrink: 0;
  border-right: 2px solid var(--color-text-soft);
  border-bottom: 2px solid var(--color-text-soft);
  transform: rotate(45deg);
  transition: transform var(--dur-micro) var(--curva);
}

.faq__item--plegable[open] > .faq__resumen::after {
  transform: rotate(225deg);
}

.faq__resumen .faq__pregunta { margin: 0; }

.faq__item--plegable[open] > .faq__resumen { margin-bottom: var(--space-2); }

/* =========================================================================
   DESTINOS, TANDA 6 (31/07): respuesta al informe de los 10 revisores.
   Monogramas, tarjetas contenedoras con identidad, pistas reales.
   ========================================================================= */

/* Tarjeta contenedora generica de destino. */
.prev-tarjeta {
  width: 100%;
  display: grid;
  justify-items: center;
  gap: 8px;
  padding: 16px 14px 14px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: #ffffff;
  color: #111827;
  box-shadow: var(--shadow);
}

.prev-tarjeta--centrada { padding-top: 20px; padding-bottom: 18px; }

/* Monogramas pequeños (canal de video, canal de mensajeria). */
.prev-canal__avatar--monograma {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.02em;
}

.prev-canalMsg__avatar--monograma {
  font-size: 20px;
  font-weight: 800;
  letter-spacing: 0.02em;
}

/* Nav de la maqueta web: monograma + marca + menu textual. */
.prev-web__logo {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: #ffffff;
  font-size: 11px;
  font-weight: 800;
}

.prev-web__marca {
  font-size: 11px;
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.prev-web__menuTxt {
  font-size: 9.5px;
  font-weight: 600;
  opacity: 0.55;
  white-space: nowrap;
}

.prev-web__menuTxt:first-of-type { margin-left: auto; }

/* Chat como pantalla de mensajeria. */
.prev-chat--tarjeta {
  width: 100%;
  display: grid;
  justify-items: center;
  gap: 10px;
  padding: 0 0 12px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: #f6f8fb;
  color: #111827;
  overflow: hidden;
}

.prev-chat--tarjeta .prev-chat__cabecera {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin: 0;
  padding: 10px 12px;
  background: #ffffff;
  border-bottom: 1px solid var(--color-border);
}

.prev-chat__contacto { font-weight: 700; font-size: 12px; }

.prev-chat__hilo {
  width: 100%;
  display: grid;
  justify-items: start;
  gap: 6px;
  padding: 4px 12px;
}

.prev-chat__fecha {
  justify-self: center;
  font-size: 9.5px;
  padding: 2px 8px;
  border-radius: 999px;
  background: rgba(17, 24, 39, 0.07);
  opacity: 0.75;
}

.prev-chat--whatsapp { background: #e9f8ef; }
.prev-chat--whatsapp .prev-chat__burbuja { background: #1faa55; }
/* 01/08, revision exhaustiva: --prev-acento no tiene valor propio en los
   tipos de accion directa (editor-preview.js lo retira, solo fija
   --prev-fondo por tipo), asi que el chip "WhatsApp" y el boton "Send"
   seguian en azul junto a una burbuja verde — el choque de color que
   señalaba el panel de revision. Con --prev-acento fijado aqui, chip y
   boton (ambos usan var(--prev-acento)) heredan el verde de la app. */
.prev-chat--whatsapp { --prev-acento: #1faa55; }

/* Correo como ventana de mensaje nuevo. */
.prev-correo {
  width: 100%;
  display: grid;
  gap: 8px;
  padding: 0 12px 12px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: #ffffff;
  color: #111827;
  text-align: left;
  overflow: hidden;
  justify-items: start;
}

.prev-correo__titulo {
  width: calc(100% + 24px);
  margin: 0 -12px 2px;
  padding: 9px 12px;
  background: #111827;
  color: #ffffff;
  font-size: 11.5px;
  font-weight: 700;
}

.prev-correo .prev-boton { justify-self: center; }

/* Nota adhesiva del tipo texto. */
.prev-notaTexto {
  position: relative;
  width: 100%;
  display: grid;
  justify-items: center;
  gap: 8px;
  padding: 26px 16px 14px;
  border-radius: 4px 4px var(--radius-md) var(--radius-md);
  background: #fef9c3;
  color: #713f12;
  box-shadow: var(--shadow-lg);
  transform: rotate(-1deg);
}

.prev-notaTexto__cinta {
  position: absolute;
  top: -8px;
  left: 50%;
  transform: translateX(-50%) rotate(2deg);
  width: 74px;
  height: 18px;
  background: rgba(17, 24, 39, 0.12);
  border-radius: 2px;
}

.prev-notaTexto__mensaje {
  margin: 0;
  font-size: 13.5px;
  font-weight: 600;
  overflow-wrap: anywhere;
}

.prev-notaTexto .prev-nota { color: inherit; opacity: 0.65; }

/* Numero grande de la tarjeta de llamada. */
.prev-llamada__numero {
  margin: 0;
  font-size: 17px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}

/* Cripto: icono con el acento. */
.prev-cripto__icono { color: var(--prev-acento, var(--color-brand)); }

/* Spotify: pistas con texto real y titulo a dos lineas. */
.prev-lista-musica__nombre {
  white-space: normal;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.prev-lista-musica__datos2 {
  flex: 1;
  min-width: 0;
  display: grid;
  gap: 1px;
}

.prev-lista-musica__cancion {
  font-size: 11px;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.prev-lista-musica__artista {
  font-size: 9.5px;
  opacity: 0.6;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}


/* =========================================================================
   DESTINOS, TANDA 7 (31/07): tercera pasada del informe.
   ========================================================================= */

/* Los paneles con foto de portada anclan ARRIBA (hero a sangre): el
   centrado vertical dejaba una banda vacia sobre la imagen. */
.prev__panel:has(> .prev-portada) {
  align-content: start;
}

/* Tarjetas de canal en blanco: el tinte de marca lo pone ya el fondo de la
   pagina (FONDOS_DIRECTOS) y el color de la tarjeta se lo comia. */
.prev-canalMsg--telegram,
.prev-canalMsg--whatsapp,
/* Lote 2 (31/07): mismo patron para los 4 tipos nuevos de enlace directo. */
.prev-canalMsg--messenger,
.prev-canalMsg--instagram,
.prev-canalMsg--videollamada,
.prev-canalMsg--reserva {
  background: #ffffff;
  border: 1px solid var(--color-border);
  box-shadow: var(--shadow);
}

/* Correo: pildoras con aire interior y sin ras de borde. */
.prev-correo .prev-email__campo {
  width: 100%;
  /* padding-inline 10→8 (01/08): "Enquiry from the poster" rozaba el
     limite del valor de "Subject" (medido: 105px de ancho, texto pidiendo
     105px justos, cualquier redondeo de subpixel ya lo recortaba). */
  padding: 7px 8px;
  gap: 5px;
  border-radius: var(--radius);
  background: rgba(17, 24, 39, 0.05);
  overflow-wrap: anywhere;
}

/* Canal de YouTube: mas sitio para el nombre. */
.prev-canal__accion {
  font-size: 9px;
  padding: 3px 8px;
}

.prev-canal__nombre { font-size: 10.5px; }

/* Reglas del multi-URL. La tarjeta y sus filas encogen (min-width 0):
   sin ello, la condicion nowrap empuja la tarjeta fuera del movil — la
   misma trampa del canal de YouTube. */
.prev-multi {
  max-width: 100%;
  min-width: 0;
  /* cinturon: nada puede asomar fuera de la tarjeta */
  overflow: hidden;
}

.prev-multi__reglas { min-width: 0; }

.prev-multi__regla {
  min-width: 0;
  max-width: 100%;
}
/* Reglas del multi-URL. */
.prev-multi__reglas {
  list-style: none;
  margin: 0;
  padding: 0;
  width: 100%;
  display: grid;
  gap: 7px;
}

.prev-multi__regla {
  display: flex;
  align-items: center;
  gap: 4px;
  /* padding-inline 10→8 (01/08), y la tarjeta que lo envuelve tambien
     recorta lo suyo (mas abajo, .prev-tarjeta.prev-multi): el destino
     ("Dinner menu", "your-site.com/es") truncaba con elipsis un texto
     que no es especialmente largo, medido 17px corto. */
  padding: 8px 8px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: #f8fafc;
  font-size: 10.5px;
}

.prev-multi__cond {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-weight: 700;
  white-space: nowrap;
  color: var(--prev-acento, var(--color-brand));
}

/* los iconos no se encogen (min-width:0 en la fila se los comia) */
.prev-multi__cond svg { flex-shrink: 0; }

.prev-multi__flecha { opacity: 0.5; }

.prev-multi__dest {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 600;
}

/* La tarjeta generica (.prev-tarjeta) reserva 14px de margen lateral para
   paneles con poco contenido (avatar, titular...); en multi-url son 3
   filas densas y ese margen es lo que mas le faltaba al destino para no
   truncar. Acotado solo a .prev-multi para no tocar el resto de tipos. */
.prev-tarjeta.prev-multi {
  padding-inline: 10px;
}


/* Carta compacta (31/07, cierre): el pliegue del viewport partia la fila
   del Tiramisu a mitad de glifo; con esto la ultima tarjeta entra. */
[data-panel="menu"] .prev-portada { height: 70px; }
[data-panel="menu"] .prev-carta { gap: 6px; }
[data-panel="menu"] .prev-carta__grupo { padding: 8px 10px 9px; }
[data-panel="menu"] .prev-cabecera__avatar { width: 48px; height: 48px; font-size: 16px; }

/* Canal de YouTube: reparto en grid (el flex encogia el nombre a 6
   caracteres con hueco libre al lado). */
.prev-canal {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
}

.prev-canal__accion { margin-left: 0; }

/* la fila del canal ocupa TODA la tarjeta y sus piezas se hacen sitio:
   en el movil del editor la tarjeta mide ~200px y el boton se comia el
   nombre (medido: columna de 46px). Avatar y boton compactos. */
.prev-canal {
  min-width: 100%;
  justify-self: stretch;
}

.prev-canal__avatar { width: 20px; height: 20px; font-size: 8.5px; }

.prev-canal .prev-canal__accion { font-size: 8.5px; padding: 2px 7px; }

.prev-canal .prev-canal__nombre { font-size: 10px; }

.prev-canal__nombre {
  justify-self: stretch;
  width: 100%;
  text-align: left;
}

.prev-canal__subs {
  font-size: 9px;
  opacity: 0.6;
  white-space: nowrap;
}

/* =========================================================================
   DESTINOS PREMIUM (31/07): avatares con LOGO de muestra real.
   El monograma queda como respaldo dinamico cuando el usuario teclea su
   nombre sin subir logo; con logo (muestra o subido), imagen con anillo
   blanco y sombra suave — el detalle de las landing premium.
   ========================================================================= */

.prev-cabecera__avatar--logo {
  position: relative;
  padding: 0;
  overflow: hidden;
  /* background-color, NO el atajo `background` (04/08/2026, Ceferin: "no
     pone el centro de la imagen, pone una esquina"). El atajo reinicia
     TODAS las propiedades de fondo, incluidas background-size y
     background-position, y esta regla va despues de
     .prev-cabecera__avatar--subido: la foto subida se pintaba a tamaño
     natural anclada arriba a la izquierda, asi que en un logo circular con
     las esquinas oscuras el avatar salia negro. Aqui solo se quiere el
     color de debajo. */
  background-color: #ffffff;
  border: 3px solid #ffffff;
  box-shadow: 0 4px 14px rgba(17, 24, 39, 0.18);
}

.prev-cabecera__avatar--logo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  border-radius: inherit;
}

/* Variante cuadrada redondeada para iconos de app. */
.prev-cabecera__avatar--logoApp {
  border-radius: 24%;
}

/* Logo pequeño para filas de canal. */
.prev-canal__avatar--logo {
  overflow: hidden;
  background: #ffffff;
  padding: 0;
}

.prev-canal__avatar--logo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Logo mediano de las tarjetas de canal (Telegram / grupo). */
.prev-canalMsg__avatar--logo {
  overflow: hidden;
  background: #ffffff;
  border: 3px solid #ffffff;
  box-shadow: 0 4px 14px rgba(17, 24, 39, 0.16);
}

.prev-canalMsg__avatar--logo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* =========================================================================
   DESTINOS PREMIUM, PASADA TRANSVERSAL (31/07): lo repetido por el panel
   de directores de arte (docs/mejoras-destinos-premium.md) hecho sistema.
   ========================================================================= */

/* 1. Avatar SOLAPADO sobre la foto hero, con anillo y sombra: el patron
   de perfil premium. Aplica donde hay portada + cabecera consecutivas. */
.prev-portada + .prev-cabecera .prev-cabecera__avatar {
  margin-top: -40px;
  position: relative;
  z-index: 1;
}

.prev-portada + .prev-cabecera .prev-cabecera__avatar--logo {
  box-shadow: 0 8px 20px rgba(17, 24, 39, 0.22);
}

/* 2. Scrim inferior en las fotos hero: el corte deja de parecer accidental. */
.prev-portada {
  position: relative;
}

.prev-portada::after {
  content: '';
  position: absolute;
  inset: 55% 0 0;
  background: linear-gradient(to bottom, transparent, rgba(17, 24, 39, 0.30));
  pointer-events: none;
}

/* 3. Filas de datos como tarjetas con chip de icono y chevron pulsable
   (vcard, empresa): fuera el gris plano. */
.prev-filas__fila {
  background: #ffffff;
  border: 1px solid rgba(17, 24, 39, 0.05);
  box-shadow: 0 2px 8px rgba(17, 24, 39, 0.06);
}

/* el dato encoge con elipsis; sin esto el chevron cortaba el email a
   ras de borde sin puntos (visto en la captura de vCard) */
.prev-filas__dato {
  flex: 1;
  min-width: 0;
}

.prev-filas__dato .prev-filas__valor {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.prev-filas__fila::after {
  content: '›';
  margin-left: auto;
  font-size: 16px;
  color: rgba(17, 24, 39, 0.25);
  flex-shrink: 0;
}

.prev-filas__icono {
  width: 32px;
  height: 32px;
  padding: 7px;
  border-radius: 10px;
  background: color-mix(in srgb, var(--prev-acento, var(--color-brand)) 10%, #ffffff);
  box-sizing: border-box;
}

/* 4. Redes y enlaces: tarjetas con sombra, no borde-wireframe; chevron. */
.prev-redes__red {
  border: 0;
  box-shadow: 0 2px 10px rgba(17, 24, 39, 0.08);
}

.prev-redes__red::after {
  content: '›';
  margin-left: auto;
  color: rgba(17, 24, 39, 0.25);
  font-size: 15px;
}

.prev-enlaces__enlace {
  border: 0;
  box-shadow: 0 2px 10px rgba(17, 24, 39, 0.09);
  border-radius: var(--radius-md);
  /* padding-inline 12→10 (01/08): el texto del enlace (.prev-enlaces__texto)
     truncaba con elipsis incluso con ejemplos moderados ("www.example.com/menu",
     medido: necesitaba 136px y solo tenia 132px). Con menos aire lateral
     entra sin recortar. */
  padding: 10px 10px;
  gap: 6px;
}

.prev-enlaces__enlace::after {
  content: '›';
  margin-left: auto;
  color: rgba(17, 24, 39, 0.25);
  font-size: 15px;
}

.prev-enlaces__mini { border-radius: 50%; }

/* 5. Play premium: circulo blanco con sombra y triangulo de acento. */
.prev-player__play {
  width: 52px;
  height: 52px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.94);
  box-shadow: 0 4px 16px rgba(17, 24, 39, 0.30);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
}

.prev-player__play::after {
  content: '';
  margin-left: 4px;
  border-left: 16px solid var(--prev-acento, var(--color-brand));
  border-top: 10px solid transparent;
  border-bottom: 10px solid transparent;
}

/* 6. Tarjetas: sombra en dos capas en vez de borde duro. */
.prev-tarjeta,
.prev-audio {
  border: 0;
  box-shadow: 0 1px 2px rgba(17, 24, 39, 0.05), 0 16px 40px rgba(17, 24, 39, 0.10);
}

/* 7. mp3: acciones en chips anclados y barra de onda. */
.prev-audio__acciones {
  gap: 6px;
}

.prev-audio__acciones svg {
  width: 30px;
  height: 30px;
  padding: 7px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--prev-acento, var(--color-brand)) 9%, #ffffff);
  box-sizing: border-box;
}

/* 8. Kicker uppercase sobre titulares (video, mp3, pdf). */
.prev-firma {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--prev-acento, var(--color-brand));
  opacity: 1;
  font-weight: 800;
}

/* 9. La miniatura del video con radio y sin canto duro. */
.prev-player--foto {
  border-radius: var(--radius-md);
  overflow: hidden;
  position: relative;
}

.prev-player--foto::after {
  content: '';
  position: absolute;
  inset: 55% 0 0;
  background: linear-gradient(to bottom, transparent, rgba(17, 24, 39, 0.35));
  pointer-events: none;
}

.prev-player--foto .prev-player__play { position: absolute; z-index: 1; }

/* 10. Cupon: logo pequeño centrado. */
.prev-cupon__logo {
  width: 44px;
  height: 44px;
  margin-top: 2px;
}

/* 11. Galeria: contador como chip sobre la foto no es viable sin JS; se
   integra como chip bajo el boton. */
.prev-nota {
  font-size: 10.5px;
}

/* =========================================================================
   DESTINOS, TANDA 8 (01/08/2026): revision exhaustiva de los 36 tipos
   (docs/revision-destinos-01-08-2026.md y docs/listado-mejoras-por-tipo-01-08-2026.md).
   Aqui van las mejoras TRANSVERSALES, reutilizables por muchos tipos a la
   vez; las mejoras propias de cada tipo van en su propia tanda mas abajo.
   ========================================================================= */

/* 1. Boton con degradado sutil + sombra de color de marca. Sustituye el
   relleno plano en los ~20 tipos que usan .prev-boton (url, sepa, telefono,
   wifi, evento, resena, ubicacion, mp3, galeria, video...). El color de
   sombra sigue al acento vivo via color-mix; sin el soporte (navegadores
   viejos) cae a rgba fija, nunca sin sombra. */
.prev-boton {
  background: linear-gradient(180deg, var(--prev-acento, var(--color-brand)), color-mix(in srgb, var(--prev-acento, var(--color-brand)) 82%, #000000));
  box-shadow: 0 6px 16px rgba(17, 24, 39, 0.22), 0 6px 16px color-mix(in srgb, var(--prev-acento, var(--color-brand)) 35%, transparent);
  border: 0;
}

.prev-boton--secundario {
  background: #ffffff;
  color: var(--prev-acento, var(--color-brand));
  border: 1.5px solid var(--prev-acento, var(--color-brand));
  box-shadow: none;
}

/* 2. Avatares de las tarjetas de canal/mensaje (telegram, whatsapp,
   messenger, instagram, videollamada, reserva): degradado propio + anillo
   blanco + sombra de color, en vez del circulo de color plano. Los 4 del
   lote 2 heredan el mismo tratamiento que telegram/whatsapp ya tenian
   documentado en las notas del panel del 31/07. */
.prev-canalMsg__avatar {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: #ffffff;
  box-shadow: 0 0 0 3px #ffffff, 0 8px 20px rgba(17, 24, 39, 0.22);
}

.prev-canalMsg--telegram .prev-canalMsg__avatar { background: linear-gradient(135deg, #38bdf8, #0284c7); box-shadow: 0 0 0 3px #ffffff, 0 8px 20px rgba(14, 165, 233, 0.32); }
.prev-canalMsg--whatsapp .prev-canalMsg__avatar { background: linear-gradient(135deg, #34d399, #059669); box-shadow: 0 0 0 3px #ffffff, 0 8px 20px rgba(16, 185, 129, 0.32); }
.prev-canalMsg--messenger .prev-canalMsg__avatar { background: linear-gradient(135deg, #a855f7, #ec4899, #f97316); box-shadow: 0 0 0 3px #ffffff, 0 8px 20px rgba(219, 39, 119, 0.28); }
.prev-canalMsg--instagram .prev-canalMsg__avatar { background: linear-gradient(135deg, #f9ce34, #ee2a7b, #6228d7); box-shadow: 0 0 0 3px #ffffff, 0 8px 20px rgba(238, 42, 123, 0.28); }
.prev-canalMsg--videollamada .prev-canalMsg__avatar { background: linear-gradient(135deg, #60a5fa, #1d4ed8); box-shadow: 0 0 0 3px #ffffff, 0 8px 20px rgba(37, 99, 235, 0.32); }
.prev-canalMsg--reserva .prev-canalMsg__avatar { background: linear-gradient(135deg, #34d399, #047857); box-shadow: 0 0 0 3px #ffffff, 0 8px 20px rgba(4, 120, 87, 0.30); }

/* Logo real (telegram/whatsapp/messenger/instagram ensenan el logo del
   negocio): el anillo y la sombra de color se mantienen, sin degradado
   detras de la foto. */
.prev-canalMsg__avatar--logo {
  box-shadow: 0 0 0 3px #ffffff, 0 8px 20px rgba(17, 24, 39, 0.22) !important;
  background: #ffffff !important;
}

/* Marca de agua muy sutil del icono propio detras de la tarjeta, para las
   tarjetas de accion directa que hoy son una tarjeta sola sobre fondo
   liso (messenger sobre todo, sin nada mas en la pantalla). */
.prev-canalMsg { position: relative; overflow: hidden; }
.prev-canalMsg::before {
  content: '';
  position: absolute;
  inset: -20% -20% auto auto;
  width: 70%;
  aspect-ratio: 1;
  opacity: 0.05;
  background: currentColor;
  -webkit-mask: var(--marca-agua-icono, none) center / contain no-repeat;
  mask: var(--marca-agua-icono, none) center / contain no-repeat;
  pointer-events: none;
}

/* 3. Cripto: glifo en circulo naranja (el color estandar del protocolo,
   hoy suelto y azul) con anillo y sombra de color. */
.prev-cripto__icono {
  width: 64px;
  height: 64px;
  padding: 14px;
  box-sizing: border-box;
  border-radius: 50%;
  background: rgba(247, 147, 26, 0.12);
  color: #f7931a;
  box-shadow: 0 0 0 3px #ffffff, 0 8px 20px rgba(247, 147, 26, 0.28);
}

/* Direccion como chip copiable (visual: el icono de copiar real depende
   de JS de portapapeles, fuera de alcance de esta pasada; el chip si). */
.prev-cripto__direccion {
  padding: 9px 14px;
  border-radius: 10px;
  background: #f8fafc;
  border: 1px solid #e2e8f0;
  color: #334155;
  font-size: 12.5px;
}

/* 4. Wifi: icono en badge circular con halo exterior, como pide el panel
   (glifo suelto sobre blanco era lo que mas restaba acabado). */
.prev-wifi__icono {
  width: 56px;
  height: 56px;
  padding: 12px;
  box-sizing: border-box;
  border-radius: 50%;
  background: #eff6ff;
  box-shadow: 0 0 0 8px rgba(37, 99, 235, 0.06);
}
/* La insignia naranja de cripto pisa el tamano compartido con wifi:
   mas especifica, va despues. */
.prev-cripto__icono.prev-wifi__icono {
  background: rgba(247, 147, 26, 0.12);
  box-shadow: 0 0 0 3px #ffffff, 0 8px 20px rgba(247, 147, 26, 0.28);
}

/* Pregunta en dos niveles: la pequeña gris arriba, el nombre de red grande
   y en negrita debajo (mismo marcado <p data-prev="ssid">, ya no hay span
   anidado). */
.prev-wifi__pregunta-chica {
  margin: 0;
  font-size: 15px;
  font-weight: 400;
  color: #64748b;
}
.prev-wifi__pregunta {
  font-size: 22px;
  font-weight: 800;
  color: #0f172a;
}

/* Seguridad como chip con candado, no linea de texto suelta. */
.prev-wifi__seguridad {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 12px;
  border-radius: 999px;
  background: #f1f5f9;
  border: 1px solid #e2e8f0;
  color: #475569;
  font-size: 11px;
}
.prev-wifi__seguridad::before {
  content: '';
  width: 11px;
  height: 11px;
  flex-shrink: 0;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cpath d='M208,80H176V56a48,48,0,0,0-96,0V80H48A16,16,0,0,0,32,96V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V96A16,16,0,0,0,208,80ZM96,56a32,32,0,0,1,64,0V80H96ZM208,208H48V96H208V208Z'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cpath d='M208,80H176V56a48,48,0,0,0-96,0V80H48A16,16,0,0,0,32,96V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V96A16,16,0,0,0,208,80ZM96,56a32,32,0,0,1,64,0V80H96ZM208,208H48V96H208V208Z'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* 5. Opiniones: un unico color de acento (rompia paleta con naranja fijo
   en estrellas + azul en el boton); ahora sigue el esquema elegido. Las
   estrellas activas siguen usando el icono relleno (estrellaLlena) desde
   el marcado; aqui solo se homogeneiza el color. */
.prev-estrellas,
.prev-categorias__estrellas {
  color: var(--prev-acento, var(--color-brand));
}
.prev-estrellas__estrella--vacia,
.prev-categorias__estrella--vacia {
  color: #cbd5e1;
  opacity: 1;
}

/* Categorias como tarjeta blanca con sombra, no pildora gris plana. */
.prev-categorias__categoria {
  background: #ffffff;
  border: 1px solid #e5e7eb;
  border-radius: 14px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
}

/* Cuadro de comentario a juego. */
.prev-comentario {
  background: #f9fafb;
  border-radius: 16px;
}

/* 6. Chat (SMS / WhatsApp): etiqueta de app como chip, cola en la
   burbuja y hora debajo; fondo con degradado sutil en vez de plano. */
.prev-chat__app {
  display: inline-block;
  padding: 2px 10px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--prev-acento, var(--color-brand)) 12%, #ffffff);
  font-weight: 700;
}

.prev-chat__burbuja {
  position: relative;
  border-radius: 18px 18px 18px 4px;
}
.prev-chat__burbuja::after {
  content: '';
  position: absolute;
  left: -6px;
  bottom: 0;
  width: 12px;
  height: 12px;
  background: var(--prev-acento, var(--color-brand));
  clip-path: polygon(100% 0, 100% 100%, 0 100%);
}
.prev-chat--whatsapp .prev-chat__burbuja::after { background: #1faa55; }

.prev-chat__hora {
  margin: -2px 0 0 4px;
  font-size: 9.5px;
  opacity: 0.55;
}

.prev-chat--tarjeta {
  background: linear-gradient(180deg, color-mix(in srgb, var(--prev-acento, var(--color-brand)) 6%, #ffffff), #ffffff 60%);
}

/* 7. Correo: campos como compositor real (etiqueta pequeña en
   mayusculas + borde inferior), no pildoras grises; direccion completa,
   sin truncar con puntos suspensivos. Cabecera vestida de app real. */
.prev-correo .prev-email__campo {
  background: transparent;
  border-bottom: 1px solid #e2e8f0;
  border-radius: 0;
  padding: 6px 2px;
}
.prev-email__etiqueta {
  text-transform: uppercase;
  font-size: 9.5px;
  letter-spacing: 0.05em;
  opacity: 0.55;
}
.prev-email__campo > span:last-child {
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
  font-size: 11.5px;
  letter-spacing: -0.01em;
}
.prev-correo__titulo {
  position: relative;
  background: linear-gradient(180deg, #1e293b, #0f172a);
}
.prev-correo__titulo::after {
  content: '';
  position: absolute;
  right: 12px;
  top: 50%;
  transform: translateY(-50%);
  width: 32px;
  height: 8px;
  background-image: radial-gradient(circle, rgba(255,255,255,.25) 3px, transparent 3.5px);
  background-size: 12px 8px;
  background-repeat: repeat-x;
}

/* 8. Texto: fisica de papel real. Cinta rotada y con textura de tela en
   vez de un rectangulo gris recto; nota con esquina doblada; fondo con
   vineta suave en vez de crema plano. */
.prev-notaTexto__cinta {
  background: rgba(255, 255, 255, 0.55);
  width: 84px;
  height: 24px;
  transform: translateX(-50%) rotate(-3deg);
  box-shadow: 0 1px 2px rgba(120, 90, 20, 0.18);
}

.prev-notaTexto {
  position: relative;
  box-shadow: 0 12px 28px rgba(120, 90, 20, 0.20), 0 2px 6px rgba(120, 90, 20, 0.12);
}
.prev-notaTexto::after {
  content: '';
  position: absolute;
  right: 0;
  bottom: 0;
  width: 22px;
  height: 22px;
  background: linear-gradient(315deg, #e9d98a, #fdf3b8);
  clip-path: polygon(100% 0, 100% 100%, 0 100%);
  box-shadow: -2px -2px 4px rgba(120, 90, 20, 0.12);
}

[data-panel="texto"] {
  background: radial-gradient(120% 80% at 50% 30%, #fdf6dd 0%, #f6ecc8 100%);
}

/* 9. Sepa: badge de confianza junto al titulo + icono bancario en vez del
   edificio generico; color propio (verde-azulado) para no compartir el
   azul de vcard/telegram. */
.prev-sepa__badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 10px;
  border-radius: 999px;
  background: rgba(13, 148, 136, 0.10);
  color: #0f766e;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.02em;
}
.prev-sepa { --prev-acento: #0d9488; }
.prev-sepa .prev-sepa__importe { color: #0d9488; }

/* 10. Multi-url: fila activa marcada con borde izquierdo de color y los
   iconos de condicion en chip circular tintado. */
.prev-multi__regla:first-child {
  border-left: 3px solid var(--prev-acento, var(--color-brand));
  background: color-mix(in srgb, var(--prev-acento, var(--color-brand)) 5%, #f8fafc);
}
.prev-multi__cond svg {
  padding: 4px;
  box-sizing: content-box;
  border-radius: 50%;
  background: color-mix(in srgb, var(--prev-acento, var(--color-brand)) 10%, #ffffff);
}

/* 11. Galeria: chip de contador superpuesto sobre la foto central (antes
   iba como texto suelto bajo el boton), profundidad real a la foto
   central y las laterales como plano trasero mas retranqueado. */
.prev-galeria--carrusel { position: relative; }
.prev-galeria__contador {
  position: absolute;
  right: 10%;
  bottom: 6px;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 10px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.55);
  backdrop-filter: blur(4px);
  color: #ffffff;
  font-size: 10.5px;
}
.prev-galeria__foto--centro {
  box-shadow: 0 20px 48px rgba(30, 58, 138, 0.20);
  outline: 3px solid #ffffff;
  outline-offset: -3px;
}
.prev-galeria__foto--lado {
  transform: scale(0.86);
  opacity: 0.6;
  filter: brightness(0.94);
}

/* 12. Youtube: play dentro de circulo con blur, chip de duracion y
   degradado inferior en el thumbnail. */
[data-panel="youtube"] .prev-player__play {
  background: rgba(15, 23, 42, 0.55);
  backdrop-filter: blur(4px);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.3);
}
[data-panel="youtube"] .prev-player__play::after {
  border-left-color: #ffffff;
}
.prev-player__duracion {
  position: absolute;
  right: 8px;
  bottom: 8px;
  z-index: 1;
  padding: 2px 6px;
  border-radius: 4px;
  background: rgba(15, 23, 42, 0.75);
  color: #ffffff;
  font-size: 10px;
}
.prev-canal__avatar--logo {
  box-shadow: 0 0 0 3px #ffffff, 0 2px 6px rgba(15, 23, 42, 0.15);
}

/* 13. Evento: ficha de fecha solapada sobre la foto (mismo patron que el
   avatar sobre portada), filas Inicio/Organiza con icono en circulo
   tintado (ya lo dan las reglas de .prev-filas__icono transversales). */
.prev-portada + .prev-evento {
  margin-top: -36px;
  position: relative;
  z-index: 1;
  border: 3px solid #ffffff;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.14);
}

/* 14. Resena de Google: tarjeta central con sombra (el vacio sin
   contenedor parecia pagina a medio terminar) + estrellas en pildora
   calida. */
[data-panel="resena"] .prev-cabecera {
  background: #ffffff;
  border-radius: 24px;
  padding: 28px 20px 22px;
  box-shadow: 0 12px 32px rgba(30, 64, 175, 0.12);
}
.prev-resena__estrellas {
  padding: 8px 16px;
  border-radius: 999px;
  background: #fff7e6;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
}

/* 15. mp3: resplandor ambiental de la portada detras de la tarjeta y
   eyebrow "EPISODIO" sobre el titulo. */
.prev-audio { position: relative; overflow: visible; }
.prev-audio::before {
  content: '';
  position: absolute;
  inset: 10% -10% auto -10%;
  height: 70%;
  background-image: var(--prev-audio-glow-img, none);
  background-size: cover;
  background-position: center;
  filter: blur(48px);
  opacity: 0.30;
  transform: scale(1.15);
  z-index: -1;
}

.prev-audio__eyebrow {
  margin: 0;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-text-soft, #6b7280);
}

/* 16. Spotify: pista 1 "sonando" en verde con ecualizador, dividers finos
   entre filas y degradado de fondo bajo la portada. */
.prev-lista-musica__pista:first-child .prev-lista-musica__cancion {
  color: #1ed760;
}
.prev-lista-musica__pista:first-child .prev-lista-musica__num {
  display: inline-flex;
  align-items: flex-end;
  gap: 1.5px;
  height: 12px;
}
.prev-lista-musica__pista:first-child .prev-lista-musica__num::before,
.prev-lista-musica__pista:first-child .prev-lista-musica__num::after {
  content: '';
  display: block;
  width: 2.5px;
  background: #1ed760;
  border-radius: 1px;
}
.prev-lista-musica__pista:first-child .prev-lista-musica__num::before { height: 60%; }
.prev-lista-musica__pista:first-child .prev-lista-musica__num::after { height: 100%; }
.prev-lista-musica__pista {
  padding: 5px 0;
  border-top: 1px solid rgba(255, 255, 255, 0.06);
}
.prev-lista-musica__pista:first-child { border-top: 0; }
.prev-lista-musica__dur { font-variant-numeric: tabular-nums; color: #94a3b8; }
.prev-lista-musica {
  background: linear-gradient(180deg, color-mix(in srgb, var(--prev-acento, #7c3aed) 22%, #111827), #111827 45%);
}
.prev-lista-musica__caratula { box-shadow: 0 8px 20px rgba(0, 0, 0, 0.45); }
.prev-lista-musica__play {
  box-shadow: 0 6px 18px rgba(30, 215, 96, 0.40), 0 0 0 6px rgba(30, 215, 96, 0.12);
  background: #1ed760;
  color: #0a0a0a;
}
.prev-lista-musica__eyebrow {
  margin: 0;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #94a3b8;
}

/* 17. Cupon: sombra mas profunda, chip de caducidad con icono de reloj,
   foto de cabecera mas alta. */
.prev-cupon {
  box-shadow: 0 20px 40px -12px rgba(0, 0, 0, 0.18);
}
.prev-cupon__foto {
  height: 96px;
}
.prev-cupon__foto img { height: 96px; }
.prev-cupon__caducidad {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 12px;
  border-radius: 999px;
  background: #f3f4f6;
  font-weight: 600;
}
.prev-cupon__codigo {
  border: 2px dashed var(--prev-acento, var(--color-brand));
  background: color-mix(in srgb, var(--prev-acento, var(--color-brand)) 6%, #ffffff);
}

/* 18. Menu: precios en verde de marca + punto junto a cada seccion. */
[data-panel="menu"] .prev-carta__precio { color: #047857; font-weight: 700; }
[data-panel="menu"] .prev-carta__seccion {
  display: flex;
  align-items: center;
  gap: 6px;
}
[data-panel="menu"] .prev-carta__seccion::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #047857;
}
[data-panel="menu"] .prev-carta__grupo {
  box-shadow: 0 2px 12px rgba(6, 78, 59, 0.08);
  border-color: rgba(6, 78, 59, 0.06);
}

/* 19. Pagina: bloque de texto+boton solapado sobre el hero, como una
   tarjeta que llena el hueco inferior (firma+titulo+parrafo+botones
   juntos: ver .prev-pagina__tarjeta en el marcado). */
.prev-pagina__tarjeta {
  width: 100%;
  display: grid;
  justify-items: center;
  gap: 8px;
  background: #ffffff;
  border-radius: 24px;
  margin-top: -20px;
  position: relative;
  z-index: 1;
  padding: 18px 16px 16px;
  box-shadow: 0 12px 32px rgba(6, 78, 59, 0.10);
}

/* 20. Mascota: franja de alerta calida (lo que vende el tipo: "si me has
   encontrado") y fondo tintado propio en vez de blanco liso. */
[data-panel="mascota"] {
  background: linear-gradient(180deg, #fff7ed, #ffffff 55%);
}
.prev-mascota__alerta {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 12px;
  border-radius: 999px;
  background: #fff1e6;
  color: #c2410c;
  font-size: 11px;
  font-weight: 700;
}

/* 21. Apps: sombra de color bajo el icono + brillo interior, boton de
   tienda a dos lineas y tarjeta contenedora blanca (consistencia con
   video). */
.prev-cabecera__avatar--app {
  box-shadow: 0 16px 40px rgba(109, 40, 217, 0.28), inset 0 1px 0 rgba(255, 255, 255, 0.25);
}
.prev-tiendas__insignia {
  justify-content: flex-start;
  gap: 10px;
}
.prev-tiendas__texto {
  display: grid;
  gap: 0;
  line-height: 1.2;
  text-align: left;
}
.prev-tiendas__eyebrow {
  font-size: 8.5px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  opacity: 0.7;
}
.prev-tiendas__nombre {
  font-size: 14px;
  font-weight: 600;
}

/* 22. url / url-fija: sombra en dos capas + borde crisp para la tarjeta
   principal, anillo al logo, scrim en la foto de cabecera. */
.prev-web {
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.06), 0 16px 40px rgba(15, 23, 42, 0.12);
}
.prev-web__logo {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--prev-acento, var(--color-brand));
  box-shadow: 0 0 0 3px #ffffff, 0 2px 6px rgba(15, 23, 42, 0.15);
}
.prev-web__hero { position: relative; overflow: hidden; }
.prev-web__hero::after {
  content: '';
  position: absolute;
  inset: 60% 0 0;
  background: linear-gradient(to bottom, transparent, rgba(255, 255, 255, 0.92));
  pointer-events: none;
}
.prev-web__nav {
  padding: 8px 10px;
  gap: 6px;
  display: flex;
  align-items: center;
  width: 100%;
  box-sizing: border-box;
}

/* 22.5. Redes sociales: icono de marca mas presente y padding vertical
   mayor (hoy el hueco a la derecha del texto hace que cada fila parezca
   vacia); no se toca el fondo del panel porque 'redes-sociales' ya tiene
   su propio bloque Aspecto (--prev-fondo elegible por el usuario). */
.prev-redes__red {
  padding: 9px 14px;
  gap: 10px;
}
.prev-redes__insignia {
  width: 28px;
  height: 28px;
}
.prev-redes { gap: 10px; }

/* 23. url-fija: chip de estado "destino editable" sobre la tarjeta, para
   diferenciarla de 'url' (comparten el mismo panel; el gancho
   data-tipo-activo lo pone editor-preview.js en <section class="editor-v2">
   con cada cambio de tipo). Oculto salvo cuando el tipo activo es
   'url-fija'. */
/* =========================================================================
   ESCANEO (06/08/2026) — panel de los tipos que abren un enlace directo.
   Sustituye a la maqueta de web inventada: representa el acto real, que es
   la cámara leyendo el código y el sistema ofreciendo abrir la dirección.
   El QR del visor lo pinta editor-preview.js copiando el lienzo REAL.
   ========================================================================= */
.prev-escaneo {
  display: grid;
  /* minmax(0,1fr) y no `auto` (06/08/2026): con `auto` la columna se
     dimensiona al contenido mas ancho, y un mensaje largo en el aviso
     desbordaba el panel hacia la derecha, fuera del movil. */
  grid-template-columns: minmax(0, 1fr);
  justify-items: center;
  gap: 10px;
  width: 100%;
}

.prev-escaneo__visor {
  position: relative;
  display: grid;
  place-items: center;
  width: 172px;
  height: 172px;
  border-radius: 14px;
  background: #0f172a;
  overflow: hidden;
}

.prev-escaneo__qr {
  position: relative;   /* delante de la pista */
  z-index: 1;
  width: 118px;
  height: 118px;
  border-radius: 6px;
  /* Transparente A PROPOSITO: mientras no hay contenido que codificar, el
     lienzo esta vacio y se ve la pista de debajo; en cuanto hay codigo, el
     dibujo trae su propio fondo y la tapa. Sin JavaScript de por medio. */
  background: transparent;
}

.prev-escaneo__pista {
  position: absolute;
  z-index: 0;
  width: 118px;
  padding: 0 10px;
  color: rgba(255, 255, 255, 0.55);
  font-size: 10.5px;
  line-height: 1.3;
  text-align: center;
}

/* Las cuatro escuadras del visor de la cámara. */
.prev-escaneo__esquina {
  position: absolute;
  width: 26px;
  height: 26px;
  border: 3px solid rgba(255, 255, 255, 0.9);
}
.prev-escaneo__esquina--as { top: 12px; left: 12px; border-right: 0; border-bottom: 0; border-radius: 8px 0 0 0; }
.prev-escaneo__esquina--ad { top: 12px; right: 12px; border-left: 0; border-bottom: 0; border-radius: 0 8px 0 0; }
.prev-escaneo__esquina--bs { bottom: 12px; left: 12px; border-right: 0; border-top: 0; border-radius: 0 0 0 8px; }
.prev-escaneo__esquina--bd { bottom: 12px; right: 12px; border-left: 0; border-top: 0; border-radius: 0 0 8px 0; }

/* La línea que barre. El ciclo entero (barrido + aviso) dura 3,6 s. */
.prev-escaneo__linea {
  position: absolute;
  left: 10px;
  right: 10px;
  height: 2px;
  border-radius: 2px;
  background: linear-gradient(90deg, transparent, #22d3ee, transparent);
  box-shadow: 0 0 10px 2px rgba(34, 211, 238, 0.65);
  animation: prev-escaneo-barrido 3.6s ease-in-out infinite;
}

@keyframes prev-escaneo-barrido {
  0%   { top: 14px;  opacity: 0; }
  8%   { opacity: 1; }
  45%  { top: 154px; opacity: 1; }
  55%  { top: 154px; opacity: 0; }
  100% { top: 14px;  opacity: 0; }
}

/* Aviso del sistema: aparece cuando el barrido termina, como en el móvil. */
.prev-escaneo__aviso {
  display: flex;
  align-items: center;
  gap: 7px;
  width: 100%;
  padding: 8px 10px;
  border-radius: 12px;
  background: #ffffff;
  box-shadow: 0 6px 18px rgba(16, 24, 40, 0.14);
  animation: prev-escaneo-aviso 3.6s ease-in-out infinite;
}

@keyframes prev-escaneo-aviso {
  0%, 42%   { opacity: 0; transform: translateY(-6px); }
  52%, 92%  { opacity: 1; transform: translateY(0); }
  100%      { opacity: 0; transform: translateY(-6px); }
}

.prev-escaneo__icono {
  display: grid;
  place-items: center;
  flex: none;
  width: 24px;
  height: 24px;
  border-radius: 7px;
  background: #eff4fe;
  color: #1543ac;
}

.prev-escaneo__url {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 11.5px;
  font-weight: 600;
  text-align: left;
  color: #111827;
}

.prev-escaneo__abrir {
  flex: none;
  padding: 3px 9px;
  border-radius: 999px;
  background: var(--prev-acento, var(--color-brand));
  color: #ffffff;
  font-size: 10px;
  font-weight: 700;
}

/* Sin verbo (tipo Texto: no hay nada que abrir) el boton desaparece del
   todo. .oculto pierde contra el display de arriba, la trampa de siempre. */
.prev-escaneo__abrir.oculto {
  display: none;
}

/* Barra de navegador fuera cuando al escanear NO se abre ninguna web: en un
   QR de wifi, de llamada o de texto no aparece ningun navegador, y dejarla
   era la misma mentira en pequeño que la maqueta de web (06/08/2026). */
.editor-v2--sin-navegador .telefono__urlbar {
  visibility: hidden;
}

.prev-escaneo__nota {
  margin: 0;
  font-size: 10.5px;
  line-height: 1.35;
  color: var(--color-text-soft);
}

/* Sin animación para quien la haya desactivado en su sistema: se enseña el
   resultado (aviso visible, línea quieta), que es lo que hay que entender. */
@media (prefers-reduced-motion: reduce) {
  .prev-escaneo__linea { animation: none; top: 84px; opacity: 1; }
  .prev-escaneo__aviso { animation: none; opacity: 1; transform: none; }
}

.prev-url__chip-estado {
  display: none;
  align-items: center;
  gap: 5px;
  padding: 4px 10px;
  border-radius: 999px;
  background: #eff6ff;
  color: #1d4ed8;
  font-size: 10.5px;
  font-weight: 600;
}
.prev-url__chip-estado::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #22c55e;
}
.editor-v2[data-tipo-activo="url-fija"] .prev-url__chip-estado {
  display: inline-flex;
}

/* =========================================================================
   DESTINOS, TANDA 9 (01/08/2026): cierre de lo que quedaba documentado
   como pendiente tras la TANDA 8 (docs/entrega.md, Hito 18).
   ========================================================================= */

/* 1. PDF: tarjeta con foto a sangre (solo redondeada arriba, el propio
   overflow:hidden de .prev-tarjeta la recorta) + monograma solapado. */
.prev-tarjeta--pdf {
  padding: 0;
  overflow: hidden;
}
.prev-tarjeta__foto {
  position: relative;
  width: 100%;
  height: 128px;
  overflow: hidden;
}
.prev-tarjeta__foto img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.prev-tarjeta__foto::after {
  content: '';
  position: absolute;
  inset: 55% 0 0;
  background: linear-gradient(to bottom, transparent, rgba(17, 24, 39, 0.35));
  pointer-events: none;
}
.prev-tarjeta__cuerpo {
  display: grid;
  justify-items: center;
  gap: 8px;
  width: 100%;
  padding: 0 14px 14px;
  box-sizing: border-box;
}
.prev-tarjeta__foto + .prev-tarjeta__cuerpo .prev-cabecera__avatar {
  margin-top: -24px;
  position: relative;
  z-index: 1;
}
.prev-cabecera__avatar--monograma {
  background: linear-gradient(135deg, #ea580c, #c2410c);
  color: #ffffff;
  font-weight: 800;
  font-size: 18px;
  box-shadow: 0 0 0 3px #ffffff, 0 4px 14px rgba(17, 24, 39, 0.18);
}
/* Badge de tipo de documento: comunica "es un archivo" de un vistazo. */
.prev-doc__badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 9px;
  border-radius: 6px;
  background: #fee2e2;
  color: #9a3412;
  font-size: 11px;
  font-weight: 700;
}

/* 2. Apps: mockup de telefono decorativo, en flujo normal al final de la
   tarjeta (no absoluto: el panel no siempre deja hueco sobrante debajo,
   y un mockup superpuesto arriesgaba tapar el enlace real — visto y
   corregido en la revision visual). Todo en CSS, sin assets nuevos. */
.prev-tarjeta__mockup {
  justify-self: center;
  margin-top: 4px;
  width: 68px;
  height: 116px;
  border-radius: 16px;
  background: #111827;
  border: 3px solid #1f2937;
  box-shadow: 0 10px 22px rgba(17, 24, 39, 0.22);
  transform: rotate(5deg);
  padding: 9px 7px;
  box-sizing: border-box;
  display: grid;
  align-content: start;
  gap: 5px;
  pointer-events: none;
}
.prev-tarjeta__mockup::before {
  /* barra de estado simulada */
  content: '';
  display: block;
  width: 30%;
  height: 4px;
  border-radius: 2px;
  background: rgba(255, 255, 255, 0.35);
  margin: 0 auto 4px;
}
.prev-tarjeta__mockup span {
  display: block;
  height: 14px;
  border-radius: 5px;
  background: color-mix(in srgb, var(--prev-acento, var(--color-brand)) 55%, #ffffff);
}
.prev-tarjeta__mockup span:nth-child(2) { background: color-mix(in srgb, var(--prev-acento, var(--color-brand)) 35%, #ffffff); width: 70%; }
.prev-tarjeta__mockup span:nth-child(3) { background: rgba(255, 255, 255, 0.14); width: 85%; }
.prev-tarjeta__mockup span:nth-child(4) { background: rgba(255, 255, 255, 0.14); width: 55%; }

/* 3. Video: degradado radial muy sutil detras de la tarjeta, sigue el
   acento elegido en vez de un color fijo (asi no choca con el esquema). */
[data-panel="video"] {
  background: radial-gradient(ellipse 70% 55% at 50% 45%, color-mix(in srgb, var(--prev-acento, var(--color-brand)) 10%, transparent), transparent 72%);
}
[data-panel="video"] .prev-tarjeta {
  width: 92%;
}

/* 4. url-fija: el path de la URL tecleada, resaltado dentro de la
   pildora del navegador (editor-preview.js construye el nodo). */
.prev-url__path {
  color: var(--prev-acento, var(--color-brand));
  font-weight: 600;
}

/* 5. Videollamada / reserva: linea opcional de fecha/hora (o del negocio
   en reserva), solo si el usuario la rellena. */
.prev-canalMsg__extra {
  margin: 0;
  padding: 4px 12px;
  border-radius: 999px;
  background: rgba(17, 24, 39, 0.05);
  font-size: 11px;
  font-weight: 600;
}
.prev-canalMsg__kicker {
  margin: 0;
  font-size: 10px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  opacity: 0.65;
}

/* 6. Messenger: boton con el degradado real de marca (azul-morado), en
   vez del azul plano generico que comparte con telegram/videollamada. */
.prev-canalMsg--messenger .prev-canalMsg__boton {
  background: linear-gradient(90deg, #00b2ff, #006aff, #a033ff);
}


/* =========================================================================
   TARJETAS DE CAMPO CON AYUDA EN ICONO (31/07): la descripcion larga dejaba
   tarjetas de alturas dispares y mucho blanco. Ahora va en un globo que no
   ocupa sitio (display:none hasta hover/foco), asi TODAS las tarjetas miden
   lo mismo. El texto sigue en el HTML: no se pierde contenido ni SEO.
   ========================================================================= */
.campo {
  position: relative;
  /* contenido centrado en vertical y hueco reservado a la derecha para el
     icono: asi las tarjetas de 1 y 2 lineas miden lo mismo sin que el texto
     quede pegado arriba dejando un hueco muerto debajo. */
  display: grid;
  align-content: center;
  padding: var(--space-3) calc(var(--space-4) + 26px) var(--space-3) var(--space-4);
}

.campo__nombre {
  margin-bottom: 0;
}

.campo__info {
  position: absolute;
  top: 50%;
  right: var(--space-3);
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--color-surface-alt);
  color: var(--color-text-muted);
  cursor: help;
  flex-shrink: 0;
  transition: background var(--dur-micro) var(--curva), color var(--dur-micro) var(--curva);
}

.campo__info:hover,
.campo__info:focus-visible {
  background: var(--color-brand-light);
  color: var(--color-brand-dark);
}

.campo__globo {
  display: none;
  position: absolute;
  /* el boton es el bloque contenedor: se ancla a su derecha y crece hacia
     la izquierda, asi nunca se sale por el borde derecho de la pagina. */
  right: 0;
  top: calc(100% + 6px);
  width: 240px;
  max-width: 62vw;
  z-index: 5;
  padding: 10px 12px;
  border-radius: var(--radius-md);
  background: #111827;
  color: #f9fafb;
  font-size: var(--size-xs);
  font-weight: 400;
  line-height: 1.45;
  text-align: left;
  box-shadow: var(--shadow-lg);
}

.campo__info:hover .campo__globo,
.campo__info:focus .campo__globo {
  display: block;
}

/* Aire antes del parrafo de dudas comunes de las paginas de tipo (31/07):
   iba pegado a la ultima tarjeta de FAQ. */
.faq-comunes {
  margin-top: var(--space-5);
}

/* Pago SEPA (31/07): importe protagonista sobre las filas de datos. */
.prev-sepa__importe {
  margin: 0;
  font-size: 26px;
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--prev-acento, var(--color-brand));
}

.prev-sepa .prev-filas {
  width: 100%;
}

/* =========================================================================
   MINI-WEB REAL: tipo 'pagina' (31/07). Chips de navegacion decorativos +
   secciones con separador, reusando el resto de patrones del preview.
   ========================================================================= */

.prev-nav-mini {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 6px;
  width: 100%;
  margin-bottom: 4px;
}

.prev-nav-mini__chip {
  padding: 4px 10px;
  border-radius: 999px;
  background: rgba(17, 24, 39, 0.06);
  color: var(--prev-contenido, #111827);
  font-size: 10px;
  font-weight: 600;
  opacity: 0.75;
}

.prev-nav-mini__chip--activo {
  background: var(--prev-acento, var(--color-brand));
  color: #ffffff;
  opacity: 1;
}

.prev-botones {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
}

.prev-boton--secundario {
  background: transparent;
  border: 1px solid var(--prev-acento, var(--color-brand));
  color: var(--prev-acento, var(--color-brand));
}

.prev-seccion {
  width: 100%;
  padding-top: var(--space-4);
  margin-top: var(--space-2);
  border-top: 1px solid rgba(17, 24, 39, 0.08);
  display: grid;
  justify-items: center;
  gap: 8px;
}

.prev-seccion__titulo {
  margin: 0;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--prev-acento, var(--color-brand));
}

.prev-faq {
  width: 100%;
  display: grid;
  gap: 3px;
  text-align: left;
}

.prev-faq__pregunta {
  margin: 8px 0 0;
  font-size: 12px;
  font-weight: 700;
}

.prev-faq__pregunta:first-child { margin-top: 0; }

.prev-faq__respuesta {
  margin: 0;
  font-size: 11.5px;
  opacity: 0.75;
  line-height: 1.4;
}

.prev-redes__insignia--whatsapp { background: #25d366; }

/* =========================================================================
   MASCOTA "QR CREATOR" (31/07): personaje de marca, con un QR real (siempre
   el mismo, enlaza a la web) compuesto en la barriga por
   scripts/componer-mascota.mjs — nunca dibujado por la IA.
   ========================================================================= */

/* Hero (31/07, revision): la mascota va compuesta directamente dentro de
   hero-fondo-v3.jpg, apoyada de verdad en el cartel de madera (una
   superposicion aproximada por CSS no llegaba a tocarlo, visto por el
   cliente). Regla `.compo-v3__mascota` retirada.

   El QR de su barriga TAMBIEN va horneado en el mismo JPEG (31/07, otra
   revision — el cliente insistio en que fuera una sola imagen, sin capas
   sueltas por CSS). El primer intento de bakearlo fallaba con jsQR porque
   se generaba grande y se REESCALABA hacia abajo a un tamano que no era
   multiplo limpio del numero de modulos (nearestNeighbor rompia el
   patron); generado directo a su tamano natural (cada modulo un numero
   entero de pixeles, sin resize posterior) sobrevive la compresion JPEG
   sin problema — probado con jsQR sobre el archivo ya guardado. Sin capa
   CSS: `.portada-hero__qr-barriga` retirada. */

/* 3 pasos: esquina opuesta al numero (que va bottom-right, ver
   .pulido-paso .step__number) — asoma por la izquierda del circulo, sin
   tocarlo. La vineta no recorta (solo .pulido-paso__media lo hace), asi
   que puede salirse del circulo sin problema. */
.pulido-paso__mascota {
  position: absolute;
  left: -42px;
  bottom: 4px;
  width: 78px;
  height: auto;
  pointer-events: none;
}

/* Paso 1 (31/07): la pose original senala hacia SU izquierda, que puesta a
   la izquierda del circulo apuntaba hacia fuera en vez de al contenido.
   Espejo horizontal: mismo hueco, apunta hacia el circulo. */
.pulido-paso__mascota--volteada {
  transform: scaleX(-1);
}

/* =========================================================================
   ANALISIS DE CAMPOS (31/07/2026) — listas dinamicas del editor, 2o turno
   de horario, y las piezas nuevas de vista previa que trajo (aviso de
   vacaciones, aforo/precio, insignia de un solo uso, moneda cripto, usuario
   EAP del wifi, leyenda de galeria, insignias de la carta). BEM, sin
   estilos en linea, mismos tokens que el resto del fichero.
   ========================================================================= */

/* ── Listas dinamicas: enlaces, FAQ, reglas de idioma ──────────────────── */

.lista-dinamica {
  border: 0;
  padding: 0;
  margin: 0;
  min-inline-size: 0;
}

.lista-dinamica__filas {
  display: grid;
  gap: var(--space-2);
}

.lista-dinamica__fila {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: start;
  gap: var(--space-2);
}

.lista-dinamica template {
  display: none;
}

.lista-dinamica__quitar {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  flex: none;
  margin-top: 0;
  padding: 0;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius);
  background: var(--color-bg);
  color: var(--color-text-soft);
  cursor: pointer;
}
.lista-dinamica__quitar:hover:not(:disabled) {
  background: var(--color-danger-bg);
  color: var(--color-danger);
  border-color: var(--color-danger);
}
.lista-dinamica__quitar:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.lista-dinamica__anadir {
  display: flex;
  width: fit-content;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-2);
  padding: var(--space-2) var(--space-4);
  min-height: 36px;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius);
  background: var(--color-bg);
  color: var(--color-brand);
  font-family: inherit;
  font-size: var(--size-sm);
  font-weight: 600;
  cursor: pointer;
}
.lista-dinamica__anadir:hover {
  background: var(--color-brand-light);
  color: var(--color-brand-dark);
}

/* Enlaces: etiqueta + URL lado a lado, boton de quitar a la derecha. */
.lista-enlaces__fila {
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr) auto;
}
@media (max-width: 480px) {
  .lista-enlaces__fila {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: 'etiqueta quitar' 'url quitar';
  }
}

/* FAQ: pregunta + respuesta apiladas, boton de quitar a la derecha de las
   dos. */
.lista-faq__campos {
  display: grid;
  gap: var(--space-2);
  min-width: 0;
}

/* Reglas de idioma (Multi-URL): selector + URL lado a lado. */
.lista-idioma__fila {
  grid-template-columns: minmax(0, 9rem) minmax(0, 1fr) auto;
}
@media (max-width: 480px) {
  .lista-idioma__fila {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: 'idioma quitar' 'url quitar';
  }
}

/* ── Horario: 2o turno opcional (mañana/tarde) ─────────────────────────── */

.horario__turno2-activar {
  display: inline-flex;
  align-items: center;
  font-size: var(--size-xs);
  color: var(--color-brand);
  cursor: pointer;
  white-space: nowrap;
}
.horario__turno2-activar:hover {
  color: var(--color-brand-dark);
  text-decoration: underline;
}

.horario__turno2 {
  display: none;
  align-items: center;
  gap: var(--space-2);
}

/* La casilla vive oculta (accesible, no visual): su unico trabajo es
   ensenar u ocultar las horas del segundo turno. */
.horario__turno2-check:checked ~ .horario__turno2-activar {
  color: var(--color-text-soft);
  text-decoration: line-through;
}
.horario__turno2-check:checked ~ .horario__turno2 {
  display: flex;
}
.horario__turno2-check:focus-visible ~ .horario__turno2-activar {
  outline: 3px solid var(--color-focus);
  outline-offset: 2px;
  border-radius: var(--radius);
}

@media (max-width: 420px) {
  .horario__turno2-activar,
  .horario__turno2 {
    grid-column: 1 / -1;
  }
}

/* ── Vista previa: aviso de vacaciones (empresa, pagina) ───────────────── */

.prev-aviso {
  margin: 0;
  padding: 6px 10px;
  border-radius: var(--radius);
  background: var(--color-warning-bg);
  color: var(--color-warning);
  font-size: 11px;
  font-weight: 600;
  text-align: left;
}

/* ── Vista previa: aforo/precio del evento ─────────────────────────────── */

.prev-insignia {
  margin: 0;
  padding: 2px 10px;
  border-radius: 999px;
  background: rgba(17, 24, 39, 0.06);
  color: var(--prev-contenido, var(--color-text));
  font-size: 10px;
  font-weight: 700;
  width: fit-content;
}

/* ── Vista previa: cupon de un solo uso ────────────────────────────────── */

.prev-cupon__uso-unico {
  margin: 0;
  padding: 2px 10px;
  border-radius: 999px;
  border: 1px solid var(--color-border-strong);
  color: var(--color-text-muted);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  width: fit-content;
}

/* ── Vista previa: FAQ (ahora en filas dinamicas) ──────────────────────── */

.prev-faq__par {
  display: grid;
  gap: 3px;
}
.prev-faq__par + .prev-faq__par {
  margin-top: 8px;
}
.prev-faq__par .prev-faq__pregunta {
  margin-top: 0;
}

/* ── Vista previa: reglas de idioma de Multi-URL dinamicas ─────────────── */
/* Reutiliza .prev-multi__regla / __cond / __dest ya existentes: sin CSS
   nuevo, solo se generan mas filas desde el mismo patron. */

/* ── Vista previa: moneda cripto elegida ───────────────────────────────── */

.prev-cripto__moneda {
  margin: 0;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-text-soft);
}

/* ── Vista previa: usuario EAP del wifi ─────────────────────────────────── */

.prev-wifi__usuario {
  margin: 4px 0 0;
  font-size: 10px;
  color: var(--color-text-soft);
}

/* ── Vista previa: leyenda de la galeria ───────────────────────────────── */

.prev-galeria__leyenda {
  margin: 6px 0 0;
  font-size: 10.5px;
  font-style: italic;
  color: var(--color-text-soft);
  text-align: center;
}

/* ── Vista previa: insignias de la carta (#vegano, #sinGluten...) ──────── */

.prev-carta__badges {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-inline-start: 4px;
}

.prev-carta__badge {
  padding: 1px 6px;
  border-radius: 999px;
  background: var(--color-success-bg);
  color: var(--color-success);
  font-size: 8px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  white-space: nowrap;
}

/* =========================================================================
   35. MODAL DE ERROR DE CAMPO (03/08/2026)
   Que esta mal, por que y como arreglarlo -- SOLO para datos que la
   persona tiene que corregir ella misma (un enlace que no es del dominio
   esperado, un IBAN mal escrito...). Nunca para lo que el editor ya
   arregla solo (GTM, contraste/forma del QR): eso no lleva modal, se
   corrige sin interrumpir a nadie. Ver editor.js, abrirModalError().
   ========================================================================= */

.modal-error {
  max-width: 420px;
  width: calc(100vw - var(--space-6));
  margin: auto; /* <dialog> se centra solo con esto una vez abierto */
  padding: var(--space-5);
  border: none;
  border-radius: var(--radius-lg);
  background: var(--color-bg);
  box-shadow: 0 20px 40px -8px rgba(17, 24, 39, 0.25);
}

.modal-error::backdrop {
  background: rgba(17, 24, 39, 0.5);
}

.modal-error__cabecera {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  margin-bottom: var(--space-3);
}

.modal-error__icono {
  flex: 0 0 24px;
  width: 24px;
  height: 24px;
  color: var(--color-danger);
  margin-top: 2px;
}

.modal-error__titulo {
  flex: 1 1 auto;
  margin: 0;
  font-size: var(--size-lg);
  font-weight: 700;
  line-height: 1.35;
  color: var(--color-text);
}

.modal-error__cerrar {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--color-text-soft);
  cursor: pointer;
}
.modal-error__cerrar:hover {
  background: var(--color-surface);
  color: var(--color-text);
}

.modal-error__como {
  margin: 0 0 var(--space-5);
  color: var(--color-text-muted);
  font-size: var(--size-sm);
  line-height: 1.6;
}

.modal-error__pie {
  display: flex;
  justify-content: flex-end;
}

@keyframes modal-error-entrada {
  from {
    opacity: 0;
    transform: translateY(8px) scale(0.98);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.modal-error[open] {
  animation: modal-error-entrada 0.18s ease-out;
}

@media (prefers-reduced-motion: reduce) {
  .modal-error[open] {
    animation: none;
  }
}

/* ═══════════════════════════════════════════════════════════════════════
   ADMIN — panel de administracion (backoffice), 04/08/2026
   No es parte del embudo publico: pantalla interna para gestionar QR y ver
   analitica con el token de servicio. Reutiliza .field__*, .button y .oculto
   ya definidos arriba; aqui solo lo que es exclusivo de esta pantalla.
   ═══════════════════════════════════════════════════════════════════════ */

.admin { background: var(--color-surface); color: var(--color-text); min-height: 100vh; }

.admin-acceso {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-6) var(--space-4);
}
/* Misma razon que ".admin-lateral.oculto" mas abajo: ".admin-acceso" define
   su propio "display" y gana por orden de cascada sobre ".oculto" si no se
   sube la especificidad aqui. Encontrado con Playwright: tras iniciar
   sesion, la pantalla de acceso se quedaba apilada encima del panel. */
.admin-acceso.oculto {
  display: none;
}
.admin-acceso__caja { width: 100%; max-width: 24rem; }
.admin-acceso__titulo { font-size: var(--size-xl); font-weight: 700; margin: 0 0 var(--space-2); }
.admin-acceso__texto { color: var(--color-text-soft); font-size: var(--size-sm); margin: 0 0 var(--space-4); }
.admin-acceso__error { color: var(--color-danger); font-size: var(--size-sm); margin-top: var(--space-3); }
#admin-form-token .field__control { margin-bottom: var(--space-3); }

.admin-cabecera {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-5);
  background: var(--color-bg);
  border-bottom: 1px solid var(--color-border);
  position: sticky;
  top: 0;
  z-index: 10;
}
.admin-cabecera__marca { font-weight: 700; margin: 0; }
.admin-cabecera__estado { flex: 1; font-size: var(--size-sm); color: var(--color-text-soft); }

.admin-contenido { max-width: 72rem; margin: 0 auto; padding: var(--space-5); }

.admin-barra {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  align-items: center;
  margin-bottom: var(--space-4);
}
.admin-buscador { min-width: 12rem; flex: 1; }
.admin-filtro { width: auto; }

.admin-tabla-envoltorio { overflow-x: auto; border: 1px solid var(--color-border); border-radius: var(--radius); }
.admin-tabla { width: 100%; border-collapse: collapse; font-size: var(--size-sm); background: var(--color-bg); }
.admin-tabla th,
.admin-tabla td { padding: var(--space-3) var(--space-4); text-align: left; border-bottom: 1px solid var(--color-border); white-space: nowrap; }
.admin-tabla th { color: var(--color-text-soft); font-weight: 600; font-size: var(--size-xs); text-transform: uppercase; letter-spacing: 0.03em; }
.admin-tabla tbody tr:last-child td { border-bottom: none; }
.admin-tabla tbody tr:hover { background: var(--color-surface-alt); }
.admin-vacio { color: var(--color-text-soft); text-align: center; padding: var(--space-6) !important; white-space: normal !important; }

.admin-estado-chip { display: inline-flex; align-items: center; gap: var(--space-1); padding: 0.15rem var(--space-2); border-radius: 999px; font-size: var(--size-xs); font-weight: 600; }
.admin-estado-chip--activo { background: var(--color-success-bg); color: var(--color-success); }
.admin-estado-chip--inactivo { background: var(--color-surface-alt); color: var(--color-text-soft); }
.admin-estado-chip--caducado,
.admin-estado-chip--agotado { background: var(--color-warning-bg); color: var(--color-warning); }

.admin-tabla a { color: var(--color-brand); }
.admin-accion-borrar { color: var(--color-danger); background: none; border: none; cursor: pointer; font-size: var(--size-sm); padding: var(--space-1) var(--space-2); }
.admin-accion-borrar:hover { text-decoration: underline; }

.admin-paginacion { display: flex; align-items: center; justify-content: center; gap: var(--space-4); margin-top: var(--space-4); font-size: var(--size-sm); color: var(--color-text-soft); }

/* Panel lateral (drawer) compartido por editor y analitica. */
.admin-lateral {
  position: fixed;
  inset: 0;
  z-index: 50;
  background: rgba(17, 24, 39, 0.4);
  display: flex;
  justify-content: flex-end;
}
/* Mayor especificidad que ".oculto" a proposito: sin esto, ".admin-lateral"
   (misma especificidad, declarado despues en la hoja) gana por orden de
   cascada y el panel se queda visible -- con position:fixed e inset:0 --
   e intercepta clics en el resto de la pagina aunque lleve "oculto".
   Encontrado con Playwright: el boton "Sign in" quedaba bloqueado. */
.admin-lateral.oculto {
  display: none;
}
.admin-lateral__caja {
  width: 100%;
  max-width: 28rem;
  height: 100%;
  background: var(--color-bg);
  padding: var(--space-5);
  overflow-y: auto;
  box-shadow: -4px 0 16px rgba(16, 24, 40, 0.12);
}
.admin-lateral__cabecera { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--space-4); }
.admin-lateral__titulo { font-size: var(--size-lg); font-weight: 700; margin: 0; }
.admin-cerrar { background: none; border: none; font-size: 1.5rem; line-height: 1; cursor: pointer; color: var(--color-text-soft); padding: var(--space-1) var(--space-2); }
.admin-lateral__acciones { display: flex; gap: var(--space-3); margin-top: var(--space-5); }

.admin-oculto-tipo.oculto,
.admin-campo-tipo.oculto { display: none; }

.admin-json { font-family: var(--font-mono); font-size: var(--size-xs); line-height: 1.5; }
.admin-ayuda { font-size: var(--size-xs); color: var(--color-text-soft); margin: 0 0 var(--space-2); }
.admin-error { color: var(--color-danger); font-size: var(--size-sm); margin-top: var(--space-2); }

.admin-avanzado { margin: var(--space-4) 0; border: 1px solid var(--color-border); border-radius: var(--radius); padding: var(--space-3) var(--space-4); }
.admin-avanzado summary { cursor: pointer; font-weight: 600; font-size: var(--size-sm); }
.admin-avanzado .field { margin-top: var(--space-3); }

/* Analitica: totales, listas por dimension y un mini grafico de barras en
   CSS puro (sin libreria: 30 barras como mucho, un div por dia). */
.admin-analitica-totales { display: flex; gap: var(--space-5); margin-bottom: var(--space-5); }
.admin-analitica-total { flex: 1; }
.admin-analitica-total__numero { font-size: var(--size-2xl); font-weight: 700; display: block; }
.admin-analitica-total__etiqueta { font-size: var(--size-xs); color: var(--color-text-soft); }

.admin-grafico { display: flex; align-items: flex-end; gap: 2px; height: 6rem; margin-bottom: var(--space-5); }
.admin-grafico__barra { flex: 1; background: var(--color-brand-light); border-radius: 2px 2px 0 0; min-height: 2px; position: relative; }
.admin-grafico__barra--con-datos { background: var(--color-brand); }

.admin-analitica-seccion { margin-bottom: var(--space-4); }
.admin-analitica-seccion__titulo { font-size: var(--size-xs); text-transform: uppercase; letter-spacing: 0.03em; color: var(--color-text-soft); margin: 0 0 var(--space-2); }
.admin-analitica-fila { display: flex; justify-content: space-between; font-size: var(--size-sm); padding: var(--space-1) 0; border-bottom: 1px solid var(--color-border); }
.admin-analitica-fila:last-child { border-bottom: none; }

@media (max-width: 640px) {
  .admin-lateral__caja { max-width: 100%; }
  .admin-contenido { padding: var(--space-4) var(--space-3); }
}

/* ═══════════════════════════════════════════════════════════════════════
   CUENTA — dashboard de cliente final (/account/), 04/08/2026
   Reutiliza el sistema .admin-* de arriba (misma tabla, mismo drawer
   lateral, mismos formularios): es el mismo lenguaje de panel interno,
   solo cambia quien entra y con que alcance de datos. Aqui solo lo
   exclusivo de esta pantalla: pestanas login/registro y nav de secciones.
   ═══════════════════════════════════════════════════════════════════════ */

.cuenta-pestanas { display: flex; gap: var(--space-2); margin-bottom: var(--space-4); border-bottom: 1px solid var(--color-border); }
.cuenta-pestana {
  background: none; border: none; cursor: pointer;
  padding: var(--space-2) var(--space-3);
  font-family: inherit; font-size: var(--size-sm); font-weight: 600;
  color: var(--color-text-soft);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.cuenta-pestana--activa { color: var(--color-brand); border-bottom-color: var(--color-brand); }

.cuenta-nav { display: flex; gap: var(--space-1); flex-wrap: wrap; }
.cuenta-nav__link {
  background: none; border: none; cursor: pointer;
  padding: var(--space-2) var(--space-3);
  font-family: inherit; font-size: var(--size-sm); font-weight: 600;
  color: var(--color-text-soft); border-radius: var(--radius);
}
.cuenta-nav__link:hover { background: var(--color-surface-alt); }
.cuenta-nav__link--activo { color: var(--color-brand); background: var(--color-brand-light); }

.cuenta-seccion__titulo { font-size: var(--size-lg); font-weight: 700; margin: 0 0 var(--space-4); }

.cuenta-datos { display: grid; grid-template-columns: auto 1fr; gap: var(--space-2) var(--space-4); max-width: 28rem; }
.cuenta-datos dt { color: var(--color-text-soft); font-size: var(--size-sm); }
.cuenta-datos dd { margin: 0; font-size: var(--size-sm); }
