/* ==========================================================================
   GUIA MOLINS DE REI — SISTEMA DE DISEÑO «LA PLAÇA» (rework #47, 07/10)
   Mobile-First | AA medido en los dos temas | 0 CDN, 0 fuentes externas
   Doctrina: CSP estricta (nada inline) · system-ui · papel cálido + blau + terra
   ========================================================================== */

/* 1. DESIGN TOKENS (:root)
   Ratios de contraste CALCULADOS con script (07/10), no estimados.
   -------------------------------------------------------------------------- */
:root {
  /* Superficies: papel cálido (identidad propia, no slate genérico) */
  --color-bg-base: #f6f3ee;
  --color-bg-card: #ffffff;
  --color-bg-sunken: #efeae2;
  --color-border: #e5dfd4;
  --color-border-strong: #d6cfc1;

  /* Tinta */
  --color-text-primary: #1f2733; /* 13.6:1 papel · 15:1 tarjeta */
  --color-text-secondary: #49536b; /* 6.9:1 papel · 7.7:1 tarjeta */
  --color-text-muted: #5d6676; /* 5.2:1 papel · 5.8:1 tarjeta */

  /* Blau mediterrani (marca e interacción) */
  --color-brand-primary: #0369a1; /* blanco encima: 5.9:1 */
  --color-brand-hover: #075985; /* blanco encima: 7.6:1 */
  --color-brand-text: #075985; /* 6.8:1 papel · 7.6:1 tarjeta */
  --color-brand-wash: #e0f1fb;
  --color-focus-ring: rgba(3, 105, 161, 0.35); /* halo blando (box-shadow) */
  /* El ANILLO de foco va opaco: con alfa se quedaba en 1,68:1 sobre el
     papel y WCAG 1.4.11 pide 3:1. Opaco mide 5,36:1. */
  --color-focus-outline: #0369a1;

  /* Terra (acento cálido: col·laboradors, destacats, ofertes) */
  --color-terra-text: #a03d14; /* 6:1 sobre papel */
  --color-terra-strong: #8a3410; /* 7:1 sobre su lavado */
  --color-terra-wash: #fbeadf;
  --color-terra-border: #efcdb4;

  /* Contacto (el blanco sobre #25d366 daba 1.98:1 — medido y corregido) */
  --color-whatsapp-bg: #2bd97b;
  --color-whatsapp-text: #073c26; /* 6.7:1 */
  --color-whatsapp-hover: #22c56d;
  --color-call-bg: #185abc;
  --color-call-text: #ffffff; /* 6.5:1 */
  --color-call-hover: #1450a8;
  --color-website-btn: #3c475c;
  --color-website-btn-hover: #2c3547;

  /* Badges y estados */
  --color-badge-bg: #e0f1fb;
  --color-badge-text: #075985; /* 6.5:1 sobre su lavado */
  --color-candelera-text: #9a3412; /* 6.3:1 */
  --color-candelera-bg: rgba(234, 88, 12, 0.12);
  --color-candelera-border: rgba(234, 88, 12, 0.35);
  --color-closed-text: #92400e; /* 6.3:1 */
  --color-closed-bg: rgba(245, 158, 11, 0.15);
  --color-closed-border: rgba(217, 119, 6, 0.4);
  /* El sello «Negoci verificat» (M4, 119ª) es este verde sobre su lavado:
     6,33:1 en la tarjeta · 5,61:1 en el peor punto del lavado de .claim-card */
  --color-ok-text: #166534;
  --color-ok-bg: rgba(34, 197, 94, 0.14);
  --color-ok-border: rgba(34, 197, 94, 0.35);
  --color-error-text: #b91c1c;
  --color-error-bg: rgba(239, 68, 68, 0.12);
  --color-error-border: rgba(239, 68, 68, 0.3);
  --color-featured-text: #92550a; /* 6:1 sobre tarjeta · 5.6:1 sobre su lavado */
  --color-featured-border: rgba(245, 158, 11, 0.55);
  /* El Amic EN COLOR (85ª): ámbar al 8 % sobre la tarjeta, ya mezclado.
     Medido: título 14.1:1 · dirección 7.2:1 · categoría 5.4:1 */
  --color-featured-wash: #fef7eb;
  /* El Col·laborador RELLENO (89ª): la misma familia ámbar, más peso. El
     chip lleva el ámbar oscuro de fondo y texto blanco; el mismo ámbar hace
     de marco de la tarjeta. Medido: texto 6:1 · marco 5.6:1 sobre el lavado */
  --color-collab: #92550a;
  --color-collab-on: #ffffff;

  /* Dirección (enlace a Maps), con variante por tema */
  --color-address-link: #49536b; /* 7.7:1 */
  --color-address-link-hover: #075985;

  /* Vista previa del perfil ForgeBio (ficha): el verde de ForgeBio en los
     dos temas; el claro copia sus perfiles claros (botón blanco + borde) */
  --fb-accent: #16a34a; /* iconos: 3.3:1 sobre blanco (gráfico, ≥3) */
  --fb-accent-text: #15803d; /* 5:1 sobre tarjeta */
  --fb-ring: #22c55e;
  --fb-glow: rgba(34, 197, 94, 0.45);
  --fb-line: rgba(22, 163, 74, 0.38);
  --fb-wash: #ecfdf3;
  --fb-phone-bg: #fafafa;
  --fb-phone-border: #e3e6ea;
  --fb-phone-text: #1f2733;
  --fb-phone-meta: #5d6676; /* 5.5:1 sobre el móvil */
  --fb-phone-btn: #ffffff;
  --fb-cta-bg: #22c55e;
  --fb-cta-text: #052e16; /* 6.5:1 */
  --fb-cta-hover: #4ade80; /* 8.5:1 */
  --fb-btn-line: rgba(22, 163, 74, 0.38);
  --fb-bolt: #f59e0b;
  /* El avatar es un círculo BLANCO en los dos temas (como en ForgeBio) */
  --fb-avatar-bg: #ffffff;
  --fb-avatar-text: #1f2733;

  /* Color por categoría MADRE (24e, 178ª; «un color sutil por categoria y
     así cuando hacen scroll las que son de restauració se identifican con
     el color sin necesidad de leerlo en texto»). Lo llevan el disco de la
     tarjeta (la tinta del disco encima) y el icono y el borde de su chip.
     Son gráfico, no texto: ≥ 3:1 medido en tests/salidaEstetica.test.js
     (disco: tinta sobre color · chip: color sobre la tarjeta). El fondo de
     la tarjeta NO lo tocan: el pago manda (Amic lavado, Col·laborador marco). */
  --cat-restauracion: #b42318; /* vermell */
  --cat-comercio: #6941c6; /* pruna */
  --cat-servicios: #0369a1; /* el blau de marca */
  --cat-salud: #1a7f4b; /* verd */
  --cat-vida-local: #64748b; /* pedra */
  --cat-badge-ink: #ffffff;

  /* El pont (24e): la tinta de la arcada, apagada como un borde */
  --arcade-ink: #cdc4b4;

  /* Lavado del héroe: dos manchas suaves (cel + sorra) sobre el papel */
  --hero-wash:
    radial-gradient(42rem 20rem at 8% -4rem, rgba(14, 116, 180, 0.14), transparent 60%),
    radial-gradient(36rem 18rem at 98% 0, rgba(214, 112, 49, 0.12), transparent 55%);

  /* Controles nativos acordes al tema del SO */
  color-scheme: light dark;

  /* Sombras con tinta azulada (no negro puro) */
  --shadow-sm: 0 1px 2px rgba(31, 39, 51, 0.06), 0 1px 6px rgba(31, 39, 51, 0.05);
  --shadow-md: 0 10px 28px -8px rgba(31, 39, 51, 0.16), 0 4px 10px -4px rgba(31, 39, 51, 0.08);
  --shadow-lift: 0 14px 30px -10px rgba(7, 89, 133, 0.22);

  /* Tipografía fluida (system: 0 fuentes externas, doctrina del proyecto) */
  --font-family:
    system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --font-size-base: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
  --font-size-sm: clamp(0.875rem, 0.83rem + 0.2vw, 1rem);
  --font-size-xs: 0.8125rem;
  --font-size-lg: clamp(1.25rem, 1.15rem + 0.5vw, 1.5rem);
  --font-size-xl: clamp(1.75rem, 1.5rem + 1vw, 2.25rem);
  --font-size-hero: clamp(2rem, 1.55rem + 2.2vw, 3.1rem);
  --line-height-base: 1.6;

  /* Geometría */
  --radius-sm: 0.5rem;
  --radius-md: 0.75rem;
  --radius-lg: 1.125rem;
  --radius-xl: 1.5rem;
  /* El ancho de la columna: lo usan el contenedor y la caja «Buscar» fijada
     (#62), que se alinea con él aunque viva fuera */
  --app-max-width: 1080px;

  /* Accesibilidad táctil */
  --touch-target-min: 48px;

  /* El brillo que cruza las tarjetas de pago (M2, 135ª) */
  --color-shine: rgba(255, 255, 255, 0.55);
}

/* 2. MODO OSCURO (automático por SO) — nit mediterrània, AA medido
   -------------------------------------------------------------------------- */
@media (prefers-color-scheme: dark) {
  :root {
    --color-bg-base: #0d1322;
    --color-bg-card: #171f33;
    --color-bg-sunken: #0a0f1b;
    --color-border: #28324b;
    --color-border-strong: #394562;

    --color-text-primary: #eef1f6; /* 14.5:1 sobre tarjeta */
    --color-text-secondary: #b6c0d4; /* 9:1 */
    --color-text-muted: #8e99af; /* 5.7:1 */

    --color-brand-primary: #38bdf8; /* tinta oscura encima: 7.1:1 */
    --color-brand-hover: #5bc0f8;
    --color-brand-text: #5bc0f8; /* 8.1:1 sobre tarjeta */
    --color-brand-wash: #13324a;
    --color-focus-ring: rgba(91, 192, 248, 0.4); /* halo blando (box-shadow) */
    --color-focus-outline: #5bc0f8; /* opaco: 9,13:1 sobre el fondo oscuro */

    --color-terra-text: #ffb38a; /* 8.7:1 sobre su lavado oscuro */
    --color-terra-strong: #ffb38a;
    --color-terra-wash: #3a2012;
    --color-terra-border: #5c3322;

    --color-whatsapp-bg: #2bd97b;
    --color-whatsapp-text: #04271a; /* 8.6:1 */
    --color-whatsapp-hover: #4ae18f;
    --color-call-bg: #60a5fa;
    --color-call-text: #071e4a; /* 6.4:1 */
    --color-call-hover: #7eb6fb;
    --color-website-btn: #475569;

    /* Color por categoría (24e): versión clara de cada uno, con la tinta
       oscura del fondo encima del disco */
    --cat-restauracion: #f97066;
    --cat-comercio: #b69cff;
    --cat-servicios: #38bdf8;
    --cat-salud: #4ade80;
    --cat-vida-local: #94a3b8;
    --cat-badge-ink: #0d1322;
    --arcade-ink: #34405a;
    --color-website-btn-hover: #596b85;

    --color-badge-bg: #13324a;
    --color-badge-text: #9fd7fa; /* 8.6:1 */
    --color-candelera-text: #fb923c;
    --color-candelera-bg: rgba(251, 146, 60, 0.14);
    --color-candelera-border: rgba(251, 146, 60, 0.3);
    --color-closed-text: #fbbf24;
    --color-closed-bg: rgba(251, 191, 36, 0.14);
    --color-closed-border: rgba(251, 191, 36, 0.3);
    --color-ok-text: #4ade80; /* sello: 7,33:1 en la tarjeta · 6,63:1 en el lavado de .claim-card */
    --color-ok-bg: rgba(74, 222, 128, 0.12);
    --color-ok-border: rgba(74, 222, 128, 0.3);
    --color-error-text: #f87171;
    --color-error-bg: rgba(248, 113, 113, 0.12);
    --color-error-border: rgba(248, 113, 113, 0.3);
    --color-featured-text: #fbbf24; /* 9.8:1 · 8.6:1 sobre su lavado */
    --color-featured-border: rgba(251, 191, 36, 0.45);
    /* Ámbar al 7 % sobre la tarjeta oscura. Medido: título 12.7:1 ·
       dirección 7.8:1 · categoría 5.0:1 */
    --color-featured-wash: #272a32;
    /* El chip del Col·laborador en oscuro: ámbar claro de fondo y el azul
       del fondo de la página como texto. Medido: texto 11:1 · marco 8.6:1 */
    --color-collab: #fbbf24;
    --color-collab-on: #0d1322;

    --color-address-link: #b6c0d4;
    --color-address-link-hover: #5bc0f8;

    /* El perfil ForgeBio oscuro de verdad: negro, botones grafito */
    --fb-accent: #22c55e; /* 7.5:1 sobre el botón */
    --fb-accent-text: #4ade80; /* 9.4:1 sobre tarjeta */
    --fb-line: rgba(34, 197, 94, 0.55);
    --fb-phone-bg: #0a0a0a;
    --fb-phone-border: #262626;
    --fb-phone-text: #fafafa;
    --fb-phone-meta: #a3a3a3; /* 7.9:1 */
    --fb-phone-btn: #1c1c1c;
    --fb-btn-line: transparent;
    --fb-wash: #0a0a0a; /* sin lavado: el oscuro es plano */

    --hero-wash:
      radial-gradient(42rem 20rem at 8% -4rem, rgba(56, 189, 248, 0.14), transparent 60%),
      radial-gradient(36rem 18rem at 98% 0, rgba(255, 138, 76, 0.1), transparent 55%);

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.35), 0 1px 6px rgba(0, 0, 0, 0.3);
    --shadow-md: 0 10px 28px -8px rgba(0, 0, 0, 0.55), 0 4px 10px -4px rgba(0, 0, 0, 0.4);
    --shadow-lift: 0 14px 30px -10px rgba(0, 0, 0, 0.6);

    --color-shine: rgba(255, 255, 255, 0.12);
  }
}

/* 3. RESET Y BASE (Mobile-First)
   -------------------------------------------------------------------------- */
*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  scroll-padding-top: 1rem;
}

body {
  font-family: var(--font-family);
  font-size: var(--font-size-base);
  line-height: var(--line-height-base);
  background-color: var(--color-bg-base);
  color: var(--color-text-primary);
  min-height: 100vh;
  padding: 0 1rem 1.5rem;
  transition:
    background-color 0.25s ease,
    color 0.25s ease;
  -webkit-tap-highlight-color: transparent;
}

.app-container {
  width: 100%;
  max-width: var(--app-max-width);
  margin: 0 auto;
}

/* 4. HÉROE DE LA GUÍA (cabecera + buscador, con lavado de color)
   -------------------------------------------------------------------------- */
.guia-hero {
  position: relative;
  margin: 0 -1rem 0.75rem;
  padding: 0.75rem 1rem 1rem;
  background-color: var(--color-bg-base);
  background-image: var(--hero-wash);
  border-bottom: 1px solid var(--color-border);
  /* La mola (24e) asoma por la esquina: lo que sobra se recorta aquí. No
     afecta al buscador fijado (position: fixed sale del recorte). */
  overflow: hidden;
}

/* La mola (24e, 178ª; «marca de agua OK»): dibujo propio
   (src/brandMarks.js), grande y muy tenue, arriba a la derecha del héroe.
   No ocupa alto (absoluta) ni roba el toque (pointer-events). Va la PRIMERA
   en el DOM y lo demás del héroe se posiciona para pintarse encima: así el
   título y el buscador quedan nítidos, sin velo. Sin stacking context en el
   héroe (ni z-index ni isolation): el buscador fijado (z-index 95) tiene
   que seguir por encima de la lupa y de «volver arriba». */
.hero-wm {
  position: absolute;
  top: -2.75rem;
  right: -2.25rem;
  width: 11rem;
  height: 11rem;
  color: var(--color-brand-primary);
  opacity: 0.07;
  pointer-events: none;
  transform: rotate(-12deg);
}

.hero-wm .mola {
  display: block;
  width: 100%;
  height: 100%;
}

.guia-breadcrumb,
.guia-hero__titlerow,
.guia-hero__tagline,
.guia-hero__actions {
  position: relative;
}

/* En oscuro la tinta es más clara que el fondo: sube un punto para verse igual de poco */
@media (prefers-color-scheme: dark) {
  .hero-wm {
    opacity: 0.12;
  }
}

@media (min-width: 640px) {
  .hero-wm {
    top: -4rem;
    right: 4rem;
    width: 15rem;
    height: 15rem;
  }
}

/* Título + conmutador de idioma, en una sola fila (E2, 137ª; en TODAS las
   páginas). El título envuelve; el idioma no encoge nunca. En móvil el
   título baja a 1,75rem: con el tamaño de héroe no cabían los dos a 375. */
.guia-hero__titlerow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}

.guia-hero__titlerow .lang-switch {
  flex-shrink: 0;
  margin-left: auto;
}

@media (max-width: 639px) {
  .guia-hero__titlerow .app-title {
    font-size: min(var(--font-size-hero), 1.75rem);
  }
}

/* La cabecera clásica (ficha, 404) se mantiene */
.app-header {
  text-align: center;
  margin-bottom: 2rem;
}

.app-header--guia {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  text-align: left;
  gap: 0.25rem;
  margin-bottom: 0;
}

.app-title {
  font-size: var(--font-size-hero);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1.08;
  color: var(--color-text-primary);
  text-wrap: balance;
}

.guia-hero__tagline {
  margin-top: 0.25rem;
  max-width: 34rem;
  font-size: var(--font-size-base);
  color: var(--color-text-secondary);
  text-wrap: pretty;
}

/* Conmutador de idioma (enlaces, sin JavaScript) */
.lang-switch {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  font-size: var(--font-size-xs);
  background-color: var(--color-bg-card);
  border: 1px solid var(--color-border);
  border-radius: 9999px;
  padding: 0.125rem;
  box-shadow: var(--shadow-sm);
}

/* M3 (135ª): a la vista, la MISMA altura que el sello «Sense cookies»
   (31 px medidos: 25 de botón + el aro del conmutador); el dedo sigue
   teniendo ≥ 44 × 44 gracias a la capa invisible de .lang-switch__link. */
.lang-switch__current,
.lang-switch__link {
  display: inline-flex;
  align-items: center;
  min-height: 25px;
  padding: 0 0.8rem;
  border-radius: 9999px;
  text-decoration: none;
  font-weight: 600;
}

.lang-switch__current {
  color: var(--color-bg-card);
  background-color: var(--color-text-primary);
}

.lang-switch__link {
  position: relative;
  color: var(--color-text-secondary);
}

/* El blanco del dedo: crece hasta 46 × 46 alrededor del botón, sin
   pintarse (si el botón ya es más grande, no encoge). 46 y no 44: con 44
   el redondeo dejaba 43,99 px a 375 (medido, 135ª). */
.lang-switch__link::before {
  content: "";
  position: absolute;
  inset: min(0px, calc(50% - 23px));
}

.lang-switch__link:hover {
  color: var(--color-brand-text);
  background-color: var(--color-brand-wash);
}

.lang-switch__link:focus-visible {
  outline: 3px solid var(--color-focus-outline);
  outline-offset: 1px;
}

/* En pantalla estrecha el idioma se enseña por su código (CA/ES): así el
   sello y el conmutador CABEN en una sola fila; el nombre entero queda
   en el aria-label. El corte: donde dejan de caber los nombres. */
.lang-switch__short {
  display: none;
}

@media (max-width: 459px) {
  .lang-switch__long {
    display: none;
  }

  .lang-switch__short {
    display: inline;
  }
}

/* Miga de las landings: volver a la guía */
.guia-breadcrumb {
  font-size: var(--font-size-sm);
}

.guia-breadcrumb a {
  display: inline-flex;
  align-items: center;
  min-height: var(--touch-target-min);
  color: var(--color-brand-text);
  font-weight: 600;
  text-decoration: none;
}

.guia-breadcrumb a:hover {
  color: var(--color-brand-hover);
  text-decoration: underline;
}

/* Buscador y puerta del alta dentro del héroe, en UNA fila (#56): son las
   dos cosas que se vienen a hacer. El buscador se queda el sitio que
   sobra; el botón mide lo que pide. */
.guia-hero__actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.75rem;
}

.search-box {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
  max-width: 38rem;
  display: flex;
  align-items: center;
}

/* El icono del buscador ya no es un emoji con línea base propia: es un
   svg, y se centra él solo respecto a la caja */
.search-icon {
  position: absolute;
  top: 50%;
  left: 1.1rem;
  display: flex;
  transform: translateY(-50%);
  color: var(--color-text-muted);
  pointer-events: none;
}

.search-icon svg {
  display: block;
  width: 18px;
  height: 18px;
}

.search-input {
  width: 100%;
  min-height: 44px;
  padding: 0 1.1rem 0 3rem;
  font-size: var(--font-size-base);
  font-family: inherit;
  color: var(--color-text-primary);
  background-color: var(--color-bg-card);
  border: 1px solid var(--color-border-strong);
  border-radius: 9999px;
  box-shadow: var(--shadow-sm);
  outline: none;
  transition:
    border-color 0.2s ease,
    box-shadow 0.2s ease;
}

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

.search-input:focus {
  border-color: var(--color-brand-primary);
  box-shadow: 0 0 0 4px var(--color-focus-ring);
}

/* Llegar desde «Busca el teu negoci» (d3-a, 187ª): el halo del foco late
   dos veces para llevar el ojo a la caja (en iPhone el teclado no se abre
   solo). La clase la pone y la quita app.js. Con movimiento reducido, el
   halo quieto. */
.search-box--beckon .search-input {
  border-color: var(--color-brand-primary);
  box-shadow: 0 0 0 4px var(--color-focus-ring);
  animation: search-beckon 1.1s ease-in-out 2;
}

@keyframes search-beckon {
  0%,
  100% {
    box-shadow: 0 0 0 4px var(--color-focus-ring);
  }

  50% {
    box-shadow: 0 0 0 10px var(--color-focus-ring);
  }
}

@media (prefers-reduced-motion: reduce) {
  .search-box--beckon .search-input {
    animation: none;
  }
}

/* La puerta del alta: píldora del alto del buscador, con su «+» en una
   insignia de marca. Es un enlace (lleva a la página del alta). Buscador y
   puerta miden lo que las píldoras de los filtros (44; 137ª). */
.guia-hero__add {
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
  gap: 0.5rem;
  min-height: 44px;
  padding: 0 1rem 0 0.4rem;
  font-size: var(--font-size-sm);
  font-weight: 700;
  color: var(--color-brand-text);
  text-decoration: none;
  white-space: nowrap;
  background-color: var(--color-bg-card);
  border: 1px solid var(--color-border-strong);
  border-radius: 9999px;
  box-shadow: var(--shadow-sm);
  transition:
    background-color 0.2s ease,
    border-color 0.2s ease;
}

.guia-hero__add-badge {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  color: #ffffff;
  background-color: var(--color-brand-primary);
  border-radius: 50%;
}

/* En oscuro el relleno de marca es claro: la tinta va oscura (7.1:1) */
@media (prefers-color-scheme: dark) {
  .guia-hero__add-badge {
    color: #06283d;
  }
}

.guia-hero__add-badge svg {
  display: block;
  width: 20px;
  height: 20px;
}

.guia-hero__add:hover {
  background-color: var(--color-brand-wash);
  border-color: var(--color-brand-primary);
}

.guia-hero__add:focus-visible {
  outline: 3px solid var(--color-focus-outline);
  outline-offset: 3px;
}

/* En móvil, al buscar el buscador se lleva la fila: el botón se pliega a
   su «+» (sigue ahí, y su nombre entero lo sigue diciendo el aria-label).
   Sin JavaScript: con el foco dentro, o con algo ya escrito. En pantalla
   ancha sobra sitio y plegarlo sería un salto sin motivo. */
@media (max-width: 479px) {
  .guia-hero__actions:has(.search-input:focus, .search-input:not(:placeholder-shown)) .guia-hero__add {
    justify-content: center;
    gap: 0;
    width: 56px;
    padding: 0;
  }

  .guia-hero__actions:has(.search-input:focus, .search-input:not(:placeholder-shown)) .guia-hero__add-text {
    display: none;
  }
}

/* #62 · La caja «Buscar» FIJADA arriba de la pantalla. Es la MISMA caja del
   héroe (nunca una copia: serían dos textos que mantener iguales) y la fija
   UNA clase de estado en <html>, que pone app.js: al tocar la lupa flotante
   o al buscar (desde 2 letras). Todo lo demás cuelga de esa clase.
   En pantalla ancha la barra cruza la ventana, pero el campo se alinea con
   la columna y no pasa del ancho que tiene en el héroe. */
.search-close {
  display: none;
}

.search-pinned .search-box {
  --pin-left: max(1rem, calc((100% - var(--app-max-width)) / 2));
  --pin-right: max(1rem, calc(100% - var(--pin-left) - 38rem));
  position: fixed;
  top: 0;
  right: 0;
  left: 0;
  z-index: 95;
  max-width: none;
  padding: 0.5rem var(--pin-right) 0.5rem var(--pin-left);
  background-color: var(--color-bg-base);
  border-bottom: 1px solid var(--color-border);
  box-shadow: var(--shadow-md);
}

.search-pinned .search-icon {
  left: calc(var(--pin-left) + 1.1rem);
}

.search-pinned .search-input {
  padding-right: 3.5rem;
}

/* La × que type="search" trae de serie (Chrome, Safari): con la nuestra
   saldrían DOS */
.search-pinned .search-input::-webkit-search-cancel-button {
  -webkit-appearance: none;
  appearance: none;
}

.search-pinned .search-close {
  position: absolute;
  top: 50%;
  right: calc(var(--pin-right) + 4px);
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--touch-target-min);
  height: var(--touch-target-min);
  padding: 0;
  color: var(--color-text-secondary);
  background: none;
  border: 0;
  border-radius: 9999px;
  cursor: pointer;
  transform: translateY(-50%);
}

.search-close svg {
  display: block;
  width: 20px;
  height: 20px;
}

.search-close:focus-visible {
  outline: 3px solid var(--color-focus-outline);
  outline-offset: -4px;
}

@media (hover: hover) {
  .search-close:hover {
    color: var(--color-text-primary);
  }
}

/* La caja fijada sale del flujo: este hueco ocupa SU sitio en la fila del
   héroe (mismo reparto y mismo tope), para que «Añadir» no se mueva */
.search-pinned .guia-hero__actions::before {
  content: "";
  flex: 1 1 auto;
  min-width: 0;
  max-width: 38rem;
}

/* Lo que el navegador lleva a la vista (un ancla, el foco del tabulador)
   no puede quedar DEBAJO de la caja fijada */
html.search-pinned {
  scroll-padding-top: 5.75rem;
}

/* 5. CATEGORÍAS, SUBCATEGORÍAS Y FILTROS
   -------------------------------------------------------------------------- */
.category-nav {
  position: relative;
  z-index: 30;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

/* EL VELO (punto 7, 211ª; su elección: «Velo oscurecido»): con
   Categories o Filtres abierto, una capa algo oscura tapa TODA la página
   (también el buscador fijado, 95, la lupa y la rueda, 90); solo la fila
   sube por encima y el menú se sigue usando. El toque de fuera cae en el
   velo (cierra, no abre nada) y el dedo sobre él no mueve lo de debajo
   (touch-action aquí; touchmove y rueda, cortados en app.js). El panel
   largo se desplaza por DENTRO (.popover-menu: overscroll contenido). El
   velo ES el aviso: sin texto. `cursor: pointer`: iOS solo entrega el clic
   de algo que parece «clicable». */
.menu-veil {
  position: fixed;
  inset: 0;
  z-index: 96;
  background-color: rgba(13, 19, 34, 0.35);
  cursor: pointer;
  touch-action: none;
  animation: menuVeilIn 0.15s ease-out;
}

.menu-veil[hidden] {
  display: none;
}

/* En oscuro el fondo ya ES ese azul noche: el velo tiene que ser más negro
   para que se note. */
@media (prefers-color-scheme: dark) {
  .menu-veil {
    background-color: rgba(0, 0, 0, 0.55);
  }
}

.category-nav--menu-open {
  z-index: 97;
}

@keyframes menuVeilIn {
  from {
    opacity: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .menu-veil {
    animation: none;
  }
}

/* La fila de TRES botones (punto 5, 207ª; «tres botones claros amigos -
   categorías - filtros»): fija, sin deslizar. Amics y Filtres miden lo que
   su texto; Categories se queda el resto y, si lo elegido no cabe, lo corta
   con «…». Con la letra del sistema muy grande (150 %, 208ª) el «…» lo
   aplastaba hasta 0: Categories tiene un MÍNIMO (en rem: crece con la
   letra) y, si ni así caben los tres, Filtres baja a otra línea. La base
   pequeña (no «auto») hace que solo salte de línea por ese mínimo, nunca
   por un nombre largo, que se corta con «…». Y crece como mucho hasta su
   texto (max-content): en escritorio no se estira a lo ancho. */
.nav-buttons {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}

.nav-buttons > .chip {
  flex: 0 0 auto;
}

.cat-menu {
  position: relative;
  flex: 1 1 6.5rem;
  min-width: 6.5rem;
  max-width: max-content;
}

.filter-popover-wrapper {
  position: relative;
  flex: 0 0 auto;
}

.filter-popover-wrapper[hidden] {
  display: none;
}

/* El summary hace de botón: sin el triángulo del navegador. El contenido
   va en .chip__inner (flex): WebKit viejo no hace flex en un <summary>. */
.chip--categories {
  display: flex;
  width: 100%;
  list-style: none;
}

.chip--categories::-webkit-details-marker {
  display: none;
}

.chip__inner {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-width: 0;
  max-width: 100%;
}

.chip--categories .chip__label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.chip--categories .chip__icon,
.chip--categories .popover-arrow {
  flex-shrink: 0;
}

.cat-menu[open] .popover-arrow {
  transform: rotate(180deg);
}

/* El menú de Categories: el de Filtres, abierto hacia la derecha desde su
   botón. Los dos con TOPE de alto: con 10 subcategorías no cabe en un
   móvil apaisado y se desplaza dentro. */
/* SIN el fundido de .popover-menu (208ª): dentro de un <details> el
   menú se quedaba a medio transparentar y se leía lo de debajo a través. */
.cat-menu .cat-menu__panel {
  left: 0;
  right: auto;
  width: max-content;
  max-width: min(20rem, calc(100vw - 2rem));
  animation: none;
}

/* En móvil los DOS menús cuelgan de la FILA, no de su botón (208ª): desde
   el botón del medio el de Categories se salía 13 px por la derecha a 375,
   y con Filtres en la 2ª línea (letra grande) el suyo se saldría por la
   izquierda. Categories abre pegado a la izquierda de la fila y Filtres a
   la derecha (su right: 0), siempre dentro. */
.nav-buttons {
  position: relative;
}

@media not all and (min-width: 700px) {
  .cat-menu,
  .nav-buttons .filter-popover-wrapper {
    position: static;
  }

  .cat-menu .cat-menu__panel {
    max-width: 100%;
  }
}

.popover-menu {
  max-height: min(65vh, 28rem);
  overflow-y: auto;
  overscroll-behavior: contain;
}

.cat-menu__level {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}

.cat-menu__level[hidden] {
  display: none;
}

.cat-menu__item,
.cat-menu__back {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  width: 100%;
  min-height: 44px;
  padding: 0.6rem 0.85rem;
  font-size: var(--font-size-sm);
  font-family: inherit;
  font-weight: 500;
  color: var(--color-text-primary);
  text-align: left;
  text-decoration: none;
  background: transparent;
  border: none;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition:
    background-color 0.15s ease,
    color 0.15s ease;
}

.cat-menu__back {
  font-weight: 600;
  color: var(--color-text-secondary);
}

.cat-menu__item:hover,
.cat-menu__back:hover,
.cat-menu__item--active {
  background-color: var(--color-brand-wash);
  color: var(--color-brand-text);
}

.cat-menu__item--active {
  font-weight: 700;
}

.cat-menu__item--sub {
  padding-left: 2.6rem;
}

.cat-menu__item[data-cat] {
  --cat: var(--color-text-secondary);
}

.cat-menu__item[data-cat="restauracion"] {
  --cat: var(--cat-restauracion);
}

.cat-menu__item[data-cat="comercio"] {
  --cat: var(--cat-comercio);
}

.cat-menu__item[data-cat="servicios"] {
  --cat: var(--cat-servicios);
}

.cat-menu__item[data-cat="salud"] {
  --cat: var(--cat-salud);
}

.cat-menu__item[data-cat="vida-local"] {
  --cat: var(--cat-vida-local);
}

.cat-menu__item[data-cat] .chip__icon {
  color: var(--cat);
}

.cat-menu__item--active .popover-option__check {
  visibility: visible;
}

.cat-menu__item:focus-visible,
.cat-menu__back:focus-visible {
  outline: 3px solid var(--color-focus-outline);
  outline-offset: -3px;
}

.cat-menu__rule {
  margin: 0.25rem 0.5rem;
  border: 0;
  border-top: 1px solid var(--color-border);
}

/* «Amics» sin « de la Guia» por debajo de 700 (su 168ª): la cola NO se
   borra, la sigue diciendo el lector (el recorte de .sr-only). Desde el
   punto 5, «Filtres» enseña su palabra desde 360 (botones claros; por
   debajo, el bloque de 360 de más abajo). Escrito
   como el CONTRARIO exacto del de 700: con zoom el ancho sale con decimales
   (699,2) y entre «max-width: 699px» y «min-width: 700px» quedaba un hueco
   sin ninguno. */
@media not all and (min-width: 700px) {
  .chip__tail {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }
}

/* Los tres botones en móvil (208ª, MEDIDO con Amics): por debajo de 420
   menos relleno y menos hueco, y «Categories» entra entero desde 360 en ca
   y es. Por debajo de 360 (su iPhone con «Ampliar») no cabe nada más sin
   quitar algo que se ve: «Filtres» se queda en icono y flecha, y la palabra
   la sigue diciendo el lector (su OK: «Filtres solo icono»). Mismo truco del
   CONTRARIO exacto que el de 700. */
@media not all and (min-width: 420px) {
  .nav-buttons {
    gap: 0.375rem;
  }

  .nav-buttons .chip {
    padding-left: 0.625rem;
    padding-right: 0.625rem;
  }
}

@media not all and (min-width: 360px) {
  .filter-popover-wrapper .chip__label {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }
}

/* (Punto 7, 211ª: fuera la línea «llisca per veure'n més» y todo su CSS;
   el asomo de «Ara a Molins» sigue, en app.js.) */

/* En pantalla ancha hay sitio: las píldoras ENVUELVEN y nada se desliza
   ni se corta (el carrusel con fundido es patrón de móvil) */
@media (min-width: 700px) {
  .pill-row {
    flex-wrap: wrap;
    overflow-x: visible;
    -webkit-mask-image: none;
    mask-image: none;
  }
}

/* Filas con scroll horizontal a sangre + difuminado en los bordes (avisa
   de que hay más). La máscara no corta el foco: solo es pintura. */
.pill-row {
  display: flex;
  gap: 0.45rem;
  margin: 0 -1rem;
  padding: 0.15rem 1rem;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  /* Sin esto, el imán del snap pega la 1ª píldora al BORDE ignorando el
     padding: la fila carga ya desplazada 16px (el «Tots» sin margen) */
  scroll-padding-inline-start: 1rem;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 0.9rem, #000 calc(100% - 1.4rem), transparent);
  mask-image: linear-gradient(to right, transparent, #000 0.9rem, #000 calc(100% - 1.4rem), transparent);
}

.pill-row::-webkit-scrollbar {
  display: none;
}

.pill-row:empty,
.pill-row[hidden] {
  display: none;
}

.chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  white-space: nowrap;
  min-height: 44px;
  padding: 0.5rem 1rem;
  font-size: var(--font-size-sm);
  font-weight: 600;
  font-family: inherit;
  color: var(--color-text-secondary);
  background-color: var(--color-bg-card);
  border: 1px solid var(--color-border-strong);
  border-radius: 9999px;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition:
    border-color 0.2s ease,
    background-color 0.2s ease,
    color 0.2s ease,
    transform 0.15s ease;
}

a.chip {
  text-decoration: none;
}

@media (hover: hover) {
  .chip:hover {
    border-color: var(--color-brand-primary);
    color: var(--color-brand-text);
    transform: translateY(-1px);
  }
}

.chip:focus-visible {
  outline: 3px solid var(--color-focus-outline);
  outline-offset: 2px;
}

.chip:active {
  transform: scale(0.97);
}

.chip--active {
  background-color: var(--color-text-primary);
  color: var(--color-bg-card);
  border-color: var(--color-text-primary);
}

.chip--active:hover {
  background-color: var(--color-text-primary);
  color: var(--color-bg-card);
}

/* El icono SVG de la categoría es decorativo (stroke = currentColor:
   hereda el color de la píldora activa/inactiva, en claro y en oscuro) */
.chip__icon {
  display: inline-flex;
  align-items: center;
}

.chip__icon svg {
  display: block;
}

/* Cápsula de los iconos de la TARJETA y la FICHA (botones, badges,
   dirección). El svg pinta con currentColor, así que hereda el color del
   botón o del badge en claro y en oscuro — lo que un emoji no hace. El
   hueco entre icono y texto lo pone el `gap` de cada contenedor. */
.icon-slot {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
  /* Para los que van DENTRO de un texto (la dirección): sin esto el icono
     se sienta en la línea base y queda alto respecto a la letra */
  vertical-align: -0.15em;
}

.icon-slot svg {
  display: block;
}

/* El icono acompaña al texto: a tamaño de badge o de dirección, 16px se
   come la línea, así que cada contexto fija el suyo. */
.badge .icon-slot svg {
  width: 14px;
  height: 14px;
}

.featured-mark .icon-slot svg {
  width: 13px;
  height: 13px;
}

.merchant-card__address .icon-slot svg {
  width: 15px;
  height: 15px;
}

/* El badge de la agenda es texto xs: 16px se comería la píldora */
.agenda-card__kind .icon-slot svg {
  width: 14px;
  height: 14px;
}

.chip--category {
  flex-shrink: 0;
  scroll-snap-align: start;
}

/* La ✕ de quitar un filtro activo (tocar el activo = quitarlo) */
.chip__clear {
  display: inline-flex;
  align-items: center;
}

.chip__clear svg {
  display: block;
  width: 13px;
  height: 13px;
}

/* El caret era el carácter ▾ y convivía en el MISMO botón con un svg:
   ahora es otro trazo lucide. La rotación al abrir sigue igual. */
.popover-arrow {
  display: inline-flex;
  margin-left: 0.2rem;
  transition: transform 0.2s ease;
}

.popover-arrow svg {
  display: block;
  width: 14px;
  height: 14px;
}

.chip--popover[aria-expanded="true"] .popover-arrow {
  transform: rotate(180deg);
}

.popover-menu {
  position: absolute;
  top: calc(100% + 0.5rem);
  right: 0;
  z-index: 100;
  min-width: 220px;
  padding: 0.5rem;
  background-color: var(--color-bg-card);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  animation: popoverFadeIn 0.15s ease-out;
}

.popover-menu[hidden] {
  display: none;
}

.popover-option {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  width: 100%;
  min-height: 44px;
  padding: 0.6rem 0.85rem;
  font-size: var(--font-size-sm);
  font-family: inherit;
  font-weight: 500;
  color: var(--color-text-primary);
  background: transparent;
  border: none;
  border-radius: var(--radius-sm);
  text-align: left;
  cursor: pointer;
  transition:
    background-color 0.15s ease,
    color 0.15s ease;
}

.popover-option:hover,
.popover-option--active {
  background-color: var(--color-brand-wash);
  color: var(--color-brand-text);
}

/* La elegida no es solo «el color del hover» (su 138ª): lleva peso y su ✓,
   que ocupa siempre su sitio para que el texto no salte al marcar. */
.popover-option--active {
  font-weight: 700;
}

.popover-option__check {
  display: inline-flex;
  margin-left: auto;
  padding-left: 0.5rem;
  visibility: hidden;
}

.popover-option--active .popover-option__check {
  visibility: visible;
}

.popover-option__check svg {
  display: block;
  width: 16px;
  height: 16px;
}

/* Los filtros activos (138ª): una fila propia bajo las píldoras, cada uno
   con su ✕ (al lado del botón no cabían a 375). Envuelve, no se desliza:
   son pocos y todos deben verse. */
.active-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.active-filters[hidden] {
  display: none;
}

.chip--filter .chip__clear,
.empty-msg__clear .chip__clear {
  margin-left: 0.15rem;
}

@keyframes popoverFadeIn {
  from {
    opacity: 0;
    transform: translateY(-6px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* Chips TEÑIDOS (24e, 178ª; «disco + chips teñidos OK»): el menú es la
   leyenda del color de las tarjetas. El icono de la madre va en su color y
   el borde, a medias (color-mix); el activo sigue sólido y su icono hereda.
   Una madre sin color en la lista (una categoría nueva del panel) hereda el
   gris del texto: nunca un chip sin borde. Solo las principales llevan
   data-cat (las subs no tienen icono ni color propio). */
.chip--category[data-cat] {
  --cat: var(--color-text-secondary);
  border-color: color-mix(in srgb, var(--cat) 45%, transparent);
}

.chip--category[data-cat="restauracion"] {
  --cat: var(--cat-restauracion);
}

.chip--category[data-cat="comercio"] {
  --cat: var(--cat-comercio);
}

.chip--category[data-cat="servicios"] {
  --cat: var(--cat-servicios);
}

.chip--category[data-cat="salud"] {
  --cat: var(--cat-salud);
}

.chip--category[data-cat="vida-local"] {
  --cat: var(--cat-vida-local);
}

.chip--category[data-cat] .chip__icon {
  color: var(--cat);
}

.chip--category[data-cat].chip--active {
  border-color: var(--color-text-primary);
}

.chip--category[data-cat].chip--active .chip__icon {
  color: inherit;
}

@media (hover: hover) {
  .chip--category[data-cat]:hover {
    border-color: var(--cat);
  }
}

/* 6. «ARA A MOLINS» (lo puntual: actes, ofertes, avisos)
   El módulo solo existe si hay contenido vigente (lo decide el servidor).
   -------------------------------------------------------------------------- */
.section-label {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin: 1.5rem 0 0.6rem;
  font-size: var(--font-size-xs);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}

.section-label::after {
  content: "";
  flex: 1;
  height: 1px;
  background-color: var(--color-border);
}

/* Cabecera de sección con texto de apoyo (89ª, decisión suya): el título,
   el apoyo en gris y la raya hasta el borde en UNA fila, el mismo ritmo que
   la zona de Amics (.listing-group). Si no cabe (320 px), el apoyo baja de
   línea y la raya lo sigue. El apoyo es un <p> hermano, no parte del h2:
   el nombre del encabezado sigue siendo solo el título, y el contador de
   «Establiments» conserva su aria-live. */
.section-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem 0.6rem;
  margin: 1rem 0 0.4rem;
}

.section-head .section-label {
  margin: 0;
}

.section-head .section-label::after {
  display: none;
}

.section-head::after {
  content: "";
  flex: 1 1 2rem;
  height: 1px;
  background-color: var(--color-border);
}

.section-lead {
  margin: 0;
}

.agenda__title {
  color: var(--color-terra-text);
}

.agenda__row {
  display: flex;
  gap: 0.75rem;
  margin: 0 -1rem;
  padding: 0.25rem 1rem 0.35rem;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  scroll-padding-inline-start: 1rem;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 0.9rem, #000 calc(100% - 1.4rem), transparent);
  mask-image: linear-gradient(to right, transparent, #000 0.9rem, #000 calc(100% - 1.4rem), transparent);
}

.agenda__row::-webkit-scrollbar {
  display: none;
}

/* El carril de «Ara a Molins» (M1, 135ª): lo pone agenda.js alrededor de
   la fila y posiciona las flechas ‹ ›. Las flechas solo existen con ratón
   fino (en táctil se desliza con el dedo) y agenda.js las esconde en los
   extremos y si todo cabe. */
.agenda__rail {
  position: relative;
}

.agenda__arrow {
  display: none;
  position: absolute;
  top: 50%;
  z-index: 1;
  width: 44px;
  height: 44px;
  align-items: center;
  justify-content: center;
  transform: translateY(-50%);
  border: 1px solid var(--color-border-strong);
  border-radius: 9999px;
  background-color: var(--color-bg-card);
  color: var(--color-text-primary);
  box-shadow: var(--shadow-md);
  cursor: pointer;
  transition:
    background-color 0.2s ease,
    color 0.2s ease;
}

.agenda__arrow--prev {
  left: -0.5rem;
}

.agenda__arrow--next {
  right: -0.5rem;
}

.agenda__arrow .icon-slot svg {
  width: 22px;
  height: 22px;
}

@media (hover: hover) and (pointer: fine) {
  .agenda__arrow:not([hidden]) {
    display: inline-flex;
  }

  .agenda__arrow:hover {
    color: var(--color-brand-text);
    background-color: var(--color-brand-wash);
  }
}

/* El brillo de las de PAGO (M2, 135ª): una franja de luz cruza la tarjeta
   UNA vez, cuando entra en pantalla (lo enciende agenda.js). Pintura sobre
   la tarjeta: no se puede pulsar y no cambia nada de sitio. */
.agenda-card--shine::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background: linear-gradient(105deg, transparent 42%, var(--color-shine) 50%, transparent 58%) 100% 0 / 250% 100% no-repeat;
  animation: agenda-shine 1.1s ease-out 1 both;
}

@keyframes agenda-shine {
  from {
    background-position: 100% 0;
  }

  to {
    background-position: 0 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .agenda-card--shine::after {
    display: none;
  }
}

.agenda-card {
  /* Contenedor de lo que lleve en absoluto: el aviso .sr-only de «pestanya
     nova» de un acto externo. Sin esto se posiciona respecto al body, se
     escapa del clip de la fila y, en cuanto su tarjeta es la 3a o posterior,
     ensancha el documento entero en el movil (medido con LOCALS, L2:
     375 -> 586 px, con el buscador flotante fuera de pantalla). */
  position: relative;
  flex: 0 0 auto;
  width: min(16.5rem, 78vw);
  scroll-snap-align: start;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  padding: 0.7rem 0.85rem 0.75rem;
  background-color: var(--color-bg-card);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  color: var(--color-text-primary);
  text-decoration: none;
  transition:
    transform 0.15s ease,
    box-shadow 0.2s ease,
    border-color 0.2s ease;
}

@media (hover: hover) {
  a.agenda-card:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-md);
    border-color: var(--color-border-strong);
  }
}

.agenda-card:focus-visible {
  outline: 3px solid var(--color-focus-outline);
  outline-offset: 2px;
}

.agenda-card__kind {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.15rem 0.6rem;
  font-size: var(--font-size-xs);
  font-weight: 700;
  border-radius: 9999px;
}

.agenda-card__kind--event {
  background-color: var(--color-brand-wash);
  color: var(--color-badge-text);
}

.agenda-card__kind--offer {
  background-color: var(--color-terra-wash);
  color: var(--color-terra-strong);
}

/* «Notícies» (#85) lleva su propia clase, pero el MISMO gris que «Avís»:
   las dos son del pueblo; los colores encendidos, de los comercios */
.agenda-card__kind--notice,
.agenda-card__kind--news {
  background-color: var(--color-bg-sunken);
  color: var(--color-text-secondary);
}

/* «Locals» (LOCALS v1, L2): un cuarto color, verde, que no se confunde con
   los otros tres. Medido sobre el lavado terra de la tarjeta encendida:
   5,5:1 en claro y 6,9:1 en oscuro */
.agenda-card__kind--local {
  background-color: var(--color-ok-bg);
  color: var(--color-ok-text);
}

/* Tope de líneas (137ª): los avisos los escribe él a mano (título hasta
   120, detalle hasta 200) y sin tope una sola tarjeta estiraba toda la
   fila. Título 3 líneas, detalle 2; Ofertes/Locals siguen a 2 (su
   .offer-frame__text va después y manda). */
.agenda-card__title {
  font-size: var(--font-size-base);
  font-weight: 700;
  line-height: 1.3;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  overflow: hidden;
  overflow-wrap: anywhere;
}

.agenda-card__sub {
  font-size: var(--font-size-sm);
  color: var(--color-text-secondary);
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  overflow-wrap: anywhere;
}

/* Lo gordo de la semana (festa major, fira): tarjeta encendida */
.agenda-card--featured {
  background-color: var(--color-terra-wash);
  border-color: var(--color-terra-border);
}

.agenda-card--featured .agenda-card__title {
  color: var(--color-terra-strong);
}

/* «Notícies» (#85): una caja con DOS enlaces, apagada como «Avís»: el
   diario del pueblo y, tras una linea, la agenda del Ajuntament. Cada enlace
   es su propia zona de toque; en flex, la flecha no se queda sola en otra
   linea aunque el texto parta. Sin gap: la altura de los enlaces ya separa. */
.agenda-card--news {
  gap: 0;
}

.agenda-news__link {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  min-height: var(--touch-target-min);
  color: inherit;
  text-decoration: none;
  border-radius: var(--radius-sm);
}

.agenda-news__link .icon-slot svg {
  width: 14px;
  height: 14px;
}

.agenda-news__link--main {
  font-size: var(--font-size-base);
  font-weight: 700;
  line-height: 1.3;
}

.agenda-news__link--agenda {
  border-top: 1px solid var(--color-border);
  font-size: var(--font-size-sm);
  color: var(--color-text-secondary);
}

@media (hover: hover) {
  .agenda-news__link:hover {
    text-decoration: underline;
    text-underline-offset: 0.2em;
  }
}

.agenda-news__link:focus-visible {
  outline: 3px solid var(--color-focus-outline);
  outline-offset: 2px;
}

/* La tarjeta «Ofertes» que gira (tramo 1b): un fotograma a la vista, los
   demas `hidden`; agenda.js los va encendiendo. La oferta reserva SIEMPRE
   dos lineas (y se corta en dos) para que la tarjeta no cambie de altura
   entre fotogramas; el nombre del negocio va en una linea con puntos.
   La tarjeta «Locals» (L2) es el mismo fotograma con otra etiqueta. */
.agenda-card--offers,
.agenda-card--locals {
  gap: 0.3rem;
}

.offer-frame {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  min-width: 0;
  animation: offer-frame-in 0.35s ease;
}

.offer-frame[hidden] {
  display: none;
}

.offer-frame__name {
  font-size: var(--font-size-sm);
  color: var(--color-text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.offer-frame__text {
  min-height: 2.6em;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  overflow-wrap: anywhere;
}

.offer-frame__until {
  font-size: var(--font-size-xs);
  color: var(--color-text-secondary);
}

.offer-frame__featured {
  color: var(--color-terra-strong);
}

@keyframes offer-frame-in {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}

/* 7. COL·LABORADORS (banners): etiquetados, rotativos, con CTA propio
   -------------------------------------------------------------------------- */
.partners-label {
  color: var(--color-terra-text);
}

/* La etiqueta del listado, igual que «Ara a Molins» y «Col·laboradors»:
   las tres secciones de la portada se anuncian del mismo modo */
.merchants-label {
  color: var(--color-terra-text);
}

/* En móvil 5:2 (E3, 137ª: «OK carrousel más bajo», suyo): Col·laboradors
   entra entero en la primera pantalla. Recorta un poco arriba y abajo los
   banners pensados a 2:1 (object-fit: cover).
   M3 punto 4 (206ª, «en lugar de fijar tamaños vamos a utilizar
   proporciones», suyo): la proporción es el PUNTO DE PARTIDA, no una jaula.
   - Lo de dentro (letra, márgenes, pie) se mide en `cqi` = % del ancho del
     propio banner: escala junto con él, como una imagen.
   - La letra tiene un suelo en rem: quien agranda el texto lo sigue viendo.
   - Si con ese suelo NO cabe (iPhone con «Ampliar» = 320 de ancho, idioma
     largo), el banner CRECE en vez de cortar: `overflow: clip` no es un
     contenedor con scroll, y entonces el alto mínimo de una caja con
     aspect-ratio es el de su contenido. Con `hidden` se cortaba (33 px del
     CTA a 320). Crecen todas las diapositivas a la vez: el carrusel no salta.
   - La proporción sigue reservando el sitio antes de que llegue el JS (CLS 0).
   Navegadores sin `clip` ni `cqi` se quedan con `hidden` y los rem: lo de antes. */
.banner-slot {
  position: relative;
  aspect-ratio: 5 / 2;
  container-type: inline-size;
  display: flex;
  flex-direction: column;
  margin-bottom: 0.5rem;
  overflow: hidden;
  overflow: clip;
  border-radius: var(--radius-xl);
  background-color: var(--color-bg-card);
  border: 1px solid var(--color-border);
  box-shadow: var(--shadow-sm);
  touch-action: pan-y;
  user-select: none;
  -webkit-touch-callout: none;
}

.banner-slot[hidden] {
  display: none;
}

/* En pantallas anchas el 2:1 a sangre sería un mural: se acota */
@media (min-width: 700px) {
  .banner-slot {
    aspect-ratio: 3 / 1;
  }
}

/* Llena el hueco O MÁS: con `height: 100%` la pista se ataba a la proporción
   y el contenido nunca empujaba (la red de seguridad de arriba no saltaba:
   con la letra al 150 % se cortaba igual). Las diapositivas se estiran a la
   más alta (align-items: stretch por defecto). */
.banner-track {
  display: flex;
  flex: 1 0 auto;
  transition: transform 0.4s ease;
  will-change: transform;
}

.banner-track--instant {
  transition: none;
}

/* Columna pegada abajo: el pie de las de foto cae al fondo (va en el flujo,
   ver `.banner-caption`). El CTA y las de texto lo cambian con sus reglas. */
.banner-slide {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  flex: 0 0 100%;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  /* El subrayado del <a> no llegaba al pie mientras era absoluto; ahora que
     va en el flujo, lo heredaría en los banners que enlazan a una web */
  text-decoration: none;
  cursor: pointer;
  /* WebKit (el Safari de su iPhone) levanta el fantasma de arrastre del
     enlace aunque el gesto ya esté cancelado en JS: aquí no se arrastra nada */
  -webkit-user-drag: none;
}

div.banner-slide {
  cursor: default;
}

.banner-slot--carousel .banner-slide {
  cursor: grab;
}

/* La foto va DE FONDO: si estuviera en el flujo, su 2:1 natural empujaría
   el alto del banner (ver arriba) y la proporción dejaría de mandar. */
.banner-slide img {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  -webkit-user-drag: none;
}

.banner-slide:focus-visible {
  outline: 3px solid var(--color-brand-primary);
  outline-offset: -3px;
}

/* El pie va EN EL FLUJO, pegado abajo (`.banner-slide` es columna al fondo):
   así cuenta para el alto y, si no cabe, el banner crece en vez de taparse.
   Antes: 2rem arriba + 1,75rem abajo fijos = a 320 de ancho el pie medía
   108 de 113 px y tapaba la foto con el degradado. Ahora el aire es
   proporcional; abajo queda siempre el sitio de los puntos (24 px + 0,25rem). */
.banner-caption {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  padding: 2rem 1rem 1.75rem;
  padding: clamp(0.5rem, 7cqi, 2rem) clamp(0.75rem, 4cqi, 1rem) 1.75rem;
  color: #ffffff;
  background: linear-gradient(transparent, rgba(0, 0, 0, 0.72));
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
}

.banner-caption strong {
  font-size: var(--font-size-lg);
  font-size: clamp(1rem, 5.5cqi, var(--font-size-lg));
  line-height: 1.2;
}

.banner-caption span {
  font-size: var(--font-size-sm);
  font-size: clamp(0.8125rem, 4cqi, var(--font-size-sm));
  line-height: 1.3;
}

/* La diapositiva propia: «El teu negoci, aquí?» (blanco sobre blau: 7.6:1) */
.banner-slide--cta {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 0.35rem;
  gap: clamp(0.2rem, 1.5cqi, 0.35rem);
  padding: 1.25rem 1.5rem;
  padding: clamp(0.5rem, 4cqi, 1.25rem) clamp(1rem, 5cqi, 1.5rem);
  background-image: linear-gradient(135deg, #075985, #0a6ea8 55%, #a03d14 160%);
  color: #ffffff;
  text-decoration: none;
}

/* Con puntos, el texto de las diapositivas sin foto no baja hasta ellos:
   «Com funcionen…» quedaba DEBAJO de los puntos a 320 de ancho */
.banner-slot--carousel .banner-slide--cta,
.banner-slot--carousel .banner-slide--text {
  padding-bottom: 1.75rem;
}

.banner-cta__title {
  font-size: var(--font-size-lg);
  font-size: clamp(1rem, 5.5cqi, var(--font-size-lg));
  font-weight: 800;
  letter-spacing: -0.01em;
  line-height: 1.2;
}

.banner-cta__text {
  font-size: var(--font-size-sm);
  font-size: clamp(0.8125rem, 4cqi, var(--font-size-sm));
  line-height: 1.3;
  opacity: 0.92;
  max-width: 28rem;
}

.banner-cta__arrow {
  margin-top: 0.3rem;
  margin-top: clamp(0.1rem, 1cqi, 0.3rem);
  font-size: var(--font-size-sm);
  font-size: clamp(0.8125rem, 4cqi, var(--font-size-sm));
  font-weight: 700;
  border-bottom: 2px solid rgba(255, 255, 255, 0.6);
  padding-bottom: 0.1rem;
}

/* Colaborador SIN arte todavía: el nombre es la diapositiva (migración 019).
   Centrada, para que no se confunda con la propia («El teu negoci, aquí?»),
   que va alineada a la izquierda. El tono lo pone `data-tone`, que sale del
   id del banner: aquí NO hay ninguna regla por marca, solo cuatro números. */
.banner-slide--text {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  gap: clamp(0.2rem, 1.5cqi, 0.4rem);
  padding: 1.25rem 1.5rem;
  padding: clamp(0.5rem, 4cqi, 1.25rem) clamp(1rem, 5cqi, 1.5rem);
  background-image: linear-gradient(135deg, var(--banner-tone-a), var(--banner-tone-b));
  color: #ffffff;
  text-align: center;
  text-decoration: none;
}

.banner-slide--text[data-tone="0"] {
  --banner-tone-a: #0c4a6e;
  --banner-tone-b: #075985;
}

.banner-slide--text[data-tone="1"] {
  --banner-tone-a: #8a3410;
  --banner-tone-b: #a03d14;
}

.banner-slide--text[data-tone="2"] {
  --banner-tone-a: #2c3547;
  --banner-tone-b: #3c475c;
}

.banner-slide--text[data-tone="3"] {
  --banner-tone-a: #8a3410;
  --banner-tone-b: #2c3547;
}

.banner-text__name {
  font-size: var(--font-size-xl);
  font-size: clamp(1.25rem, 8cqi, var(--font-size-xl));
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.15;
  text-wrap: balance;
}

.banner-text__subtitle {
  font-size: var(--font-size-sm);
  font-size: clamp(0.8125rem, 4cqi, var(--font-size-sm));
  opacity: 0.92;
  max-width: 24rem;
}

/* Puntos del carrusel: pequeños a la vista, 24px al tacto */
.banner-dots {
  position: absolute;
  bottom: 0.25rem;
  left: 50%;
  display: flex;
  transform: translateX(-50%);
}

.banner-dot {
  width: 24px;
  height: 24px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}

.banner-dot::before {
  content: "";
  display: block;
  width: 8px;
  height: 8px;
  margin: auto;
  border-radius: 9999px;
  background-color: rgba(255, 255, 255, 0.55);
  box-shadow: 0 0 2px rgba(0, 0, 0, 0.6);
  transition: width 0.2s ease;
}

.banner-dot[aria-current="true"]::before {
  width: 18px;
  background-color: #ffffff;
}

.banner-dot:focus-visible {
  outline: 2px solid #ffffff;
  outline-offset: -2px;
  border-radius: 9999px;
}

/* 8. LISTADO Y TARJETAS DE COMERCIO
   -------------------------------------------------------------------------- */
/* El contador vive en la cabecera «Establiments» (89ª) y viste como todo
   texto de apoyo (.section-lead); aquí solo lo que es suyo. */
.results-count {
  color: var(--color-text-muted);
}

.merchant-list {
  position: relative;
  z-index: 10;
  display: grid;
  /* minmax(0, ...) y no 1fr a secas: un 1fr NO baja del contenido de la
     tarjeta, asi que una tarjeta ancha empujaria la columna fuera del
     contenedor y la lista desbordaria al encoger la ventana. */
  grid-template-columns: minmax(0, 1fr);
  gap: 1rem;
}

/* #62: con la caja fijada, el inicio de los resultados sube hasta quedar
   bajo ella. La lista guarda al menos una pantalla de alto para que ese
   salto se pueda dar también con DOS resultados: si no, el documento se
   queda corto y la vista baila con cada letra. Las filas no se estiran. */
.search-pinned .merchant-list {
  min-height: 100vh;
  align-content: start;
}

.merchant-card {
  /* El disco de categoría (24e) se ancla a la esquina; una madre sin color
     en la lista sale en el gris de la tinta apagada */
  position: relative;
  --cat: var(--color-text-muted);
  background-color: var(--color-bg-card);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: 1.15rem 1.25rem 1.25rem;
  box-shadow: var(--shadow-sm);
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  /* SIN content-visibility (205a). Lo llevaba («con ~350 tarjetas solo se
     maqueta lo cercano»), pero tras un salto (la rueda de letras) las fichas
     de en medio quedaban sin dibujar con un alto ESTIMADO; al pasar el dedo
     se dibujaban, cambiaban de alto y empujaban la lista. Chrome lo tapa con
     su anclaje de scroll; Safari no tiene: trompicones. Probado en SU iPhone
     sin él: «ahora fluye socia» → «ok a la A». Tras desplegar, Lighthouse. */
  transition:
    transform 0.18s ease,
    box-shadow 0.2s ease,
    border-color 0.2s ease;
}

.merchant-card:focus-within {
  box-shadow: var(--shadow-lift);
  transform: translateY(-3px);
  border-color: var(--color-border-strong);
}

@media (hover: hover) {
  .merchant-card:hover {
    box-shadow: var(--shadow-lift);
    transform: translateY(-3px);
    border-color: var(--color-border-strong);
  }
}

/* Amic de la Guia: EN COLOR (85ª) — lavado y marco cálidos y estrella,
   sin romper la retícula */
.merchant-card--featured {
  background-color: var(--color-featured-wash);
  border-color: var(--color-featured-border);
  box-shadow: 0 0 0 1px var(--color-featured-border), var(--shadow-sm);
}

.featured-mark {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  font-size: var(--font-size-xs);
  font-weight: 700;
  letter-spacing: 0.02em;
  color: var(--color-featured-text);
}

/* Col·laborador de la Guia (89ª): el distintivo RELLENO y el marco de la
   tarjeta más marcado. Misma familia ámbar que el Amic, más peso: el ojo
   lee «relleno = más» sin explicación. La estrella hereda el color del
   texto (currentColor). */
.featured-mark--collaborator {
  padding: 0.2rem 0.6rem;
  border-radius: 999px;
  background-color: var(--color-collab);
  color: var(--color-collab-on);
}

.merchant-card--collaborator {
  border-color: var(--color-collab);
  box-shadow: 0 0 0 2px var(--color-collab), var(--shadow-sm);
}

/* La zona de los Amics de la Guia y la divisoria «Més negocis» (64ª):
   ocupan la fila entera (en escritorio la lista va a dos columnas) y se
   anuncian como las secciones de la portada, con la raya hasta el borde.
   El subtítulo («Donen suport a la guia») dice que es apoyo: lo que se
   paga, identificado. */
.listing-group {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem 0.6rem;
  margin: 0.5rem 0 -0.25rem;
  font-size: var(--font-size-xs);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-featured-text);
}

.listing-group::after {
  content: "";
  flex: 1 1 2rem;
  height: 1px;
  background-color: var(--color-featured-border);
}

.listing-group__lead,
.section-lead {
  font-size: var(--font-size-xs);
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: none;
  color: var(--color-text-muted);
}

/* «Veure'ls tots (N)» (85ª): cierra la muestra de Amics que rota en la
   entrada. Fila entera, con el color de su zona y alto de dedo (44 px). */
.listing-see-all {
  grid-column: 1 / -1;
  margin: -0.25rem 0 0;
  font-size: var(--font-size-sm);
  font-weight: 700;
}

.listing-see-all__link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--color-featured-text);
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

/* La divisoria: clara pero sin competir con la zona de arriba */
.listing-group ~ .listing-group {
  margin-top: 1.25rem;
  color: var(--color-terra-text);
}

.listing-group ~ .listing-group::after {
  background-color: var(--color-border);
}

/* Categoría de la tarjeta (contexto al escanear la lista) */
.merchant-card__category {
  font-size: var(--font-size-xs);
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}

/* overflow-wrap (159ª): una palabra que no cabe ni en una línea entera se
   parte en vez de salirse de la tarjeta (a 320, «Supercalifragilisticoexpialidós»
   se salía, con escudo o sin él). Solo actúa en ese caso: los nombres que
   caben parten igual que antes (medido con las 344, 320/375/escritorio, ca y
   es). El escudo va pegado a las últimas letras (shared/merchantCard.js). */
.merchant-card__title {
  font-size: var(--font-size-lg);
  font-weight: 700;
  color: var(--color-text-primary);
  line-height: 1.25;
  letter-spacing: -0.01em;
  overflow-wrap: anywhere;
}

.merchant-card__link {
  color: inherit;
  text-decoration: none;
}

.merchant-card__link:hover {
  color: var(--color-brand-text);
  text-decoration: underline;
}

.merchant-card__link:focus-visible {
  outline: 3px solid var(--color-focus-outline);
  outline-offset: 3px;
  border-radius: var(--radius-sm);
}

/* La tarjeta ENTERA lleva a su ficha (210ª). Antes, tocar fuera del nombre
   abría un vistazo rápido con lo mismo que ya tenían la tarjeta y la ficha,
   y había que tocar otra vez: los testers no lo entendían. Una capa del
   enlace del título cubre la tarjeta (sigue siendo UN enlace de verdad:
   otra pestaña, compartir, SEO); la tarjeta ya es `position: relative`. */
.merchant-card__link::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: var(--radius-lg);
}

/* Lo que tiene destino PROPIO, por encima de esa capa: si no, WhatsApp,
   Truca y Com arribar llevarían a la ficha en vez de hacer lo suyo. Solo en
   el listado: la ficha comparte estas clases y ahí no hay capa que saltar. */
.merchant-list .merchant-card .btn-whatsapp,
.merchant-list .merchant-card .btn-call,
.merchant-list .merchant-card .card-address-link {
  position: relative;
  z-index: 1;
}

.merchant-card__address {
  font-size: var(--font-size-sm);
  color: var(--color-text-secondary);
  display: flex;
  align-items: center;
  gap: 0.35rem;
}

/* La dirección va en FLUJO DE TEXTO, no en flex: con una dirección de dos
   líneas, un flex deja la flecha de «abre fuera» descolgada a la derecha
   en vez de pegada a la última palabra. */
.card-address-link,
.card-address-plain {
  display: inline;
  font-size: var(--font-size-sm);
}

/* `>`: la flecha también es el primer elemento DE SU span y no debe
   heredar el aire del pin */
.card-address-link > .icon-slot:first-child,
.card-address-plain > .icon-slot:first-child {
  margin-right: 0.3rem;
}

/* La última palabra y la flecha no se separan (shared/merchantCard.js) */
.nowrap-tail {
  white-space: nowrap;
}

.card-address-link {
  color: var(--color-address-link);
  text-decoration: none;
  transition: color 0.2s ease;
  /* Es hijo de un flex (.merchant-card__address), asi que se blockifica y
     el padding SI cuenta. Sin el, la direccion de una sola linea medía 22px
     de alto y WCAG 2.5.8 pide 24: el dedo de quien no afina se iba al vacio
     entre dos tarjetas. Las de dos lineas ya pasaban (45px). */
  padding-block: 0.15rem;
}

.card-address-link:hover {
  color: var(--color-address-link-hover);
  text-decoration: underline;
}

.merchant-card__tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

.merchant-card__tags:empty {
  display: none;
}

.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  background-color: var(--color-badge-bg);
  color: var(--color-badge-text);
  font-size: var(--font-size-xs);
  font-weight: 600;
  padding: 0.3rem 0.65rem;
  border-radius: 9999px;
}

.badge--pwa {
  background-color: var(--color-brand-wash);
  color: var(--color-badge-text);
  border: 1px solid var(--color-focus-ring);
}

.badge--candelera {
  background-color: var(--color-candelera-bg);
  color: var(--color-candelera-text);
  border: 1px solid var(--color-candelera-border);
}

.badge--closed {
  background-color: var(--color-closed-bg);
  color: var(--color-closed-text);
  border: 1px solid var(--color-closed-border);
}

/* El sello «Negoci verificat» (M4, 113ª): verde de «ok» con su escudo, el
   PRIMERO de la fila y sin fecha. Gratis: el verde no compite con el ámbar
   del Amic (pagado). Texto y escudo: 6,33:1 claro · 7,33:1 oscuro sobre el
   fondo de tarjeta (ficha y vistazo rápido; la tarjeta de la lista lleva solo
   el escudo, .verified-mark); en el primer bloque del titular, sobre el
   lavado de .claim-card, 5,61:1 · 6,63:1 (medido, junto a los tokens
   --color-ok-*). */
.badge--verified {
  background-color: var(--color-ok-bg);
  color: var(--color-ok-text);
  border: 1px solid var(--color-ok-border);
}

/* El escudo PEQUEÑO del sello en la tarjeta (corte ③): pegado a la última
   palabra del nombre (shared/merchantCard.js), en el verde de «ok», el del
   sello. Con su color propio, el :hover del enlace no lo tiñe; y al ser
   inline-flex, el subrayado del enlace no lo cruza. Sin lavado, va sobre el
   fondo de la tarjeta: 7,13:1 claro · 9,41:1 oscuro; sobre el ámbar del Amic
   y del Col·laborador, 6,70:1 · 8,23:1; el :hover no cambia el fondo
   (medido en el pane, 121ª; un icono pide 3:1). */
.verified-mark {
  display: inline-flex;
  margin-left: 0.3em;
  color: var(--color-ok-text);
  vertical-align: -0.1em;
}

.verified-mark .icon-slot svg {
  width: 0.9em;
  height: 0.9em;
}

/* Botones de contacto: píldoras compactas, AA medido */
.btn-whatsapp,
.btn-call {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.45rem;
  min-height: var(--touch-target-min);
  font-weight: 700;
  font-size: var(--font-size-sm);
  text-decoration: none;
  border-radius: 9999px;
  padding: 0 1.2rem;
  margin-top: 0.25rem;
  transition:
    background-color 0.2s ease,
    transform 0.15s ease;
}

.btn-whatsapp {
  background-color: var(--color-whatsapp-bg);
  color: var(--color-whatsapp-text);
}

.btn-whatsapp:hover {
  background-color: var(--color-whatsapp-hover);
}

.btn-call {
  background-color: var(--color-call-bg);
  color: var(--color-call-text);
}

.btn-call:hover {
  background-color: var(--color-call-hover);
}

.btn-whatsapp:active,
.btn-call:active,
.btn-primary-cta:active {
  transform: scale(0.98);
}

.btn-whatsapp:focus-visible,
.btn-call:focus-visible {
  outline: 3px solid var(--color-focus-outline);
  outline-offset: 3px;
}

.btn-website {
  background-color: var(--color-website-btn);
  color: #ffffff;
}

.btn-website:hover {
  background-color: var(--color-website-btn-hover);
}

/* Mensajes de estado */
.empty-msg,
.error-msg {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  text-align: center;
  padding: 2.5rem 1rem;
  color: var(--color-text-muted);
  font-size: var(--font-size-base);
  background-color: var(--color-bg-card);
  border: 1px dashed var(--color-border-strong);
  border-radius: var(--radius-lg);
}

/* #51 · Buscaba su negocio y no sale: el mensaje se apila y lleva la
   puerta del ALTA (solo cuando hay texto en el buscador). */
.empty-msg--add {
  flex-direction: column;
  gap: 0.75rem;
}

.empty-msg__lead {
  color: var(--color-text-primary);
  font-weight: 700;
}

/* El DISCO de categoría (24e, 178ª; «disco + chips teñidos OK»): el
   icono de la MADRE, en tinta clara sobre su color, arriba a la derecha de
   la tarjeta. Es gráfico (≥ 3:1 medido), no texto: lo que se lee es el
   eyebrow. El fondo de la tarjeta NO cambia: el pago manda (Amic lavado,
   Col·laborador marco). El disco se mete en el padding de la esquina sin
   empujar nada; la etiqueta deja sitio para no meterse debajo. */
.merchant-card[data-cat="restauracion"] {
  --cat: var(--cat-restauracion);
}

.merchant-card[data-cat="comercio"] {
  --cat: var(--cat-comercio);
}

.merchant-card[data-cat="servicios"] {
  --cat: var(--cat-servicios);
}

.merchant-card[data-cat="salud"] {
  --cat: var(--cat-salud);
}

.merchant-card[data-cat="vida-local"] {
  --cat: var(--cat-vida-local);
}

.cat-badge {
  position: absolute;
  top: 0.85rem;
  right: 0.85rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 999px;
  background-color: var(--cat);
  color: var(--cat-badge-ink);
  pointer-events: none;
}

.cat-badge svg {
  display: block;
  width: 15px;
  height: 15px;
}

.merchant-card[data-cat] .merchant-card__category {
  padding-right: 2.5rem;
}

/* En el Col·laborador (183ª, él: «ajustar un poquito más abajo la
   redondita de la categoria para que este a la misma altura que la franja
   de colaborador»): el disco se centra con la franja RELLENA, que abre la
   tarjeta. Su alto sale de sus propias medidas (línea de 1.6 × el cuerpo xs
   + 0.2rem arriba y abajo) y empieza en el padding de la tarjeta (1.15rem):
   si una cambia, el disco la sigue. Medido: 4,4 px más arriba sin esto. */
.merchant-card--collaborator .cat-badge {
  top: calc(1.15rem + (var(--font-size-xs) * 1.6 + 0.4rem - 1.75rem) / 2);
}

/* 9. PIE DE LA GUÍA (quién es esto + la segunda puerta del embudo)
   -------------------------------------------------------------------------- */
.app-footer {
  margin-top: 3rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--color-border);
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

/* El pont de les 15 arcades (24e, 178ª; «puente al finalizar las cards
   de los negocios OK»): la arcada cierra el listado, pegada a la raya del
   pie (el margen negativo se come el padding) y antes del reclamo. Dibujo
   (src/brandMarks.js: patrón de 25 px, 15 arcos a 375) en una tinta
   apagada; sin texto ni toque. */
.arcade {
  height: 22px;
  margin: -1.5rem 0 0.25rem;
  overflow: hidden;
  color: var(--arcade-ink);
}

.arcade__svg {
  display: block;
  width: 100%;
  height: 22px;
}

/* El reclamo del pie (#reclama). El CTA del carrusel ya va a «Com funcionen els Amics» (A3) */
.footer-claim {
  scroll-margin-top: 1.5rem;
  padding: 1.25rem 1.25rem 1.35rem;
  background-color: var(--color-bg-card);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  color: var(--color-text-secondary);
}

.footer-claim:target {
  border-color: var(--color-brand-primary);
  box-shadow: 0 0 0 4px var(--color-focus-ring);
}

/* #51: la puerta del ALTA. En móvil, ancho entero (pulgar); en pantalla
   ancha, a la medida del texto. */
.footer-claim__cta {
  margin-top: 1rem;
  /* A 320 el catalán no cabe en una línea: que el corte quede repartido */
  text-align: center;
  text-wrap: balance;
}

@media (min-width: 640px) {
  .footer-claim__cta {
    width: fit-content;
  }
}

.footer-claim__title {
  font-size: var(--font-size-lg);
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--color-text-primary);
  margin-bottom: 0.25rem;
}

.footer-credit {
  text-align: center;
}

.footer-credit a {
  color: var(--color-brand-text);
  font-weight: 600;
  text-decoration: none;
}

.footer-credit a:hover {
  text-decoration: underline;
}

/* 10. VOLVER ARRIBA Y LA LUPA
   -------------------------------------------------------------------------- */
/* Llevan un svg dentro (antes era el carácter ↑): se centra con flex.
   #62: la lupa es GEMELA de la flecha (mismas reglas, por eso comparten
   bloque) y va encima de ella. */
.back-to-top,
.search-fab {
  display: flex;
  align-items: center;
  justify-content: center;
  position: fixed;
  right: 1rem;
  bottom: 1rem;
  z-index: 90;
  width: var(--touch-target-min);
  height: var(--touch-target-min);
  border-radius: 9999px;
  border: 1px solid var(--color-border);
  background-color: var(--color-bg-card);
  color: var(--color-text-primary);
  font-size: 1.25rem;
  cursor: pointer;
  box-shadow: var(--shadow-md);
  opacity: 0;
  pointer-events: none;
  /* Escondidos, tampoco los alcanza el tabulador: un botón que no se ve y
     que mueve la caja «Buscar» sería una trampa con teclado. Al esconderse
     espera a que acabe el fundido; al aparecer es visible AL INSTANTE (sin
     eso, darle el foco nada más enseñarlo no tiene efecto). */
  visibility: hidden;
  transform: translateY(0.5rem);
  transition: opacity 0.2s ease, transform 0.2s ease, visibility 0s linear 0.2s;
}

/* M2 (200ª, los testers): la lupa en blanco se perdía al bajar → rellena
   de marca, para que se vea que BUSCA (la flecha sigue neutra). Icono
   blanco 5.9:1 · hover 7.6:1; el botón contra el papel 5.4:1. */
.search-fab {
  bottom: calc(1rem + var(--touch-target-min) + 0.5rem);
  border-color: var(--color-brand-primary);
  background-color: var(--color-brand-primary);
  color: #ffffff;
}

/* En oscuro el relleno de marca es claro: la tinta va oscura (7.1:1 ·
   hover 7.5:1) */
@media (prefers-color-scheme: dark) {
  .search-fab {
    color: #06283d;
  }
}

/* Y late UNA vez cada vez que aparece: la clase la pone app.js al bajar, y
   al volver a ponerla la animación arranca de nuevo. Un halo que se abre,
   sin tocar transform (es de la transición de aparecer). */
.search-fab--visible {
  animation: search-fab-pulse 0.9s ease-out 0.2s 1;
}

@keyframes search-fab-pulse {
  0% {
    box-shadow: var(--shadow-md), 0 0 0 0 var(--color-focus-ring);
  }

  100% {
    box-shadow: var(--shadow-md), 0 0 0 14px transparent;
  }
}

@media (prefers-reduced-motion: reduce) {
  .search-fab--visible {
    animation: none;
  }
}

.search-fab svg {
  width: 18px;
  height: 18px;
}

.back-to-top--visible,
.search-fab--visible {
  opacity: 1;
  pointer-events: auto;
  visibility: visible;
  transform: translateY(0);
  transition-delay: 0s;
}

.back-to-top:focus-visible,
.search-fab:focus-visible {
  outline: 3px solid var(--color-focus-outline);
  outline-offset: 2px;
}

@media (hover: hover) {
  .back-to-top:hover,
  .search-fab:hover {
    border-color: var(--color-border-strong);
    transform: translateY(-2px);
  }

  .search-fab:hover {
    border-color: var(--color-brand-hover);
    background-color: var(--color-brand-hover);
  }
}

/* LA RUEDA DE LETRAS (M2 pieza 3, 200ª; 202ª tras SU iPhone): la pinta
   letter-wheel.js. 7 letras a la vista (7 x 44 = 308), la del centro sobre
   una pastilla RELLENA de marca, con el mismo peso que la lupa (en oscuro,
   el fondo de tarjeta se camuflaba entre las tarjetas). La caja de fuera es
   invisible y algo más grande: es la zona de toque (el dedo caía fuera y
   movía la lista). 205ª: con 26 px de más a la izquierda robaba el pulgar
   al scroll por el borde → solo 8 px alrededor. Derecha, justo ENCIMA de la
   lupa y centrada con ella (Joaquim: «un poco por encima de la lupa»), sin
   pisarla.
   Escondida, fuera del tabulador (visibility), como la lupa. Mientras se
   arrastra, la página no se mueve (touch-action). */
.letter-wheel {
  position: fixed;
  /* La lupa acaba 120 px sobre el borde de abajo (1rem + 48 + 0.5rem + 48):
     la zona de toque empieza 4 px más arriba. */
  bottom: calc(1rem + 2 * var(--touch-target-min) + 0.5rem + 4px);
  right: 0;
  z-index: 90;
  display: flex;
  justify-content: flex-end;
  box-sizing: border-box;
  width: 78px;
  height: 328px;
  padding: 8px 10px 8px 8px;
  outline: none;
  cursor: grab;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
  opacity: 0;
  pointer-events: none;
  visibility: hidden;
  transition: opacity 0.2s ease, visibility 0s linear 0.2s;
}

.letter-wheel--visible {
  opacity: 1;
  pointer-events: auto;
  visibility: visible;
  transition-delay: 0s;
}

.letter-wheel:active {
  cursor: grabbing;
}

.letter-wheel__body {
  position: relative;
  width: 60px; /* con el borde (border-box): dentro, 56 x 308 */
  height: 312px;
  overflow: hidden;
  border: 2px solid var(--color-brand-primary);
  border-radius: 9999px;
  background-color: var(--color-bg-card);
  box-shadow: var(--shadow-md);
}

.letter-wheel:focus-visible .letter-wheel__body {
  outline: 3px solid var(--color-focus-outline);
  outline-offset: 2px;
}

.letter-wheel__window {
  position: absolute;
  top: 132px;
  right: 4px;
  left: 4px;
  height: 44px;
  border-radius: 9999px;
  background-color: var(--color-brand-primary);
}

.letter-wheel__track {
  position: absolute;
  top: 0;
  right: 0;
  left: 0;
  transition: transform 0.12s ease-out;
}

/* Arrastrando, la letra va pegada al dedo: sin transición (con ella llegaba
   tarde y se ponía al día a saltos). Al soltar, encaja con ella. */
.letter-wheel--dragging .letter-wheel__track {
  transition: none;
}

.letter-wheel__letter {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 44px;
  font-size: 1rem;
  font-weight: 700;
  color: var(--color-text-secondary);
}

/* La del centro, en la tinta de la lupa sobre el mismo relleno: blanco en
   claro, oscura en oscuro. */
.letter-wheel__letter[data-dist="0"] {
  font-size: 1.375rem;
  color: #ffffff;
}

@media (prefers-color-scheme: dark) {
  .letter-wheel__letter[data-dist="0"] {
    color: #06283d;
  }
}

/* Las lejanas, más pequeñas y en gris suave, SIN opacity (con opacity 0.6
   bajaban de AA). */
.letter-wheel__letter[data-dist="2"] {
  font-size: 0.875rem;
  color: var(--color-text-muted);
}

@media (prefers-reduced-motion: reduce) {
  .letter-wheel__track {
    transition: none;
  }
}

/* En un móvil pequeño (iPhone SE / mini: 375 px de ancho) la rueda de 7 se
   comía la pantalla (205ª, Joaquim: «solo en pantallas pequeñas»): 5 letras de
   36 px (5 x 36 = 180) y el cuerpo de 48 px, con 16 px a su derecha como
   la lupa (1rem): centrada con ella. La MISMA consulta que
   SMALL_QUERY en letter-wheel.js. Fondo opaco: translúcido, las letras
   sobre las tarjetas bajaban de AA. */
@media (max-width: 380px) {
  .letter-wheel {
    width: 72px;
    height: 200px;
    padding: 8px 16px 8px 8px;
  }

  .letter-wheel__body {
    width: 48px;
    height: 184px;
  }

  .letter-wheel__window {
    top: 72px;
    height: 36px;
  }

  .letter-wheel__letter {
    height: 36px;
    font-size: 0.9375rem;
  }

  .letter-wheel__letter[data-dist="0"] {
    font-size: 1.25rem;
  }

  .letter-wheel__letter[data-dist="2"] {
    font-size: 0.8125rem;
  }
}

/* En una pantalla baja (un móvil girado) no cabe. La grande: la zona de
   toque ocupa desde 124 px hasta 452 px sobre el borde de abajo, y arriba
   queda la caja «Buscar» fijada → hace falta un alto de al menos 540 px.
   La pequeña (205ª): de 124 a 324 px → le bastan 410. Con el tope de 540
   para las dos, en SU iPhone pequeño NO salía: Safari con sus barras (y con
   la pantalla ampliada) deja menos de 540 de alto. */
@media (max-height: 539px) and (min-width: 381px) {
  .letter-wheel {
    display: none;
  }
}

@media (max-height: 409px) {
  .letter-wheel {
    display: none;
  }
}

/* 11. BOTÓN PRINCIPAL (ficha, altas, páginas informativas)
   -------------------------------------------------------------------------- */
.btn-primary-cta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: var(--touch-target-min);
  padding: 0.75rem 1.25rem;
  font-weight: 700;
  font-size: var(--font-size-base);
  color: #ffffff;
  background-color: var(--color-brand-primary);
  border: 0;
  border-radius: 9999px;
  cursor: pointer;
  text-decoration: none;
  transition: background-color 0.2s ease, transform 0.15s ease;
}

/* En oscuro el relleno de marca es claro: la tinta va oscura (7.1:1) */
@media (prefers-color-scheme: dark) {
  .btn-primary-cta {
    color: #06283d;
  }
}

.btn-primary-cta:hover {
  background-color: var(--color-brand-hover);
}

.btn-primary-cta:focus-visible {
  outline: 3px solid var(--color-focus-outline);
  outline-offset: 3px;
}

/* 12. FICHA DE COMERCIO (/:lang/comercio/:slug)
   -------------------------------------------------------------------------- */
.merchant-page {
  max-width: 720px;
  padding-top: 1rem;
}

.merchant-page__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.25rem 1rem;
  text-align: left;
  margin-bottom: 1rem;
}

.merchant-page__back {
  display: inline-flex;
  align-items: center;
  min-height: var(--touch-target-min);
  color: var(--color-brand-text);
  font-size: var(--font-size-sm);
  font-weight: 600;
  text-decoration: none;
}

.merchant-page__back:hover {
  color: var(--color-brand-hover);
  text-decoration: underline;
}

.merchant-page__back:focus-visible {
  outline: 3px solid var(--color-focus-outline);
  outline-offset: 3px;
  border-radius: var(--radius-sm);
}

/* Una tarjeta sola y siempre a la vista: el content-visibility del listado
   aquí solo estorba (se maquetaba a 200 px y luego crecía, empujando el
   pie: CLS, Lighthouse 145ª). */
.merchant-page__card {
  margin-top: 0.5rem;
  padding: 1.5rem 1.4rem 1.6rem;
  content-visibility: visible;
}

.merchant-page__card .merchant-card__title {
  font-size: var(--font-size-xl);
  letter-spacing: -0.02em;
  line-height: 1.15;
}

.merchant-page__category {
  margin: 0.25rem 0 0.5rem;
  color: var(--color-text-muted);
  font-size: var(--font-size-xs);
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.merchant-page__actions {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-top: 1rem;
}

@media (min-width: 30rem) {
  .merchant-page__actions {
    flex-direction: row;
    flex-wrap: wrap;
  }
}

/* La oferta viva del negocio en su ficha (T3, 69ª): entre los distintivos
   y los botones. Las mismas piezas que la tarjeta de la página de ofertas
   (eyebrow, texto, detalle, «Fins al · Destacada», estas dos últimas con
   sus clases de allí); la de pago se enciende con el lavado terra, como
   allí y como la tarjeta de la portada. */
.merchant-offer {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  min-width: 0;
  margin-top: 1rem;
  padding: 0.9rem 1rem 1rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
}

.merchant-offer--featured {
  background-color: var(--color-terra-wash);
  border-color: var(--color-terra-border);
}

.merchant-offer__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  color: var(--color-text-muted);
  font-size: var(--font-size-xs);
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.merchant-offer__title {
  font-size: var(--font-size-lg);
  font-weight: 700;
  line-height: 1.25;
  color: var(--color-text-primary);
  overflow-wrap: anywhere;
}

.merchant-offer--featured .merchant-offer__title {
  color: var(--color-terra-strong);
}

.merchant-offer__sub {
  font-size: var(--font-size-sm);
  color: var(--color-text-secondary);
  overflow-wrap: anywhere;
}

.merchant-page__footer {
  margin-top: 1.75rem;
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  line-height: var(--line-height-base);
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.merchant-page__all {
  display: inline-flex;
  align-items: center;
  min-height: var(--touch-target-min);
  color: var(--color-brand-text);
  font-weight: 600;
  text-decoration: none;
}

.merchant-page__all:hover {
  color: var(--color-brand-hover);
  text-decoration: underline;
}

.merchant-page__all:focus-visible {
  outline: 3px solid var(--color-focus-outline);
  outline-offset: 3px;
  border-radius: var(--radius-sm);
}

/* 12b. LA PÁGINA DE OFERTAS (tramo 1b, T2): el armazón de la ficha (720 px,
   cabecera y pie) y una lista de tarjetas, una columna en móvil y dos desde
   40 rem. Las píldoras (.chip) y los botones (.btn-call, .btn-whatsapp)
   son los de la guía; aquí solo lo que es nuevo de verdad.
   -------------------------------------------------------------------------- */
.offers-page__title {
  font-size: var(--font-size-xl);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.15;
  color: var(--color-text-primary);
}

.offers-page__lead {
  margin: 0.4rem 0 1rem;
  color: var(--color-text-secondary);
}

/* EL ESPECIAL (E1 ④, 102ª): bajo «Del DD/MM al DD/MM», el detalle del
   acto y «Més informació» a su web; el resto, el molde de Ofertes. */
.special-page__detail {
  margin-top: -0.6rem;
}

.special-page__more {
  margin: -0.5rem 0 1rem;
}

.special-page__more a {
  min-height: var(--touch-target-min);
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  color: var(--color-brand-text);
  font-weight: 600;
}

.special-page__more a:hover {
  color: var(--color-brand-hover);
}

.offers-filters {
  margin-bottom: 1rem;
}

.offers-list {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0.9rem;
}

@media (min-width: 40rem) {
  .offers-list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.offer-card {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  min-width: 0;
  padding: 1.1rem 1.1rem 1.2rem;
  background-color: var(--color-bg-card);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  /* La tarjeta entera lleva a la ficha (offers-page.js): mano y levantada
     al pasar el raton, como la tarjeta «Ofertes» de la portada */
  cursor: pointer;
  transition:
    transform 0.15s ease,
    box-shadow 0.2s ease,
    border-color 0.2s ease;
}

@media (hover: hover) {
  .offer-card:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-md);
    border-color: var(--color-border-strong);
  }

  /* La de pago conserva su marco calido al levantarse */
  .offer-card--featured:hover {
    border-color: var(--color-terra-border);
  }

  /* Y la de la casa, el verde del sello */
  .offer-card--house:hover {
    border-color: var(--color-ok-border);
  }
}

/* Las píldoras esconden tarjetas: el atributo manda sobre el grid */
.offer-card[hidden] {
  display: none;
}

/* De pago: encendida como la tarjeta de la portada */
.offer-card--featured {
  background-color: var(--color-terra-wash);
  border-color: var(--color-terra-border);
}

/* La tarjeta de la casa (24d, 176ª): el gancho al sello gratis, con el
   verde del sello («ok», como .badge--verified) y nunca el calido de pago.
   Es un <a> entero (offersPageView.js): sin subrayado ni azul de enlace */
.offer-card--house {
  color: inherit;
  text-decoration: none;
  background-image: linear-gradient(var(--color-ok-bg), var(--color-ok-bg));
  border-color: var(--color-ok-border);
  /* Fuera de la rejilla (solo con 0 ofertas): su aire con «Avui no hi ha ofertes» */
  margin-bottom: 0.9rem;
}

.offer-card--house:focus-visible {
  outline: 3px solid var(--color-focus-outline);
  outline-offset: 2px;
}

.offer-card__house-title {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  color: var(--color-ok-text);
}

.offer-card__house-cta {
  align-self: flex-start;
  margin-top: 0.5rem;
}

.offer-card__eyebrow {
  color: var(--color-text-muted);
  font-size: var(--font-size-xs);
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

/* La marca de pago de un anuncio de local (LOCALS v1, L2): arriba, donde
   la oferta lleva su categoria, y del color de «Destacada» */
.offer-card__ad {
  color: var(--color-terra-strong);
}

.offer-card__name {
  font-size: var(--font-size-sm);
  font-weight: 600;
  color: var(--color-text-secondary);
}

.offer-card__name a {
  color: inherit;
  text-decoration: none;
}

.offer-card__name a:hover {
  color: var(--color-brand-text);
  text-decoration: underline;
}

.offer-card__name a:focus-visible {
  outline: 3px solid var(--color-focus-outline);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

.offer-card__title {
  font-size: var(--font-size-lg);
  font-weight: 700;
  line-height: 1.25;
  color: var(--color-text-primary);
  overflow-wrap: anywhere;
}

.offer-card--featured .offer-card__title {
  color: var(--color-terra-strong);
}

.offer-card__sub {
  font-size: var(--font-size-sm);
  color: var(--color-text-secondary);
  overflow-wrap: anywhere;
}

.offer-card__until {
  font-size: var(--font-size-xs);
  color: var(--color-text-secondary);
}

.offer-card__featured {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  color: var(--color-terra-strong);
}

.offer-card__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 0.5rem;
}

.offer-card__actions .btn-whatsapp,
.offer-card__actions .btn-call {
  margin-top: 0;
}

/* «Comparteix» es un <button> con la pinta de .btn-call; sale escondido y
   share.js lo enciende si el navegador sabe compartir o copiar */
.btn-share {
  border: 0;
  font-family: inherit;
  cursor: pointer;
}

.btn-share[hidden] {
  display: none;
}

.btn-share--copied {
  background-color: var(--color-brand-wash);
  color: var(--color-badge-text);
}

.offers-empty {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 1.25rem;
  border: 1px dashed var(--color-border-strong);
  border-radius: var(--radius-lg);
  color: var(--color-text-secondary);
  font-weight: 600;
}

.offers-claim {
  margin-top: 1.5rem;
}

/* Bajo el botón del anzuelo (AUTOSERVICIO T2): «Com funcionen les ofertes»
   y el alta para quien no sale, dos enlaces de texto que parten a 320 */
.footer-claim__links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.25rem;
  margin-top: 0.85rem;
  font-size: var(--font-size-sm);
}

.footer-claim__links a {
  min-height: var(--touch-target-min);
  display: inline-flex;
  align-items: center;
  color: var(--color-brand-text);
  font-weight: 600;
  text-underline-offset: 0.15em;
}

.footer-claim__links a:hover {
  color: var(--color-brand-hover);
}

/* 13. «ÉS TEU, AQUEST NEGOCI?» — el anzuelo del embudo (y ForgeBio)
   -------------------------------------------------------------------------- */
.page-notice {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.75rem 1rem;
  margin-bottom: 1rem;
  border-radius: var(--radius-md);
  font-weight: 600;
}

.page-notice--ok {
  background-color: var(--color-ok-bg);
  color: var(--color-ok-text);
  border: 1px solid var(--color-ok-border);
}

.page-notice--error {
  background-color: var(--color-error-bg);
  color: var(--color-error-text);
  border: 1px solid var(--color-error-border);
}

/* LA PUERTA, EN LA FICHA (M5, pieza 1, 113ª): la ficha es del vecino y lo
   del titular vive en SU página. Justo bajo la caja, un recuadro fino con la
   pregunta, una línea y la flecha: discreta, pero un objetivo entero (≥ 48
   px). El marco es adorno (lo que dice la puerta es el texto): pregunta
   13,6:1 · línea 6,9:1 · flecha 6,8:1 sobre el papel (oscuro: 16,4 · 10,1 ·
   9,1). */
.owner-door {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-top: 0.75rem;
  padding: 0.7rem 1rem;
  min-height: var(--touch-target-min);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  color: var(--color-text-secondary);
  text-decoration: none;
  font-size: var(--font-size-sm);
  line-height: 1.35;
}

.owner-door:hover {
  border-color: var(--color-border-strong);
  color: var(--color-text-primary);
}

.owner-door:focus-visible {
  outline: 3px solid var(--color-focus-outline);
  outline-offset: 3px;
}

.owner-door__q {
  display: block;
  color: var(--color-text-primary);
  font-weight: 700;
}

.owner-door__arrow {
  flex: none;
  color: var(--color-brand-text);
  font-weight: 700;
  font-size: var(--font-size-lg);
}

/* LA PÁGINA DEL TITULAR (M5, pieza 3, 114ª): en lugar de la caja de la
   ficha, su entrada — la cejilla «Per al titular», «És teu, ‹nom›?», la
   entradilla y el camino a la ficha tal como la ve el vecino. Cejilla
   5,2:1 · entradilla 6,9:1 · «Veure la fitxa» 6,8:1 sobre el papel (oscuro:
   6,5 · 10,1 · 9,1). El nombre largo parte donde haga falta: a 320 no empuja. */
.owner-page__eyebrow {
  margin-top: 1rem;
  color: var(--color-text-muted);
  font-size: var(--font-size-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.owner-page__title {
  margin-top: 0.2rem;
  font-size: var(--font-size-xl);
  font-weight: 800;
  letter-spacing: -0.01em;
  line-height: 1.2;
  color: var(--color-text-primary);
  overflow-wrap: anywhere;
}

.owner-page__lead {
  margin-top: 0.4rem;
  color: var(--color-text-secondary);
  font-size: var(--font-size-sm);
}

.owner-page__see {
  display: inline-flex;
  align-items: center;
  min-height: var(--touch-target-min);
  color: var(--color-brand-text);
  font-weight: 600;
  font-size: var(--font-size-sm);
  text-decoration: none;
}

.owner-page__see:hover {
  color: var(--color-brand-hover);
  text-decoration: underline;
}

.owner-page__see:focus-visible {
  outline: 3px solid var(--color-focus-outline);
  outline-offset: 3px;
  border-radius: var(--radius-sm);
}

.claim-card {
  margin-top: 1.5rem;
  padding: 1.35rem 1.4rem 1.1rem;
  background-color: var(--color-bg-card);
  background-image:
    radial-gradient(28rem 12rem at 100% -2rem, rgba(14, 116, 180, 0.1), transparent 60%);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}

.claim-card__title {
  font-size: var(--font-size-lg);
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--color-text-primary);
}

.claim-card__pitch {
  margin-top: 0.35rem;
  color: var(--color-text-secondary);
  font-size: var(--font-size-sm);
}

.request-form {
  margin-top: 1rem;
  accent-color: var(--color-brand-primary);
}

/* Las DOS PUERTAS de la tarjeta son los radios del formulario: el radio va
   oculto (pero enfocable y legible por el lector) y su etiqueta lleva el
   aspecto — botón para reclamar, enlace para la baja. */
.request-form__kind {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.25rem;
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.request-kind {
  position: relative;
  cursor: pointer;
}

.request-kind input {
  position: absolute;
  inset: 0;
  margin: 0;
  opacity: 0;
  pointer-events: none;
}

.request-kind--claim {
  align-self: stretch;
}

.request-kind--removal span {
  display: inline-flex;
  align-items: center;
  min-height: var(--touch-target-min);
  padding-inline: 0.5rem;
  font-size: var(--font-size-sm);
  color: var(--color-text-secondary);
  text-decoration: underline;
}

.request-kind--removal:hover span {
  color: var(--color-text-primary);
}

.request-kind input:focus-visible + span {
  outline: 3px solid var(--color-focus-outline);
  outline-offset: 3px;
}

/* Elegida otra puerta (la baja, «El vull», una oferta o un local), el botón
   de reclamar se queda en contorno y la baja pasa a negrita: se ve cuál
   está elegida sin leer el formulario. */
.request-form:has(.request-kind--removal input:checked, .request-kind--forgebio input:checked, .request-kind--offer input:checked, .request-kind--local input:checked)
  .request-kind--claim
  span {
  color: var(--color-brand-text);
  background-color: transparent;
  box-shadow: inset 0 0 0 2px currentColor;
}

.request-form:has(.request-kind--removal input:checked, .request-kind--forgebio input:checked, .request-kind--offer input:checked, .request-kind--local input:checked)
  .request-kind--claim:hover
  span {
  background-color: var(--color-brand-wash);
}

.request-kind--removal input:checked + span {
  font-weight: 700;
  color: var(--color-text-primary);
}

/* EL PRIMER BLOQUE de la página del titular (114ª-115ª): «La teva fitxa» ·
   «Verifica la teva fitxa» [Gratis] y su promesa (o, con el sello, «Ja està
   verificada» + el sello), «Verificar la fitxa» y «o demanar la baixa»
   JUSTO debajo. Las piezas de las otras cajas (cejilla, título, promesa),
   con la cejilla en el azul de la marca: la terra es de lo de PAGO. */
.owner-claim {
  align-self: stretch;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  text-align: center;
}

.owner-claim .claim-card__pitch {
  margin: 0;
}

.owner-claim .proposal-offer__eyebrow {
  color: var(--color-brand-text);
}

/* LA PASTILLA DEL PRECIO (MODO FOCO, 114ª): cada caja enseña lo que cuesta
   antes de elegir, y su «Estàs …» lo repite. El texto lo pone el servidor
   desde config/pricing.js (sin precio, sin pastilla). Tinta 15:1 claro ·
   14,5:1 oscuro; el marco es adorno. Si no cabe, parte dentro: no empuja. */
.price-chip {
  display: inline-block;
  align-self: center;
  width: max-content;
  max-width: 100%;
  margin: 0.1rem auto 0.25rem;
  padding: 0.15rem 0.7rem;
  border: 1px solid var(--color-border-strong);
  border-radius: 999px;
  font-size: var(--font-size-xs);
  font-weight: 700;
  color: var(--color-text-primary);
}

/* LA ÚLTIMA PUERTA (114ª; antes, la tercera): la vista previa del perfil a
   ForgeBio.io y «El vull». Va tras la línea discontinua, con peso propio
   (aviso, título, qué es y móvil).
   Elegir RECLAMAR la pliega a su puerta, en una línea: el formulario queda
   pegado a su botón y se puede cambiar de idea sin perder lo escrito.
   Elegir la BAJA la quita: a quien se va no se le ofrece nada. Sin `:has()`
   sale entera, como el resto del formulario. */
.forgebio-offer {
  align-self: stretch;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
  margin-top: 0.75rem;
  padding-top: 1rem;
  text-align: center;
  border-top: 1px dashed var(--color-border-strong);
}

.forgebio-offer__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: var(--font-size-xs);
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fb-accent-text);
}

.forgebio-offer__title {
  font-size: var(--font-size-base);
  font-weight: 800;
  line-height: 1.3;
  color: var(--color-text-primary);
}

/* Qué es ForgeBio, en una frase (114ª): quien no lo conoce no sabe qué pide */
.owner-fb-what {
  margin: 0.25rem 0 0.5rem;
  color: var(--color-text-secondary);
  font-size: var(--font-size-sm);
  text-align: center;
}

.forgebio-offer__note {
  max-width: 30ch;
  font-size: var(--font-size-xs);
  color: var(--color-text-secondary);
}

/* El móvil es un dibujo (aria-hidden): la monoespaciada del sistema, como
   los perfiles ForgeBio, y 0 fuentes de fuera */
.forgebio-phone {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.3rem;
  width: 15rem;
  max-width: 100%;
  padding: 1.4rem 0.9rem 1rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
  color: var(--fb-phone-text);
  background: linear-gradient(180deg, var(--fb-wash), var(--fb-phone-bg) 45%);
  border: 1px solid var(--fb-phone-border);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-md);
}

.forgebio-phone__avatar {
  display: grid;
  place-items: center;
  width: 4rem;
  height: 4rem;
  margin-bottom: 0.35rem;
  font-size: 1.25rem;
  font-weight: 800;
  color: var(--fb-avatar-text);
  background-color: var(--fb-avatar-bg);
  border: 3px solid var(--fb-ring);
  border-radius: 50%;
  box-shadow: 0 0 14px var(--fb-glow);
}

.forgebio-phone__name {
  font-size: 0.95rem;
  font-weight: 800;
  line-height: 1.25;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  overflow-wrap: anywhere;
}

.forgebio-phone__meta {
  display: flex;
  flex-direction: column;
  font-size: 0.72rem;
  line-height: 1.35;
  color: var(--fb-phone-meta);
}

.forgebio-phone__links {
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  width: 100%;
  margin-top: 0.6rem;
}

/* Icono a la izquierda y texto centrado, como los botones de ForgeBio */
.forgebio-phone__btn {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 2.5rem;
  padding: 0 2rem;
  font-size: 0.78rem;
  font-weight: 700;
  background-color: var(--fb-phone-btn);
  border: 1px solid var(--fb-btn-line);
  border-radius: 0.65rem;
}

.forgebio-phone__btn .icon-slot {
  position: absolute;
  left: 0.75rem;
  color: var(--fb-accent);
}

.forgebio-phone__pill {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  margin-top: 0.6rem;
  padding: 0.35rem 0.75rem;
  font-size: 0.68rem;
  font-weight: 700;
  border: 1px solid var(--fb-line);
  border-radius: 999px;
}

.forgebio-phone__pill .icon-slot {
  color: var(--fb-bolt);
}

.forgebio-phone__pill b {
  color: var(--fb-accent-text);
}

/* «El vull, gratis»: la puerta, con el verde de ForgeBio */
.request-kind--forgebio {
  align-self: stretch;
}

.forgebio-offer__cta {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: var(--touch-target-min);
  padding: 0.5rem 1rem;
  font-size: var(--font-size-base);
  font-weight: 800;
  color: var(--fb-cta-text);
  background-color: var(--fb-cta-bg);
  border-radius: var(--radius-md);
  transition: background-color 0.15s ease;
}

.request-kind--forgebio:hover .forgebio-offer__cta {
  background-color: var(--fb-cta-hover);
}

.forgebio-offer__full,
.forgebio-offer__compact {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
}

.forgebio-offer__compact {
  display: none;
}

/* Elegida RECLAMAR: la oferta se queda en su puerta, en contorno y en una
   línea («Afegeix-hi el perfil…»). */
.request-form:has(.request-kind--claim input:checked) .forgebio-offer > :not(.request-kind--forgebio),
.request-form:has(.request-kind--claim input:checked) .forgebio-offer__full {
  display: none;
}

/* En texto corrido (no flex): a 375 parte en dos líneas y el rayo se
   quedaba colgando a la izquierda; así va dentro y las líneas equilibradas */
.request-form:has(.request-kind--claim input:checked) .forgebio-offer__compact {
  display: block;
  text-wrap: balance;
}

.forgebio-offer__compact .icon-slot {
  margin-right: 0.35rem;
}

.request-form:has(.request-kind--claim input:checked) .forgebio-offer__cta {
  font-size: var(--font-size-sm);
  font-weight: 700;
  color: var(--fb-accent-text);
  background-color: transparent;
  box-shadow: inset 0 0 0 2px currentColor;
}

/* El lavado de ForgeBio y no el de «ok»: con ese, el texto bajaba a 4,45:1 */
.request-form:has(.request-kind--claim input:checked) .request-kind--forgebio:hover .forgebio-offer__cta {
  background-color: var(--fb-wash); /* 4,76:1 claro · 11,4:1 oscuro */
}

/* Elegida la BAJA: fuera */
.request-form:has(.request-kind--removal input:checked) .forgebio-offer {
  display: none;
}

/* El resto del formulario sale al ELEGIR. Sin `:has()` sale siempre. */
.request-form__body {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 0.75rem 0 1rem;
}

@supports selector(:has(*)) {
  .request-form__body {
    display: none;
  }

  .request-form:has(input[name="kind"]:checked) .request-form__body {
    display: flex;
  }
}

/* Qué se está pidiendo, dicho arriba del todo (solo con `:has()`) */
.request-form__mode {
  display: none;
  font-weight: 700;
}

.request-form:has(input[name="kind"][value="claim"]:checked) .request-form__mode--claim,
.request-form:has(input[name="kind"][value="removal"]:checked) .request-form__mode--removal,
.request-form:has(input[name="kind"][value="forgebio"]:checked) .request-form__mode--forgebio {
  display: block;
}

/* «Estàs …» (MODO FOCO, 114ª): el título, la pastilla y una línea, con y
   sin JS. Con JS recibe el foco al elegir (tabindex=-1: así el lector lo
   dice); es el destino, no un control, y el anillo alrededor del bloque
   sobra (como #contingut). Título 15:1 · línea 7,7:1 en la tarjeta (oscuro:
   14,5 · 9); sobre su lavado, la línea 6,7 · 8,2. */
.request-form__mode .focus-title {
  font-size: var(--font-size-lg);
  font-weight: 800;
  line-height: 1.25;
  color: var(--color-text-primary);
}

.request-form__mode .price-chip {
  align-self: flex-start;
  margin: 0.4rem 0 0.2rem;
}

.request-form__mode .focus-line {
  margin: 0 0 0.5rem;
  font-weight: 400;
  font-size: var(--font-size-sm);
  color: var(--color-text-secondary);
}

.request-form__mode:focus {
  outline: none;
}

/* EL MODO FOCO (114ª-116ª): lo ENCIENDE public/js/owner-page.js con la
   clase .request-form--focus (en la página del titular y si el navegador
   sabe `:has()`). ELEGIDA una puerta, las demás DESAPARECEN: se esconde el
   grupo entero y arriba del cuerpo salen «← Triar una altra cosa» y su
   «Estàs …» (mismo formulario, mismo POST). Elegida, no solo marcada (29/10,
   «Flechas solo mueven»): la marca .request-form--chosen la pone el JS al
   elegir (clic, toque, Espacio, Intro) y la quita «← Triar…»; una flecha
   marca sin elegir y deja el pliegue. La puerta marcada se sigue pidiendo
   (`:has()`): sin ninguna, nada se esconde aunque la marca se quede. Sin la
   clase (sin JS), el pliegue de este bloque, que NO se borra: es el
   respaldo y deja cambiar de idea sin perder lo escrito. «← Triar…» es un
   botón que solo sirve con JS (desmarca la puerta, no borra nada): oculto
   si no. Marca 7,6:1 en la tarjeta · 6,6:1 en su lavado (oscuro: 8,1 · 7,4). */
.focus-back {
  display: none;
  align-self: flex-start;
  align-items: center;
  min-height: var(--touch-target-min);
  padding: 0;
  font: inherit;
  font-size: var(--font-size-sm);
  font-weight: 600;
  color: var(--color-brand-text);
  background: none;
  border: 0;
  cursor: pointer;
}

.focus-back:hover {
  color: var(--color-brand-hover);
  text-decoration: underline;
}

.focus-back:focus-visible {
  outline: 3px solid var(--color-focus-outline);
  outline-offset: 3px;
  border-radius: var(--radius-sm);
}

.request-form--focus.request-form--chosen:has(input[name="kind"]:checked) .request-form__kind {
  display: none;
}

.request-form--focus.request-form--chosen:has(input[name="kind"]:checked) .focus-back {
  display: inline-flex;
}

.request-form label {
  font-weight: 600;
  font-size: var(--font-size-sm);
}

.request-form__field {
  min-height: var(--touch-target-min);
  padding: 0.5rem 0.75rem;
  font: inherit;
  color: var(--color-text-primary);
  background-color: var(--color-bg-base);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-md);
}

.request-form__field:focus {
  outline: none;
  border-color: var(--color-brand-primary);
  box-shadow: 0 0 0 3px var(--color-focus-ring);
}

.request-form__consent {
  display: flex;
  gap: 0.5rem;
  align-items: baseline;
  font-weight: 500;
}

/* La casilla de propuestas es OPCIONAL: menos peso que la del trámite. */
.request-form__leads {
  font-weight: 400;
  color: var(--color-text-muted);
}

/* Solo tiene sentido al reclamar: al pedir la baja desaparece (sin
   JavaScript). Es cosmético: el servidor la ignora en una baja. */
.request-form:has(input[name="kind"][value="removal"]:checked) .request-form__leads {
  display: none;
}

.request-form__hint {
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}

/* 198a: el aviso de owner-page.js cuando baja «Fins quan» al tope de la
   opcion. Vacio no ocupa sitio; con texto, el color del texto (no el
   apagado de la pista): es algo que ha cambiado y hay que leerlo */
.request-form__adjusted {
  color: var(--color-text-primary);
  font-size: var(--font-size-sm);
  font-weight: 600;
}

.request-form__adjusted:empty {
  display: none;
}

/* El campo-cebo: fuera de la vista y del tabulador, no display:none */
.hp-wrap {
  position: absolute;
  left: -9999px;
  top: auto;
}

/* LA CUARTA PUERTA (AUTOSERVICIO T2): «Proposar una oferta» y, en una
   inmobiliaria, la quinta, «Anunciar un local». Tras el primer bloque
   (114ª; antes, tras ForgeBio y la última), con su pastilla del precio, la
   línea discontinua, la cejilla terra de las ofertas y la
   comparación corta. Elegir RECLAMAR o «El vull» la pliega a sus puertas,
   más pequeñas; elegir la BAJA la quita. Sin `:has()` sale entera.
   Todas las reglas de aquí abajo van APARTE de las de ForgeBio: el test de
   la ficha fija aquellas por su letra. */
.proposal-offer {
  align-self: stretch;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
  margin-top: 0.75rem;
  padding-top: 1rem;
  text-align: center;
  border-top: 1px dashed var(--color-border-strong);
}

.proposal-offer__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: var(--font-size-xs);
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--color-terra-text);
}

.proposal-offer__title {
  font-size: var(--font-size-base);
  font-weight: 800;
  line-height: 1.3;
  color: var(--color-text-primary);
}

/* La comparación: una línea por plan, a la izquierda y con su viñeta (el
   reset quita las listas) */
.proposal-offer__plans {
  align-self: stretch;
  padding-left: 1.1rem;
  list-style: disc;
  text-align: left;
  font-size: var(--font-size-sm);
  color: var(--color-text-secondary);
}

.proposal-offer__plans li + li {
  margin-top: 0.3rem;
}

.request-kind--offer,
.request-kind--local {
  align-self: stretch;
}

/* El botón de cada puerta: terra en contorno (ni el azul de reclamar ni el
   verde de ForgeBio). Texto terra sobre tarjeta: 6:1 claro · 8,7:1 oscuro;
   al pasar, su lavado (7:1). Elegida, se rellena: blanco sobre terra
   6,6:1 en claro; en oscuro el terra es claro y la tinta va oscura (10,5:1). */
.proposal-offer__cta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.45rem;
  min-height: var(--touch-target-min);
  padding: 0.5rem 1rem;
  font-size: var(--font-size-base);
  font-weight: 800;
  color: var(--color-terra-text);
  background-color: transparent;
  border-radius: var(--radius-md);
  box-shadow: inset 0 0 0 2px currentColor;
  text-wrap: balance;
  transition: background-color 0.15s ease;
}

.request-kind--offer:hover .proposal-offer__cta,
.request-kind--local:hover .proposal-offer__cta {
  color: var(--color-terra-strong);
  background-color: var(--color-terra-wash);
}

.request-kind--offer input:checked + .proposal-offer__cta,
.request-kind--local input:checked + .proposal-offer__cta {
  color: #ffffff;
  background-color: var(--color-terra-text);
}

@media (prefers-color-scheme: dark) {
  .request-kind--offer input:checked + .proposal-offer__cta,
  .request-kind--local input:checked + .proposal-offer__cta {
    color: #1f1208;
  }
}

.proposal-offer__note {
  font-size: var(--font-size-xs);
  color: var(--color-text-secondary);
}

.proposal-offer__note a {
  color: var(--color-brand-text);
  font-weight: 600;
  text-underline-offset: 0.15em;
}

.proposal-offer__note a:hover {
  color: var(--color-brand-hover);
}

/* Elegida RECLAMAR o «El vull»: la oferta se queda en sus puertas, más
   pequeñas (como ForgeBio al reclamar). */
.request-form:has(.request-kind--claim input:checked, .request-kind--forgebio input:checked) .proposal-offer > :not(.request-kind--offer, .request-kind--local) {
  display: none;
}

.request-form:has(.request-kind--claim input:checked, .request-kind--forgebio input:checked) .proposal-offer__cta {
  font-size: var(--font-size-sm);
  font-weight: 700;
}

/* Elegida la BAJA: fuera, como ForgeBio */
.request-form:has(.request-kind--removal input:checked) .proposal-offer {
  display: none;
}

/* Elegida una OFERTA o un LOCAL: ForgeBio se pliega a su puerta, en
   contorno (la misma regla que al reclamar, escrita aparte). */
.request-form:has(.request-kind--offer input:checked, .request-kind--local input:checked) .forgebio-offer > :not(.request-kind--forgebio),
.request-form:has(.request-kind--offer input:checked, .request-kind--local input:checked) .forgebio-offer__full {
  display: none;
}

.request-form:has(.request-kind--offer input:checked, .request-kind--local input:checked) .forgebio-offer__compact {
  display: block;
  text-wrap: balance;
}

.request-form:has(.request-kind--offer input:checked, .request-kind--local input:checked) .forgebio-offer__cta {
  font-size: var(--font-size-sm);
  font-weight: 700;
  color: var(--fb-accent-text);
  background-color: transparent;
  box-shadow: inset 0 0 0 2px currentColor;
}

.request-form:has(.request-kind--offer input:checked, .request-kind--local input:checked) .request-kind--forgebio:hover .forgebio-offer__cta {
  background-color: var(--fb-wash);
}

/* Qué se está pidiendo, con oferta o local (solo con `:has()`, como los
   otros tres modos) */
.request-form:has(input[name="kind"][value="offer"]:checked) .request-form__mode--offer,
.request-form:has(input[name="kind"][value="local"]:checked) .request-form__mode--local {
  display: block;
}

/* «F1 bis» (163ª) · La ficha RELLENA: solo con verificar / corregir o «El
   vull» elegidos (sin `:has()` sale siempre, como el resto del cuerpo). Los
   campos son los del alta: su caja (.add-business__group) y las reglas del
   desplegable y de la pantalla estrecha (H5), las MISMAS reglas que el
   alta: su selector lleva los dos formularios. */
.request-form__fix {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  min-width: 0;
}

@supports selector(:has(*)) {
  .request-form__fix {
    display: none;
  }

  .request-form:has(input[name="kind"][value="claim"]:checked) .request-form__fix,
  .request-form:has(input[name="kind"][value="forgebio"]:checked) .request-form__fix {
    display: flex;
  }
}

.request-form__fix-lead {
  margin: 0;
  color: var(--color-text-secondary);
  font-size: var(--font-size-sm);
}

/* La marca «Canviat · abans: … · Desfés» (owner-fix.js, solo con JS) bajo
   el campo que cambió. «Desfés» pesa como «← Triar una altra cosa». */
/* Texto corrido (no flex): con un «abans» largo se parte como una frase, sin
   dejar «Canviat ·» ni «· Desfés» sueltos en su línea. */
.fix-mark {
  display: block;
  margin: 0;
  min-width: 0;
  color: var(--color-text-secondary);
  font-size: var(--font-size-sm);
  overflow-wrap: anywhere;
}

/* El `display: block` de arriba le gana al `hidden` del navegador: sin esto,
   las marcas de los campos SIN cambiar también se ven (visto en el pane, 163ª). */
.fix-mark[hidden] {
  display: none;
}

.fix-mark__changed {
  font-weight: 700;
  color: var(--color-brand-text);
}

.fix-mark__undo {
  display: inline-flex;
  align-items: center;
  min-height: var(--touch-target-min);
  padding: 0;
  vertical-align: middle;
  font: inherit;
  font-weight: 600;
  color: var(--color-brand-text);
  background: none;
  border: 0;
  cursor: pointer;
}

.fix-mark__undo:hover {
  color: var(--color-brand-hover);
  text-decoration: underline;
}

.fix-mark__undo:focus-visible {
  outline: 3px solid var(--color-focus-outline);
  outline-offset: 3px;
  border-radius: var(--radius-sm);
}

/* Los campos de la propuesta: solo con oferta o local elegidos (sin
   `:has()` salen siempre, como el resto del cuerpo). En un local no hay
   plan: es de pago siempre. */
.request-form__proposal {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

@supports selector(:has(*)) {
  .request-form__proposal {
    display: none;
  }

  .request-form:has(input[name="kind"][value="offer"]:checked) .request-form__proposal,
  .request-form:has(input[name="kind"][value="local"]:checked) .request-form__proposal {
    display: flex;
  }
}

.request-form:has(input[name="kind"][value="local"]:checked) .request-form__plan {
  display: none;
}

.request-form__plan {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.request-form__plan legend {
  padding: 0;
  margin-bottom: 0.25rem;
  font-size: var(--font-size-sm);
  font-weight: 700;
}

/* Gratis / destacada: radios de verdad, a la vista, con su pulgar */
.request-form__radio {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  min-height: var(--touch-target-min);
  font-weight: 500;
}

/* En una propuesta el mensaje libre y la casilla de propuestas sobran: el
   servidor no los lee (T1). Fuera, sin JavaScript. */
.request-form:has(input[name="kind"][value="offer"]:checked) .request-form__leads,
.request-form:has(input[name="kind"][value="local"]:checked) .request-form__leads,
.request-form:has(input[name="kind"][value="offer"]:checked) label[for="rq-message"],
.request-form:has(input[name="kind"][value="local"]:checked) label[for="rq-message"],
.request-form:has(input[name="kind"][value="offer"]:checked) #rq-message,
.request-form:has(input[name="kind"][value="local"]:checked) #rq-message {
  display: none;
}

/* ------------------------------------------------------------------------
   AMICS (036, A3): la SEXTA puerta, «Fer-me Amic de la Guia»; desde la
   114ª, ANTES de ForgeBio (la última; rompe «la última» de la 90ª, avisado).
   Comparte la caja de las ofertas (.proposal-offer) y escribe lo suyo
   APARTE (los tests fijan las reglas de ofertas por su letra): la cejilla
   en el ámbar del distintivo (--color-featured-text: 6:1 claro · 9,8:1
   oscuro sobre tarjeta); el botón, terra como el resto de puertas de pago
   (jerarquía por peso, no por color nuevo). Elegida otra puerta, se pliega
   a su botón; elegida ella, pliega a las demás como lo hace reclamar.
   ------------------------------------------------------------------------ */
.proposal-offer__eyebrow--amic {
  color: var(--color-featured-text);
}

.request-kind--amic {
  align-self: stretch;
}

.request-kind--amic:hover .proposal-offer__cta {
  color: var(--color-terra-strong);
  background-color: var(--color-terra-wash);
}

.request-kind--amic input:checked + .proposal-offer__cta {
  color: #ffffff;
  background-color: var(--color-terra-text);
}

@media (prefers-color-scheme: dark) {
  .request-kind--amic input:checked + .proposal-offer__cta {
    color: #1f1208;
  }
}

/* Elegida otra puerta (reclamar, «El vull», una oferta o un local): la del
   Amic se queda en su botón, más pequeño. Reclamar y «El vull» pliegan ya
   toda .proposal-offer (regla de ofertas, arriba) y se llevan el botón del
   Amic: aquí se le devuelve, con la misma fuerza y detrás. */
.request-form:has(.request-kind--claim input:checked, .request-kind--forgebio input:checked, .request-kind--offer input:checked, .request-kind--local input:checked) .proposal-offer--amic > :not(.request-kind--amic) {
  display: none;
}

.request-form:has(.request-kind--claim input:checked, .request-kind--forgebio input:checked) .proposal-offer--amic > .request-kind--amic {
  display: block;
}

.request-form:has(.request-kind--claim input:checked, .request-kind--forgebio input:checked, .request-kind--offer input:checked, .request-kind--local input:checked) .proposal-offer__cta--amic {
  font-size: var(--font-size-sm);
  font-weight: 700;
}

/* Elegido el AMIC: las ofertas se quedan en sus botones, ForgeBio en su
   línea y «Reclamar» en contorno (lo mismo que al reclamar, escrito aparte). */
.request-form:has(.request-kind--amic input:checked) .proposal-offer:not(.proposal-offer--amic) > :not(.request-kind--offer, .request-kind--local) {
  display: none;
}

.request-form:has(.request-kind--amic input:checked) .proposal-offer:not(.proposal-offer--amic) .proposal-offer__cta {
  font-size: var(--font-size-sm);
  font-weight: 700;
}

.request-form:has(.request-kind--amic input:checked) .forgebio-offer > :not(.request-kind--forgebio),
.request-form:has(.request-kind--amic input:checked) .forgebio-offer__full {
  display: none;
}

.request-form:has(.request-kind--amic input:checked) .forgebio-offer__compact {
  display: block;
  text-wrap: balance;
}

.request-form:has(.request-kind--amic input:checked) .forgebio-offer__cta {
  font-size: var(--font-size-sm);
  font-weight: 700;
  color: var(--fb-accent-text);
  background-color: transparent;
  box-shadow: inset 0 0 0 2px currentColor;
}

.request-form:has(.request-kind--amic input:checked) .request-kind--forgebio:hover .forgebio-offer__cta {
  background-color: var(--fb-wash);
}

.request-form:has(.request-kind--amic input:checked) .request-kind--claim span {
  color: var(--color-brand-text);
  background-color: transparent;
  box-shadow: inset 0 0 0 2px currentColor;
}

.request-form:has(.request-kind--amic input:checked) .request-kind--claim:hover span {
  background-color: var(--color-brand-wash);
}

/* Qué se está pidiendo; y el mensaje libre y la casilla sobran (el
   servidor no los lee en un Amic), como en una propuesta. */
.request-form:has(input[name="kind"][value="amic"]:checked) .request-form__mode--amic {
  display: block;
}

.request-form:has(input[name="kind"][value="amic"]:checked) .request-form__leads,
.request-form:has(input[name="kind"][value="amic"]:checked) label[for="rq-message"],
.request-form:has(input[name="kind"][value="amic"]:checked) #rq-message {
  display: none;
}

/* ------------------------------------------------------------------------
   LA OFERTA EN UN ESPECIAL (E2 ②, 107ª): una puerta más DENTRO de la caja
   de las ofertas, entre «Proposar una oferta» y el local. Escribe lo suyo
   APARTE, como el Amic (los tests fijan las reglas de ofertas por su
   letra): el botón, terra como las otras puertas de pago. Elegida otra
   puerta, se queda en su botón; elegida ella, pliega a las demás como lo
   hace el Amic. Sus campos: los de la propuesta SIN plan ni fechas (son las
   del acto) y el acto, solo con ella; fuera mensaje y casilla.
   ------------------------------------------------------------------------ */
.request-kind--event_offer {
  align-self: stretch;
}

.request-kind--event_offer:hover .proposal-offer__cta {
  color: var(--color-terra-strong);
  background-color: var(--color-terra-wash);
}

.request-kind--event_offer input:checked + .proposal-offer__cta {
  color: #ffffff;
  background-color: var(--color-terra-text);
}

@media (prefers-color-scheme: dark) {
  .request-kind--event_offer input:checked + .proposal-offer__cta {
    color: #1f1208;
  }
}

/* Elegida otra puerta: reclamar, «El vull» y el Amic pliegan la caja de las
   ofertas a sus dos puertas de siempre (:not(oferta, local), arriba) y se
   llevan la suya: aquí se le devuelve, con la misma fuerza y detrás (con el
   Amic, su :not(.proposal-offer--amic) propio: si no, pierde). Ya se queda
   pequeña con las reglas de la caja. */
.request-form:has(.request-kind--claim input:checked, .request-kind--forgebio input:checked) .proposal-offer > .request-kind--event_offer,
.request-form:has(.request-kind--amic input:checked) .proposal-offer:not(.proposal-offer--amic) > .request-kind--event_offer {
  display: block;
}

/* Elegida ELLA: ForgeBio en su línea, el Amic en su botón y «Reclamar» en
   contorno (lo mismo que con una oferta o el Amic, escrito aparte). */
.request-form:has(.request-kind--event_offer input:checked) .forgebio-offer > :not(.request-kind--forgebio),
.request-form:has(.request-kind--event_offer input:checked) .forgebio-offer__full,
.request-form:has(.request-kind--event_offer input:checked) .proposal-offer--amic > :not(.request-kind--amic) {
  display: none;
}

.request-form:has(.request-kind--event_offer input:checked) .forgebio-offer__compact {
  display: block;
  text-wrap: balance;
}

.request-form:has(.request-kind--event_offer input:checked) .forgebio-offer__cta {
  font-size: var(--font-size-sm);
  font-weight: 700;
  color: var(--fb-accent-text);
  background-color: transparent;
  box-shadow: inset 0 0 0 2px currentColor;
}

.request-form:has(.request-kind--event_offer input:checked) .request-kind--forgebio:hover .forgebio-offer__cta {
  background-color: var(--fb-wash);
}

.request-form:has(.request-kind--event_offer input:checked) .proposal-offer__cta--amic {
  font-size: var(--font-size-sm);
  font-weight: 700;
}

.request-form:has(.request-kind--event_offer input:checked) .request-kind--claim span {
  color: var(--color-brand-text);
  background-color: transparent;
  box-shadow: inset 0 0 0 2px currentColor;
}

.request-form:has(.request-kind--event_offer input:checked) .request-kind--claim:hover span {
  background-color: var(--color-brand-wash);
}

/* Qué se está pidiendo; sus campos (los de la propuesta, con el acto si hay
   que elegirlo) y lo que sobra: plan, fechas, mensaje libre y casilla (el
   servidor no los lee). El acto, como el plan: radios en columna, sin marco;
   sin `:has()` sale siempre, como el resto de la propuesta. */
.request-form:has(input[name="kind"][value="event_offer"]:checked) .request-form__mode--event_offer {
  display: block;
}

.request-form__special {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.request-form__special legend {
  padding: 0;
  margin-bottom: 0.25rem;
  font-size: var(--font-size-sm);
  font-weight: 700;
}

@supports selector(:has(*)) {
  .request-form__special {
    display: none;
  }

  .request-form:has(input[name="kind"][value="event_offer"]:checked) .request-form__proposal,
  .request-form:has(input[name="kind"][value="event_offer"]:checked) .request-form__special {
    display: flex;
  }
}

.request-form:has(input[name="kind"][value="event_offer"]:checked) .request-form__plan,
.request-form:has(input[name="kind"][value="event_offer"]:checked) label[for="rq-offer-starts"],
.request-form:has(input[name="kind"][value="event_offer"]:checked) #rq-offer-starts,
.request-form:has(input[name="kind"][value="event_offer"]:checked) #rq-offer-starts + .request-form__hint,
.request-form:has(input[name="kind"][value="event_offer"]:checked) label[for="rq-offer-ends"],
.request-form:has(input[name="kind"][value="event_offer"]:checked) #rq-offer-ends,
.request-form:has(input[name="kind"][value="event_offer"]:checked) #rq-offer-ends + .request-form__hint,
.request-form:has(input[name="kind"][value="event_offer"]:checked) .request-form__adjusted,
.request-form:has(input[name="kind"][value="event_offer"]:checked) .request-form__leads,
.request-form:has(input[name="kind"][value="event_offer"]:checked) label[for="rq-message"],
.request-form:has(input[name="kind"][value="event_offer"]:checked) #rq-message {
  display: none;
}

/* 14. PÁGINA 404
   -------------------------------------------------------------------------- */
.not-found__card {
  cursor: default;
  text-align: center;
}

.not-found__card:hover {
  transform: none;
}

.not-found__code {
  font-size: clamp(3rem, 2.5rem + 3vw, 4.5rem);
  font-weight: 800;
  line-height: 1;
  color: var(--color-brand-text);
}

.not-found__text {
  margin: 0.75rem 0 1.5rem;
  color: var(--color-text-secondary);
}

/* 404 y baja de propuestas: su cabecera es la sencilla (.app-header), sin
   el relleno del hero de la guía; sin esto el título va pegado arriba. */
.not-found .app-header {
  padding-top: 1.5rem;
}

/* Un <button> (la baja de propuestas) no se estira como el <a> del 404:
   mismo ancho para los dos. */
.not-found__card .btn-primary-cta {
  width: 100%;
}

/* 14b. PÁGINAS LEGALES (Avís legal · Privacitat) y sus enlaces
   -------------------------------------------------------------------------- */
/* Mismo armazón que la ficha (.merchant-page): aquí solo el texto largo. */
.legal-page__body {
  margin-top: 0.5rem;
  padding: 1.5rem 1.4rem 1.75rem;
  background-color: var(--color-bg-card);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  color: var(--color-text-secondary);
}

.legal-page__title {
  font-size: var(--font-size-xl);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.15;
  color: var(--color-text-primary);
}

.legal-page__updated {
  margin-top: 0.35rem;
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}

/* «Com funcionen les ofertes» (AUTOSERVICIO T2): el mismo armazón que las
   legales, con una entradilla en vez de la fecha y dos puertas al final
   (el buscador de la portada y el alta). */
.info-page__lead {
  margin-top: 0.75rem;
  font-size: var(--font-size-base);
  color: var(--color-text-secondary);
}

.info-page__actions {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.75rem;
  margin-top: 1.75rem;
}

.info-page__actions a:not(.btn-primary-cta) {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--touch-target-min);
}

@media (min-width: 640px) {
  .info-page__actions {
    flex-direction: row;
    align-items: center;
    gap: 1.25rem;
  }

  .info-page__actions .btn-primary-cta {
    width: fit-content;
  }
}

.legal-page__body h2 {
  margin-top: 2rem;
  font-size: var(--font-size-lg);
  font-weight: 800;
  letter-spacing: -0.01em;
  line-height: 1.25;
  color: var(--color-text-primary);
}

.legal-page__body h3 {
  margin-top: 1.25rem;
  font-size: var(--font-size-base);
  font-weight: 700;
  color: var(--color-text-primary);
}

.legal-page__body p,
.legal-page__body ul,
.legal-page__body ol {
  margin-top: 0.75rem;
}

/* Los pasos de «Com es contracta» (Condicions, 173ª) van numerados */
.legal-page__body ol {
  padding-left: 1.25rem;
  list-style: decimal;
}

/* El reset deja las listas sin sangría: la viñeta saldría de la tarjeta */
.legal-page__body ul {
  padding-left: 1.25rem;
  list-style: disc;
}

.legal-page__body li + li {
  margin-top: 0.4rem;
}

.legal-page__body li > ul {
  margin-top: 0.4rem;
  list-style: circle;
}

.legal-page__body li > p {
  margin-top: 0.6rem;
}

.legal-page__body strong {
  font-weight: 700;
  color: var(--color-text-primary);
}

/* Correo y web largos: que partan antes que desbordar a 320 px.
   Solo los enlaces de TEXTO: el botón de la página del alta (#51, misma
   tarjeta) se quedaba con texto azul sobre fondo azul (1,27:1). */
.legal-page__body a:not(.btn-primary-cta) {
  color: var(--color-brand-text);
  font-weight: 600;
  text-underline-offset: 0.15em;
  overflow-wrap: anywhere;
}

.legal-page__body a:not(.btn-primary-cta):hover {
  color: var(--color-brand-hover);
}

/* «En poques paraules»: el resumen de la Privacitat, a la vista */
.legal-page__summary {
  padding: 1rem 1.1rem;
  background-color: var(--color-terra-wash);
  border: 1px solid var(--color-terra-border);
  border-radius: var(--radius-md);
  color: var(--color-text-primary);
}

/* El pie de todas las páginas (legalLinks.js): el «·» es decoración */
.footer-sep {
  color: var(--color-text-muted);
}

/* Enlace en línea: el relleno vertical agranda la zona táctil sin mover
   la línea de texto. Ni los enlaces ni el sello se parten («Avís / legal»
   salía en dos líneas a 375 px): son cortos y caben enteros a 320. */
.footer-legal-link {
  padding-block: 0.35rem;
}

.footer-legal-link,
.footer-nowrap {
  white-space: nowrap;
}

/* La nota bajo el formulario de la ficha (1ª capa de información) */
.request-form__privacy a {
  color: var(--color-brand-text);
  font-weight: 600;
  text-underline-offset: 0.15em;
}

.request-form__privacy a:hover {
  color: var(--color-brand-hover);
}

.legal-page__body a:not(.btn-primary-cta):focus-visible,
.footer-credit a:focus-visible,
.request-form__privacy a:focus-visible {
  outline: 3px solid var(--color-focus-outline);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* 14b. «AÑADE TU NEGOCIO» (#51): la página del ALTA
   Misma tarjeta que las legales. El formulario sale ENTERO (no hay
   puertas que elegir) y se agrupa en «Tu negocio» y «Tus datos».
   -------------------------------------------------------------------------- */
.add-business__pitch {
  margin-top: 0.5rem;
  color: var(--color-text-secondary);
}

/* #55 · La coletilla para quien NO es de Molins: bajo la entradilla y más
   pequeña (no compite con ella). El enlace hereda el de .legal-page__body. */
.add-business__elsewhere {
  margin-top: 0.5rem;
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}

/* Enlace en línea: mismo relleno que los del pie (zona táctil > 24 px sin
   mover la línea de texto). */
.add-business__elsewhere a {
  padding-block: 0.35rem;
}

.add-business .page-notice {
  margin-top: 1rem;
}

.add-business__form {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-top: 1.25rem;
}

/* Un fieldset no encoge por debajo de su contenido (min-width: min-content
   de serie): sin el 0, un campo largo desborda a 320. */
.add-business__group {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  min-width: 0;
  margin: 0 0 1rem;
  padding: 0;
  border: 0;
}

.add-business__group legend {
  margin-bottom: 0.25rem;
  padding: 0;
  font-size: var(--font-size-lg);
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--color-text-primary);
}

.add-business__form .btn-primary-cta {
  margin-top: 0.5rem;
}

/* Un desplegable con un nombre largo se ensancha hasta su opción más
   larga: con el 100 % se queda en la tarjeta y el texto se corta dentro. */
.add-business__form select.request-form__field,
.request-form__fix select.request-form__field {
  width: 100%;
  max-width: 100%;
  text-overflow: ellipsis;
}

/* H5 · Un nombre largo («Tintoreries, bugaderies i arranjaments») no cabe en
   una línea en un móvil estrecho ni quitando todos los márgenes, y achicar
   la letra haría que iOS ampliara la página al enfocarlo. Donde el
   navegador sabe crecer con su contenido, el desplegable parte en DOS
   líneas y se lee entero; donde no, se queda en una y acaba en «…» (la
   regla de arriba). Va dentro de @supports a propósito: sin field-sizing
   el texto partiría igual, pero la caja no crecería y la segunda línea
   quedaría tapada. */
@supports (field-sizing: content) {
  .add-business__form select.request-form__field,
  .request-form__fix select.request-form__field {
    height: auto;
    white-space: normal;
    field-sizing: content;
  }
}

/* H5 · Los ejemplos de «Dirección» y «Web o Instagram» se cortaban a 320
   (en catalán el segundo pide 261 px y el campo deja 215). En pantalla
   estrecha el EJEMPLO baja a la letra pequeña y el campo cede 4 px por
   lado. La letra del campo no se toca: por debajo de 16 px, iOS amplía la
   página al enfocarlo. El corte va a 399 y no a 374: la letra es la del
   sistema, y a 375 el catalán cabía con 9 px de margen. */
@media (max-width: 399px) {
  .add-business__form .request-form__field,
  .request-form__fix .request-form__field {
    padding-inline: 0.5rem;
  }

  .add-business__form .request-form__field::placeholder,
  .request-form__fix .request-form__field::placeholder {
    font-size: var(--font-size-xs);
  }
}

/* Las etiquetas: dos columnas ACOTADAS (minmax(0, …): una etiqueta larga
   parte en dos líneas en vez de empujar la columna fuera a 320).
   Su leyenda pesa como una etiqueta de campo, no como «El teu negoci». */
.add-business__tags {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 1rem;
  min-width: 0;
  margin: 0.25rem 0 0;
  padding: 0;
  border: 0;
}

.add-business__tags legend {
  margin-bottom: 0.5rem;
  padding: 0;
  font-size: var(--font-size-sm);
  font-weight: 600;
  letter-spacing: normal;
}

/* Dos clases: `.request-form label` (clase + etiqueta) le ganaría a una.
   El relleno la deja en 44 px de alto (22 de línea + 11 + 11): en el iPhone
   se acierta con el dedo; el aire entre filas lo pone él, no el `gap` (⑤, 146ª). */
.add-business__tags .add-business__tag {
  padding-block: 0.6875rem;
  font-weight: 400;
}

/* SIN LOCAL (164ª): la casilla, con el mismo dedo que una etiqueta; la
   dirección, en su caja (el mismo hueco que el resto de campos), se esconde
   al marcarla. Sin `:has()` se ve siempre: el servidor la ignora. */
.add-business__group .listing-no-local {
  padding-block: 0.6875rem;
  font-weight: 400;
}

.listing-address {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  min-width: 0;
}

@supports selector(:has(*)) {
  form:has(input[name="business_no_local"]:checked) .listing-address {
    display: none;
  }
}

/* Tras enviar: el aviso (el icono arriba; el texto corre varias líneas) y,
   DEBAJO del aviso, la oferta de ForgeBio.io → «Así se verá tu ficha» → la
   vuelta a la guía (55ª: el regalo primero, que en el móvil se vea sin bajar). */
.add-business__done {
  align-items: flex-start;
  margin-bottom: 0;
}

/* El párrafo hereda el margen de arriba de los de la página legal: fuera, o
   el texto empieza una línea por debajo del icono. Y el icono (16 px) baja
   lo justo para quedar centrado en la primera línea (~26 px). */
.add-business__done p {
  margin-top: 0;
  font-weight: 500;
}

.add-business__done > .icon-slot {
  margin-top: 0.3rem;
}

.add-business__preview-title {
  margin-top: 1.75rem;
  font-size: var(--font-size-lg);
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--color-text-primary);
}

/* La ficha del alta es un DIBUJO: sus botones y su dirección son <span> sin
   destino. Sin esto aún reaccionarían al ratón como si llevaran a algún sitio. */
.merchant-card--drawing .btn-whatsapp,
.merchant-card--drawing .btn-call,
.merchant-card--drawing .card-address-link {
  pointer-events: none;
}

/* La oferta, sola en su tarjeta: sin la línea que en la ficha la separa de
   las otras dos puertas. «El vull, gratis» aquí es un <button>; el `:where`
   deja su especificidad como la del <span> de la ficha, y así el borde de
   colores forzados (más abajo) le sigue ganando a este `border: 0`. */
.forgebio-offer--alone {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}

:where(button).forgebio-offer__cta {
  align-self: stretch;
  gap: 0.45rem;
  font-family: inherit;
  border: 0;
  cursor: pointer;
}

:where(button).forgebio-offer__cta:hover {
  background-color: var(--fb-cta-hover);
}

:where(button).forgebio-offer__cta:focus-visible {
  outline: 3px solid var(--color-focus-outline);
  outline-offset: 3px;
}

.add-business__back {
  display: flex;
  width: fit-content;
  margin: 1.25rem auto 0;
}

/* «GRATIS, AMIC O COL·LABORADOR» (M6, /ca/col-laboradors): la maqueta de la
   125ª tal cual (medida a 375/320/1280 y AA, con SU OK). Va DESPUÉS de las
   reglas de .legal-page__body a propósito: con su misma especificidad
   (`.collab-card p` = `.legal-page__body p`), gana por ORDEN.
   Las tres tarjetas, APILADAS también en escritorio (ⓑ: el cuerpo de
   lectura no da para tres columnas); la tercera, la destacada, con el
   marco del color de marca. Debajo, el formulario (#vull). */
.collab-cards {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  margin-top: 1.5rem;
}

.collab-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.6rem;
  padding: 1.1rem 1.1rem 1.2rem;
  text-align: center;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-lg);
  background-color: var(--color-bg-card);
}

.collab-card--featured {
  border: 2px solid var(--color-brand-text);
  box-shadow: var(--shadow-sm);
}

.collab-card .proposal-offer__title {
  margin: 0;
  font-size: var(--font-size-lg);
}

.collab-card .price-chip,
.collab-card p,
.collab-card .proposal-offer__plans {
  margin: 0;
}

.collab-card__eyebrow {
  color: var(--color-brand-text);
}

.collab-card__lead {
  align-self: stretch;
  text-align: left;
  font-size: var(--font-size-sm);
  color: var(--color-text-secondary);
}

.collab-cta {
  display: flex;
  align-items: center;
  justify-content: center;
  align-self: stretch;
  min-height: var(--touch-target-min);
  padding: 0.5rem 1rem;
  border-radius: var(--radius-md);
  font-weight: 800;
  text-decoration: none;
  text-wrap: balance;
}

.collab-cta--line {
  color: var(--color-brand-text);
  box-shadow: inset 0 0 0 2px currentColor;
}

.collab-cta--line:hover {
  background-color: var(--color-brand-wash);
}

.collab-card .btn-primary-cta {
  align-self: stretch;
  text-decoration: none;
}

.collab-form {
  margin-top: 2rem;
  padding-top: 1.5rem;
  border-top: 1px dashed var(--color-border-strong);
  scroll-margin-top: 1rem;
}

.collab-form h2 {
  margin-top: 0;
}

.collab-form__body {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-top: 0.75rem;
}

.collab-form__for {
  padding: 0.6rem 0.9rem;
  border-radius: var(--radius-md);
  background-color: var(--color-brand-wash);
  color: var(--color-text-primary);
  font-weight: 600;
  font-size: var(--font-size-sm);
}

.collab-form .btn-primary-cta {
  margin-top: 0.5rem;
}

/* Las líneas que llevan a la página: en el titular (no-Amic, al final del
   bloque Amics: se pliega con él · ya Amic, la suya, que se va entera en
   cuanto se elige una puerta: sin texto quedaría la raya del .proposal-offer).
   La de «Com funcionen els Amics» (.collab-howto-link) lleva el estilo de los
   enlaces del artículo (.legal-page__body a: 600), como en la maqueta. */
.collab-next {
  font-size: var(--font-size-sm);
}

.collab-line {
  font-size: var(--font-size-sm);
  color: var(--color-text-secondary);
}

.collab-line p {
  margin: 0;
}

.request-form:has(input[name="kind"]:checked) .collab-line {
  display: none;
}

.collab-next a,
.collab-line a {
  color: var(--color-brand-text);
  font-weight: 700;
  text-underline-offset: 0.15em;
}

.collab-next a:hover,
.collab-line a:hover {
  color: var(--color-brand-hover);
}

/* 15. ESCRITORIO (la guía crece sin perder el aire)
   -------------------------------------------------------------------------- */
@media (min-width: 640px) {
  .merchant-list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1.1rem;
  }

  .guia-hero {
    padding: 1.25rem 1.5rem 2rem;
    margin: 0 -1rem 1.5rem;
    border-radius: 0 0 var(--radius-xl) var(--radius-xl);
    border: 1px solid var(--color-border);
    border-top: 0;
  }
}

@media (min-width: 980px) {
  .merchant-list {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  body {
    padding-left: 1.5rem;
    padding-right: 1.5rem;
  }
}

/* 16. MOVIMIENTO REDUCIDO: todo sigue funcionando, nada salta
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }

  .banner-track {
    transition: none;
  }
}

/* 17. SALTO A CONTENIDO (WCAG 2.4.1) + UTILIDAD SOLO-LECTOR
   El enlace existe siempre para el lector de pantalla y para el teclado;
   solo se VE cuando recibe el foco. No se oculta con display:none ni con
   visibility:hidden porque eso tambien lo quita del orden de tabulacion.
   -------------------------------------------------------------------------- */
.skip-link {
  position: absolute;
  z-index: 100;
  top: 0.5rem;
  left: 0.5rem;
  padding: 0.7rem 1.1rem;
  border-radius: 999px;
  background-color: var(--color-bg-card);
  color: var(--color-text-primary);
  border: 2px solid var(--color-focus-outline);
  box-shadow: 0 6px 20px rgb(0 0 0 / 25%);
  font-size: var(--font-size-sm);
  font-weight: 700;
  text-decoration: none;
  transform: translateY(-200%);
}

.skip-link:focus-visible,
.skip-link:focus {
  transform: translateY(0);
  outline: 3px solid var(--color-focus-outline);
  outline-offset: 2px;
}

/* El destino del salto recibe el foco por programa: sin esto, el navegador
   le pinta su propio anillo alrededor de TODO el listado. */
#merchants-container:focus,
#contingut:focus {
  outline: none;
}

/* Texto que solo leen los lectores de pantalla (el aviso de «pestanya nova»). */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* 18. ALTO CONTRASTE Y COLORES FORZADOS
   Mucha gente con baja vision navega con el modo de alto contraste del
   sistema: ahi el navegador IGNORA nuestros colores, y lo primero que se
   pierde son los limites que dibujamos con FONDO en vez de con BORDE.
   -------------------------------------------------------------------------- */
@media (prefers-contrast: more) {
  :root {
    --color-focus-outline: #003d66;
  }

  .chip,
  .merchant-card,
  .agenda-card,
  .btn-whatsapp,
  .btn-call {
    border-width: 2px;
  }
}

@media (forced-colors: active) {
  /* En colores forzados, `outline-color` debe ser una palabra del sistema
     o el anillo se pinta del color del texto y se pierde. */
  *:focus-visible {
    outline: 3px solid Highlight;
    outline-offset: 2px;
  }

  /* Los iconos son `stroke: currentColor` y siguen al texto solos; lo que
     desaparece son los fondos. Borde para que no se fundan con el papel. */
  .chip,
  .merchant-card,
  .agenda-card,
  .skip-link,
  .btn-whatsapp,
  .btn-call {
    border: 1px solid CanvasText;
  }

  /* El disco de categoría (24e) pierde su color: queda el aro con el icono
     en la tinta del sistema (el nombre lo dice el eyebrow de todas formas). */
  .cat-badge {
    border: 1px solid CanvasText;
    color: CanvasText;
  }

  /* La pildora activa se distingue por COLOR; en colores forzados eso no
     llega, asi que se marca tambien con el fondo de seleccion. */
  .chip--active {
    background-color: Highlight;
    color: HighlightText;
  }

  /* Las dos puertas de la ficha: el botón pierde su fondo y la elegida se
     distinguía por color. Borde siempre y la elegida, con el de selección. */
  .request-kind--claim span,
  .forgebio-offer__cta {
    border: 1px solid CanvasText;
  }

  .request-kind input:checked + span {
    background-color: Highlight;
    color: HighlightText;
  }

  .request-kind input:focus-visible + span {
    outline: 3px solid Highlight;
  }

  /* «← Triar una altra cosa» se dibuja como el «←» de la cabecera (un
     enlace) y sin marco: con el color de enlace del sistema, para que no se
     lea como texto suelto. El sello, la pastilla y la puerta ya llevan
     borde; el «Estàs …» enfocado sigue sin anillo (es destino, no control). */
  .focus-back {
    color: LinkText;
  }
}
