/* ============================================================================
   turismo-pages.css — PATRONES DE PÁGINA de San Juan Turismo
   ============================================================================

   QUÉ ES ESTA CAPA Y POR QUÉ EXISTE (FASE H2.1-bis)
   --------------------------------------------------
   El DS tiene dos capas de componentes (`turismo-components.css` para vocabulario
   propio, `turismo-extend.css` para overrides del DS Gobierno padre). Pero las 27
   pantallas del kit traían además **55,7 KB de CSS en el `<style>` de cada HTML**:
   la maquetación específica de cada página —grillas, heroes, sub-navegaciones—
   que no es un componente reusable pero tampoco puede vivir dentro del HTML,
   porque el sitio real no sirve esos archivos: los sirve un template de Gantry.

   Esta es esa tercera capa. Va DESPUÉS de `turismo-extend.css`, así que puede
   ajustar lo que haga falta sin pelear especificidad.

   REGLA DE ADMISIÓN
   -----------------
   Entra sólo lo que es maquetación de una página o familia de páginas, con
   prefijo propio (`art-`, `in-`, `pl-`, `dir-`, `home-`…). NO entra:
     · nada `gsj-*` → eso es del DS, va a components o a extend;
     · el harness del kit (`body{margin:0}`, estilos del visor de demo), que sólo
       existe porque las pantallas del kit son HTML suelto.

   ESTADO DE LA MIGRACIÓN
   ----------------------
   Se migra por lote, a medida que cada override o particle necesita su pantalla.
   Migrado hasta ahora (contado sobre este archivo, no de memoria): `art-*` 19 ·
   `in-*` 16 · `exp-*` 24 · `edi-*` 13 · `atr-*` 23 · `at-*` 6 · `hub-*` 21 ·
   `dir-*` 23 · `home-*` 56 · `pr-*` 46 · `bus-*` 16 · `pl-*` 42 · `of-*` 5.
   PENDIENTE el barrido completo antes de cerrar H2 — quedan las pantallas que
   todavía no se implementaron (agenda, promociones, errores, contacto…), y
   **47 selectores no-`gsj` están repetidos en 3+ pantallas** que hay que
   deduplicar de una sola vez, no lote por lote. Ese
   barrido incluye además sacar los `<style>` de los HTML del kit y resincronizar
   a Claude Design, para que el kit no quede como segunda fuente de verdad.
   ============================================================================ */


/* ────────────────────────────────────────────────────────────────────────────
   RUTA DE NAVEGACIÓN  (`sj-ruta`) — cromo de sitio, no de una página
   H2.7. El kit dibuja la miga adentro de `main.gsj-page-main`, así que hereda
   la grilla y lo único que le hace falta es aire arriba: las 21 pantallas que
   la traen la envuelven en `padding-top:20px`. En el sitio la miga es un módulo
   en la posición `breadcrumbs` del outline —un bloque HERMANO del contenido—,
   de modo que el override le pone `.gsj-container` (la primitiva de grilla del
   DS, misma medida que `.gsj-page-main`) y esta clase aporta sólo ese aire.
   Se declara con nombre propio y no como estilo suelto para que la separación
   sea un dato del diseño y no un `style=""` escondido en un PHP.
   ──────────────────────────────────────────────────────────────────────────── */

.sj-ruta { padding-top: 20px }


/* ────────────────────────────────────────────────────────────────────────────
   ARTÍCULO INFORMATIVO  (`art-*`)
   Contenido Informativo: los 4 artículos de "Sobre San Juan" (Ubicación, Cómo
   llegar, Geografía y clima, Historia) y cualquier artículo de texto largo.
   La grilla la pone `.gsj-page-main`; la columna de lectura angosta (~68ch) la
   pone `.gsj-prosa` sobre el `<article>`. Ver turismo-extend.css.
   ──────────────────────────────────────────────────────────────────────────── */

.art-main { padding-bottom: 72px }

/* Aire entre la ruta de navegación y el arranque de la prosa. Mismo criterio que
   `.hub-main > .gsj-section-header` de más abajo: el kit lo escribe inline
   (`<header style="margin-top:28px">`) y acá se refleja como selector contextual,
   sin agregarle una clase al elemento —que la auditoría leería como un elemento
   distinto del kit—.
   🔴 Faltaba desde H2.5 lote (a) y no se veía: hasta H2.7 no había nada arriba de
   la prosa contra qué medir el hueco, así que el margen colapsaba hacia afuera y
   el "8/8 idénticos" del lote no lo miraba. Lo destapó poner el breadcrumb. */
.art-main .gsj-prosa > header { margin-top: 28px }

.art-eyebrow {
  font-family: var(--gsj-font-heading);
  font-size: .8rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--gsj-color-primary-text);
  margin: 0;
}

/* Escala estándar del DS (48/32), igual que el resto de los títulos en flujo. El
   clamp propio que había acá lo dejaba en 44,8px: cerca del estándar pero no
   igual, que es la peor variante — se percibe como error de render, no como
   jerarquía. */
.art-title {
  font-family: var(--gsj-font-heading);
  font-weight: 700;
  font-size: clamp(2rem, 4vw, 3rem);
  line-height: 1.08;
  margin: 10px 0 14px;
  color: var(--gsj-color-text);
}

.art-lead {
  font-size: 1.2rem;
  line-height: 1.6;
  color: var(--gsj-color-text-secondary);
  margin: 0;
  max-width: 60ch;
}

.art-media {
  width: 100%;
  margin: 28px 0 8px;
  border-radius: var(--gsj-radius-lg);
  overflow: hidden;
  aspect-ratio: 16/6;
  min-height: 200px;
}

/* `image-slot` es el placeholder del kit; `img` y `figure` son lo que emite el
   sitio real. Las tres se estiran igual para que la banda no cambie de alto
   según de dónde venga la imagen. */
.art-media image-slot,
.art-media img,
.art-media figure {
  display: block;
  width: 100%;
  height: 100%;
  margin: 0;
}

.art-media img { object-fit: cover }

.art-body {
  font-size: 1.06rem;
  line-height: 1.75;
  text-wrap: pretty;
}

/* Jerarquía del cuerpo (2026-09-22): las SECCIONES son h2 —regla del kit, `articulo-informativo.html`:
   «en el cuerpo se empieza en h2, nunca en h3»— y el h3 es la subsección (en «Cómo llegar», «Paso de
   Agua Negra» y «Rutas y caminos» cuelgan de «En auto»). Hasta hoy sólo había regla para h3 y el contenido
   saltaba de h1 a h3; el h2 tomaba el tamaño de nucleus/bootstrap, que el kit no puede revelar. */
.art-body h2 {
  font-family: var(--gsj-font-heading);
  font-weight: 700;
  font-size: 1.3rem;
  margin: 34px 0 10px;
  color: var(--gsj-color-text);
}

.art-body h3 {
  font-family: var(--gsj-font-heading);
  font-weight: 700;
  font-size: 1.125rem;
  margin: 26px 0 8px;
  color: var(--gsj-color-text);
}

.art-body p { margin: 0 0 16px }

/* El cuerpo llega del CMS con <a class="button"> — el template lo estiliza como
   botón secundario. */
.art-body .button {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  text-decoration: none;
  font-family: var(--gsj-font-heading);
  font-weight: 600;
  font-size: .9rem;
  padding: 8px 16px;
  border-radius: var(--gsj-radius-pill, 999px);
  border: 1px solid var(--gsj-color-border);
  color: var(--gsj-color-primary-text);
  background: var(--gsj-color-bg-subtle);
}

.art-body .button:hover { background: var(--gsj-color-surface, #fff) }

/* Sub-navegación entre los artículos hermanos de la misma categoría. */
.art-siblings {
  margin-top: 48px;
  padding-top: 28px;
  border-top: 1px solid var(--gsj-color-border);
}

.art-siblings__title {
  font-family: var(--gsj-font-heading);
  font-size: .8rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--gsj-color-text-secondary);
  margin: 0 0 14px;
}

.art-siblings__list {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  padding: 0;
  margin: 0;
}

.art-back { margin-top: 32px }


/* ────────────────────────────────────────────────────────────────────────────
   INSTITUCIONAL  (`in-*`)
   Organigrama de la Secretaría: sede + directorio de áreas con responsable y
   contacto. Art. 329.
   ──────────────────────────────────────────────────────────────────────────── */

.in-main { padding-bottom: 64px }

/* Mismo caso que `.art-main .gsj-prosa > header`: el kit lo escribe inline
   (`<div class="gsj-section-header" style="margin-top:20px">`) y sólo hay una
   instancia en la pantalla. Sin esto el encabezado quedaba pegado a la miga. */
.in-main .gsj-section-header { margin-top: 20px }

.in-intro { max-width: 70ch }

/* Directorio de áreas: cada una es nombre + función + a quién escribirle.
   No reusa OficinaCard porque ese componente exige mapaUrl y no tiene lugar para
   el texto de función; todas las áreas comparten la misma sede. */
.in-areas {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 20px;
  margin-top: 24px;
}

@media (min-width: 860px) {
  .in-areas { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px }
}

.in-area {
  background: var(--gsj-color-surface);
  border: .5px solid var(--gsj-color-border);
  border-radius: var(--gsj-radius-card);
  padding: 24px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.in-area__nombre {
  font-family: var(--gsj-font-heading);
  font-size: 1.125rem;
  font-weight: 700;
  line-height: 1.25;
  margin: 0;
  color: var(--gsj-color-text);
}

.in-area__funcion {
  margin: 0;
  font-size: .9375rem;
  line-height: 1.55;
  color: var(--gsj-color-text-secondary);
}

.in-area__datos {
  display: flex;
  flex-direction: column;
  gap: 7px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.in-area__dato {
  display: flex;
  gap: 9px;
  align-items: flex-start;
  font-size: .9375rem;
  line-height: 1.45;
}

.in-area__dato svg {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  margin-top: 3px;
  color: var(--gsj-color-primary);
}

.in-area__dato a { color: var(--gsj-color-text); text-decoration: none }
.in-area__dato a:hover { color: var(--gsj-color-text-link); text-decoration: underline }

.in-area__rol { color: var(--gsj-color-text-muted) }

.in-programas {
  margin: 2px 0 0;
  padding-left: 18px;
  font-size: .9375rem;
  line-height: 1.5;
  color: var(--gsj-color-text-secondary);
}

.in-programas li { margin-bottom: 4px }
.in-programas strong { color: var(--gsj-color-text) }


/* ────────────────────────────────────────────────────────────────────────────
   FICHAS DE ENTIDAD: DESTINO y EXPERIENCIA  (`exp-*`, `edi-*`)
   Pantallas `destino.html` y `experiencia.html` del kit. Van JUNTAS porque
   comparten el prefijo `exp-`: es el esqueleto de secciones apilables que fijó
   la sesión 3 de H1. `edi-*` son las filas editoriales alternadas, exclusivas
   de Destino (salen del cuerpo, ver SjturEditorial).

   Los valores son los LITERALES del `<style>` de las dos pantallas —incluidos
   los `clamp()` y los breakpoints exactos (560/620/720/760/900)—, no
   equivalentes redondeados.

   ⚠️ Dos grupos de selectores son AGREGADOS, no migrados, y conviene saber cuál
   es cuál:
     · El kit maqueta los espacios entre secciones con `style="margin-top:56px"`
       inline y los títulos con `style="font-family:…"` inline. Acá se nombran
       (`.exp-seccion`, `.exp-auto__titulo`, `.exp-auto__subtitulo`…) con los
       MISMOS valores computados: el objetivo de esta capa es justamente que el
       markup no lleve `style=`.
     · `.edi-row--no-media` y `.sj-hueco` no existen en el kit. El primero hace
       falta porque el mock tenía foto para cada fila y el catálogo no: **Valle
       de Tulum tiene 8 filas y 7 fotos**. El segundo es el marco del estado
       `hueco` de `SjturSlots`, y su forma sí sale del kit — es el tratamiento
       de `atr-widgets` (borde punteado + antetítulo «espacio reservado»).
   ──────────────────────────────────────────────────────────────────────────── */

.exp-main { padding-bottom: 80px }

.exp-hero-wrap { padding-top: 20px }

/* El badge del hero no se estira a lo alto de la banda. */
.exp-hero-badge { align-self: flex-start }

/* 🔴 EL AIRE DE ABAJO ES DEL KIT, y la auditoría exhaustiva lo destapó: el kit le pone
   **20px debajo en las TRES apariciones** —dos veces envolviendo el h2 en un
   `div style="display:flex;flex-direction:column;gap:4px;margin-bottom:20px"` y una vez
   con `style="margin-bottom:20px"` inline—. O sea que no es un caso especial de la
   sección de la oficina: es la norma. La primera pasada lo trató como excepción
   (`--con-aire`) y las otras dos secciones quedaron 20px pegadas a su encabezado.
   `margin-top: 0` explícito porque es un heading y el `p`/heading de nucleus manda
   margen — ver la nota de márgenes propios en turismo-extend.css. */
.exp-h2 {
  font-family: var(--gsj-font-heading);
  font-weight: 700;
  margin: 0;
  color: var(--gsj-color-text);
}

/* El encabezado de sección: el kit lo escribe como
   `div style="display:flex;flex-direction:column;gap:4px;margin-bottom:20px"` y lo repite
   en las tres secciones. Se replica la ESTRUCTURA y no sólo el resultado: aplanarlo
   —poniéndole los 20px al propio h2— daba el mismo espacio pero movía el margen a otro
   elemento, y el `gap: 4px` existe porque el kit a veces cuelga un subtítulo del h2. */
.exp-seccion__head {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-bottom: 20px;
}

/* Ritmo vertical entre secciones de la ficha: el `margin-top:56px` que el kit
   repetía inline en cada `<section>`. */
.exp-seccion { margin-top: 56px }

/* Nota al pie de un bloque de datos (procedencia del clima, aclaraciones). */
.exp-nota {
  margin: 14px 0 0;
  font-size: 0.82rem;
  color: var(--gsj-color-text-secondary);
}

/* Tres grillas, con los breakpoints exactos del kit. */
.exp-grid-info { display: grid; gap: 16px; grid-template-columns: 1fr }
@media (min-width: 620px) { .exp-grid-info { grid-template-columns: repeat(3, 1fr) } }
/* 4 bloques: el kit sólo contempla 3 porque su mock trae «Desde la capital» EN LUGAR de un
   tercer bloque de clima. En el sitio el clima son 3 lecturas en vivo, así que con la
   distancia son cuatro y `repeat(3,1fr)` dejaría un huérfano solo en la segunda fila.
   Va como MODIFICADOR y no tocando `.exp-grid-info`: el caso de 3 está medido contra el
   kit y no se toca. */
@media (min-width: 620px) { .exp-grid-info--4 { grid-template-columns: repeat(2, 1fr) } }
@media (min-width: 960px) { .exp-grid-info--4 { grid-template-columns: repeat(4, 1fr) } }

.exp-grid-cards { display: grid; gap: 16px; grid-template-columns: 1fr }
@media (min-width: 560px) { .exp-grid-cards { grid-template-columns: repeat(2, 1fr) } }
@media (min-width: 900px) { .exp-grid-cards { grid-template-columns: repeat(3, 1fr) } }

/* Atractivos: 2 columnas ya en mobile porque son tarjetas verticales 4/5. */
.exp-grid-atr { display: grid; gap: 16px; grid-template-columns: repeat(2, 1fr) }
@media (min-width: 720px) { .exp-grid-atr { grid-template-columns: repeat(4, 1fr) } }

/* Narrativa editorial de la ficha de Experiencia. Una sola columna por defecto:
   a 390px dos columnas dejaban renglones de ~8 palabras, ilegibles. */
.exp-narrativa { margin-top: 32px; max-width: 68ch }
@media (min-width: 760px) { .exp-narrativa { columns: 2; column-gap: 40px } }
.exp-narrativa p {
  margin: 0 0 14px;
  font-size: 1.02rem;
  line-height: 1.7;
  break-inside: avoid;
  text-wrap: pretty;
}
/* Subtítulos de la narrativa (2026-09-22, lo vio [U] en Ruta del Cielo). Mismo hueco que
   `.atr-body`: el kit sólo define párrafos y un `<h2>` del artículo caía al h2 global —48px a
   1280, MÁS que las secciones (`.exp-h2`, 32–35px), y a 390 igual que el h1—. Medido con
   `barrido_h.js` sobre las 27 páginas con h2/h3 en el cuerpo: 7 landings de Experiencia.
   Mismos tokens que `.promo-prose` y `.atr-body`. `break-after: avoid` porque la narrativa va a
   DOS columnas desde 760px: sin eso un subtítulo puede quedar huérfano al pie de una columna. */
.exp-narrativa h2 {
  font-family: var(--gsj-font-heading); font-weight: 700; color: var(--gsj-color-text);
  font-size: var(--gsj-font-size-title-3); line-height: 1.3;
  margin: var(--gsj-space-6) 0 var(--gsj-space-3);
  break-after: avoid; break-inside: avoid;
}
.exp-narrativa h3 {
  font-family: var(--gsj-font-heading); font-weight: 500; color: var(--gsj-color-text);
  font-size: var(--gsj-font-size-headline); line-height: 1.35;
  margin: var(--gsj-space-5) 0 var(--gsj-space-2);
  break-after: avoid; break-inside: avoid;
}
.exp-narrativa > h2:first-child, .exp-narrativa > h3:first-child { margin-top: 0 }
/* Aviso dentro de la narrativa (2026-09-24, veda de pesca en Aventura). Un `<aside>` es una pieza
   larga que no entra en DOS columnas: partida, la lista caía en la otra columna; entera, dejaba un
   hueco; a lo ancho (`column-span`), quedaba bajo las dos columnas y [U] la vio «desconectada de
   Agua». Con un aviso, la narrativa va a UNA columna (el mismo 68ch): Agua → veda → lo que sigue.
   Las landings sin aviso no cambian. Sin soporte de `:has()` queda como antes: dos columnas. */
.exp-narrativa:has(> aside) { columns: auto }

/* ── Bloque automático por tag ────────────────────────────────────────────────
   Panel tintado + borde: separarlo visualmente del editorial es el requisito
   central de la pantalla de Destino (lo que el organismo escribió vs. lo que el
   sitio arma solo). */
.exp-auto {
  margin-top: 72px;
  background: var(--gsj-color-bg-muted);
  border: 1px solid var(--gsj-color-border);
  border-radius: var(--gsj-radius-lg);
  padding: clamp(24px, 5vw, 44px);
}

.exp-auto__titulo {
  font-family: var(--gsj-font-heading);
  font-weight: 700;
  font-size: clamp(1.6rem, 4.5vw, 2.3rem);
  margin: 0;
  color: var(--gsj-color-text);
}

.exp-auto__grupo { margin-top: 36px }

/* Encabezado de grupo: título a la izquierda y "ver todo" empujado al borde.
   `flex-wrap` + `align-items:flex-end` es lo del kit: a 390px el botón baja de
   renglón en vez de comprimir el título. */
.exp-auto__encabezado {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 12px;
  margin-bottom: 16px;
}

.exp-auto__subtitulo {
  font-family: var(--gsj-font-heading);
  font-weight: 700;
  font-size: 1.15rem;
  margin: 0;
  color: var(--gsj-color-text);
}

.exp-auto__vertodo { margin-left: auto }

/* Cuando el subtítulo va solo (sin botón) conserva el mismo aire de abajo que
   le daba el `.exp-auto__encabezado`. */
.exp-auto__grupo > .exp-auto__subtitulo { margin-bottom: 16px }


/* ── Filas editoriales alternadas (sólo Destino) ─────────────────────────────
   Storytelling del organismo: imagen + texto, invirtiendo el lado en las pares.
   Salen del cuerpo del artículo (SjturEditorial), no de campos. */

.edi-seccion { margin-top: 40px }

.edi-lista { display: flex; flex-direction: column; gap: 44px }

.edi-row { display: flex; flex-direction: column; gap: 20px }

.edi-media {
  border-radius: var(--gsj-radius-md);
  overflow: hidden;
  min-height: 200px;
  aspect-ratio: 5 / 3;
}

.edi-media img,
.edi-media image-slot {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.edi-body { max-width: 60ch }

.edi-titulo {
  font-family: var(--gsj-font-heading);
  font-weight: 700;
  font-size: clamp(1.3rem, 3.5vw, 1.8rem);
  margin: 0 0 12px;
  color: var(--gsj-color-text);
}

.edi-texto { margin: 0 0 12px; font-size: 1.06rem; line-height: 1.75; text-wrap: pretty }
.edi-texto:last-child { margin-bottom: 0 }

/* Encabezado de sección que sale de un <h2> suelto del cuerpo (Valle de Tulum
   intercala uno y después abre una segunda grilla; Jáchal cierra con dos). */
.edi-intro { max-width: 68ch }
.edi-intro__texto { margin: 12px 0 0; line-height: 1.7 }

.edi-galeria {
  margin-top: 56px;
  padding-top: 40px;
  border-top: 1px solid var(--gsj-color-border);
}

@media (min-width: 760px) {
  /* Variante D (decidida el 2026-08-28, tercera iteración de C2 con [U]): foto
     y panel de texto lado a lado, con el panel MONTADO 90px sobre el borde de
     la foto, centrado verticalmente y alternando el lado en las pares. Tres
     columnas de grid: foto | franja de solape | panel — la foto ocupa 1-2 y el
     panel 2-4, así que sólo comparten la franja: con texto largo el panel crece
     hacia abajo EN SU COLUMNA y la foto se estira manteniéndose apaisada.
     La foto queda en ~64% del ancho: no repite la silueta del hero (la objeción
     que enterró a B, cuyas bandas full-width medían 493px contra 460 del hero).
     🔴 nth-of-type y no nth-child: el `edi-intro` intercalado de Tulum es un div
     hermano de los article, y con nth-child correría la paridad de la segunda
     grilla. */
  .edi-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 90px minmax(0, 44ch);
    align-items: center;
  }
  /* 🔴 El ratio va por ::before y NO por aspect-ratio: con aspect-ratio +
     align-self:stretch, cuando el panel es más alto que la foto el alto
     estirado le DICTA el ancho a la foto (2×alto) y desborda sus columnas —
     medido: una foto de 1026px sobre un span de 686. El padding porcentual da
     el alto base (50% del ancho = 2:1) y el ancho queda clavado al track. */
  .edi-media {
    grid-column: 1 / 3;
    grid-row: 1;
    aspect-ratio: auto;
    min-height: 0;
    align-self: stretch;
    position: relative;
  }
  .edi-media::before { content: ''; display: block; padding-top: 50% }
  .edi-media img,
  .edi-media image-slot {
    position: absolute;
    inset: 0;
  }
  .edi-body {
    grid-column: 2 / 4;
    grid-row: 1;
    position: relative;
    z-index: 1;
    background: var(--gsj-color-bg-page);
    border-radius: var(--gsj-radius-md);
    padding: 26px 30px;
    margin: 28px 0;
    box-shadow: 0 6px 18px -8px rgba(20, 12, 4, .3);
  }
  .edi-row:nth-of-type(even) { grid-template-columns: minmax(0, 44ch) 90px minmax(0, 1fr) }
  .edi-row:nth-of-type(even) .edi-media { grid-column: 2 / 4 }
  .edi-row:nth-of-type(even) .edi-body { grid-column: 1 / 3 }

  /* Sin foto no hay nada que pisar: el texto fluye al ancho de lectura completo
     y fuera del alternado. Doble clase a propósito: tiene que empatar la
     especificidad de `.edi-row:nth-of-type(even) .edi-body` (0,3,0) e ir
     DESPUÉS, o una fila par sin foto hereda el panel del alternado. */
  .edi-row.edi-row--no-media { display: block }
  .edi-row.edi-row--no-media .edi-body {
    max-width: 68ch;
    background: none;
    border-radius: 0;
    padding: 0;
    margin: 0;
    box-shadow: none;
  }
}


/* ── El marco del estado `hueco` (SjturSlots) ────────────────────────────────
   Forma tomada de `atr-widgets` del kit, que es donde el kit ya declara un
   "espacio reservado": borde punteado para que se lea como pendiente y no como
   contenido, sobre fondo tenue. */
.sj-hueco {
  margin-top: 30px;
  border: 1.5px dashed var(--gsj-color-border-strong);
  border-radius: var(--gsj-radius-md);
  background: var(--gsj-color-bg-subtle);
  padding: 16px 18px;
}

.sj-hueco__eyebrow {
  font-family: var(--gsj-font-heading);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gsj-color-text-muted);
  margin: 0 0 6px;
}

.sj-hueco__texto {
  font-size: 15px;
  line-height: 1.55;
  color: var(--gsj-color-text-secondary);
  margin: 0;
}

/* Folleto oficial de la ficha de Experiencia (BotonFolleto del kit): panel con
   jerarquía propia, porque es la conversión real de la página. */
.exp-folleto {
  display: flex;
  flex-direction: column;
  gap: 16px;
  align-items: flex-start;
  padding: clamp(24px, 5vw, 40px);
  border-radius: var(--gsj-radius-lg);
  background: var(--gsj-color-bg-muted);
}

.exp-folleto__titulo {
  font-family: var(--gsj-font-heading);
  font-weight: 700;
  font-size: clamp(1.5rem, 4vw, 2.2rem);
  margin: 0;
  max-width: 22ch;
  color: var(--gsj-color-text);
}

.exp-folleto__texto {
  margin: 0;
  font-size: 1.05rem;
  line-height: 1.6;
  max-width: 52ch;
  color: var(--gsj-color-text-secondary);
}


/* ────────────────────────────────────────────────────────────────────────────
   FICHA DE ATRACTIVO  (`atr-*`)
   Pantalla `atractivo.html` del kit. Valores literales de su `<style>`.
   El hero no deja CSS acá: es `gsj-entity-hero--foto` (o `--marca` en los 29 de
   57 que no tienen imagen), que vive en turismo-components.css.
   ──────────────────────────────────────────────────────────────────────────── */

/* 🔴 ERA `padding-bottom: 8px`, literal del `<style>` del kit — contra los **80px** de
   `.exp-main` (Destino/Experiencia) y los **72px** de `.art-main`. En el sitio real la
   última sección quedaba pegada al footer. Otro número suelto del kit que sobrevivió por
   vivir en el HTML y no en el DS, igual que el `.atr-h2` de 22px. Se alinea con `.exp-main`,
   que es la ficha de entidad hermana. */
.atr-main { padding-bottom: 80px }

/* Sello sobre el hero (los 14 del Pasaporte Sanmartiniano): el contrato de datos
   del kit pide modelarlos como SELLO y no como subtipo. */
.atr-sello {
  display: inline-flex;
  align-items: center;
  background: rgba(255, 255, 255, 0.16);
  color: #fff;
  border: 1px solid rgba(255, 255, 255, 0.6);
  border-radius: var(--gsj-radius-full);
  padding: 3px 10px;
  font-family: var(--gsj-font-heading);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.04em;
}

/* Badge de subtipo + sello, en la misma línea. En el kit es un `style` inline. */
.atr-hero-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}

/* 🔴 ERA `font-size: 22px` FIJO, literal del `<style>` del kit de Atractivo — un número
   mágico que no está en la escala de títulos y que no escala con el viewport. Convivía
   con `.exp-h2` (Destino/Experiencia) en `clamp(1.4rem,4vw,2rem)` y con el título base
   del DS en `clamp(2rem,4vw,3rem)`: TRES tamaños para el mismo rol. Sobrevivió a la
   consolidación de títulos de H1 (9→4 tamaños) porque vivía en el HTML del kit y no en
   el DS, donde esa auditoría miraba.
   Se alinea con `.exp-h2`: el título de sección de una ficha de entidad se ve igual en
   las tres. (Que ese `clamp` tampoco sea un token —lo correcto sería
   `--gsj-font-size-title-2`— queda anotado como deuda: migrarlo cambia también Destino y
   Experiencia, que ya están medidas, así que es una decisión aparte.) */
.exp-h2,
.atr-h2 { font-size: clamp(1.4rem, 4vw, 2rem) }

/* Encabezado de sección: el kit le pone `margin-bottom:20px` inline al
   `gsj-section-header` en las tres secciones. */
.atr-section-header { margin-bottom: 20px }

/* Ritmo vertical entre secciones. El kit lo escribe como `margin-top:36px` inline. */
.atr-seccion { margin-top: 36px }

.atr-body { margin-top: 30px; max-width: 760px }
.atr-body p {
  font-size: 17px;
  line-height: 1.68;
  margin: 0 0 16px;
  text-wrap: pretty;
}
/* Subtítulos DENTRO del cuerpo (2026-09-22, lo vio [U] en la ficha del CASLEO). El kit no los
   define —su `.atr-body` sólo trae párrafos— y un `<h2>` del artículo caía al h2 global: 48px a
   1280, MÁS que las secciones de la página (`.atr-h2` «Planificá la visita», 32px) y a 390 igual
   que el h1. Medido: 8 fichas publicadas traen h2/h3 en el cuerpo. Mismos tokens que
   `.promo-prose`, la otra prosa editorial del sitio, para que quede por DEBAJO de `.atr-h2`. */
.atr-body h2 {
  font-family: var(--gsj-font-heading); font-weight: 700; color: var(--gsj-color-text);
  font-size: var(--gsj-font-size-title-3); line-height: 1.3;
  margin: var(--gsj-space-8) 0 var(--gsj-space-3);
}
.atr-body h3 {
  font-family: var(--gsj-font-heading); font-weight: 500; color: var(--gsj-color-text);
  font-size: var(--gsj-font-size-headline); line-height: 1.35;
  margin: var(--gsj-space-6) 0 var(--gsj-space-2);
}
.atr-body > h2:first-child, .atr-body > h3:first-child { margin-top: 0 }
/* El valor de «Planificá la visita» con VARIOS renglones (horarios, tarifas): peso normal y
   sólo el tramo antes de los dos puntos en semibold. Lo arma `$infoBlock` en
   `default_atractivo.php`; ver el comentario ahí. Un solo renglón conserva el 600 del DS. */
.gsj-info-block__value--lineas { font-weight: 400; line-height: 1.55 }
.gsj-info-block__value--lineas strong { font-weight: 600 }

/* «Parte de»: rótulo + chips de experiencia y destino. Inline en el kit. */
.atr-partede {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  margin-top: 16px;
}
.atr-partede__rotulo {
  font-family: var(--gsj-font-heading);
  font-size: 12.5px;
  font-weight: 600;
  color: var(--gsj-color-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
/* Tag sin landing a la que ir: el chip queda como dato, no como enlace. `.gsj-chip`
   trae `cursor:pointer` y acá mentiría. Hoy no lo usa ninguna ficha (los 19 tags
   resuelven); existe para que el día que aparezca un tag nuevo no prometa un clic. */
.atr-partede__chip--inerte {
  cursor: default;
}

/* Fila de canales oficiales: sitio, tour 360 y redes en la misma línea. Van juntos
   y arriba a propósito —el kit lo dice—: al final de la página las redes quedaban
   huérfanas y se leían como redes DEL SITIO, no del atractivo. */
.atr-acciones {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 18px;
  margin-top: 18px;
}

.atr-infogrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 20px 28px;
}

/* 🔴 ERA `repeat(auto-fit, minmax(170px, 1fr))`, literal del kit — pero el kit mockeó
   subtipos cortos («Naturales», «Espacios Culturales») y el dato real trae **«Pasaporte
   Nacional Sanmartiniano»**, 33 caracteres: el badge necesita **221px** y con `auto-fit`
   la grilla caía en **6 columnas de 192px** a cualquier ancho de escritorio, así que el
   chip se cortaba contra el borde de la card.
   Se pasa a la MISMA escalera que `.exp-grid-atr` de la ficha de Destino —2 → 4— que es
   donde el kit ya resolvió esta grilla: son las mismas tarjetas de atractivo. A 1232px da
   cards de ~296px, con lugar de sobra para el chip más largo. */
.atr-relgrid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
}

/* 🔴 EN MOBILE VAN 4, NO 8. A una columna, ocho tarjetas de 4:5 son ~2.700px de scroll de
   contenido SECUNDARIO —«Cerca de acá» no es lo que la persona vino a leer— y empujan el
   resto de la ficha fuera de alcance. Se ocultan las que sobran en vez de traer menos del
   servidor porque el corte es RESPONSIVE y el PHP no sabe el ancho; y no se pierde nada:
   el botón «Ver los N atractivos del destino» ya está arriba, a un toque.
   Las imágenes de las ocultas son `loading="lazy"`, así que no se descargan. */
.atr-relgrid > :nth-child(n + 5) { display: none }

@media (min-width: 720px) {
  .atr-relgrid { grid-template-columns: repeat(4, 1fr) }
  .atr-relgrid > :nth-child(n + 5) { display: block }
}

.atr-eyebrow {
  font-family: var(--gsj-font-heading);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--gsj-color-text-muted);
  margin: 0 0 6px;
}

.atr-nota {
  margin: 14px 0 0;
  font-size: 0.82rem;
  color: var(--gsj-color-text-secondary);
}

/* El mapa embebido llena la caja del `gsj-map-card`. */
.atr-mapa {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* Fila de encabezado de sección con acción a la derecha. Misma forma que
   `.exp-auto__encabezado` de Destino/Experiencia: el kit la escribe inline y el
   `flex-wrap` es lo que hace que a 390px el botón baje de renglón en vez de
   comprimir el título. El `margin-bottom` se muda acá desde `.atr-section-header`,
   que pasa a usarse sólo cuando el encabezado va solo. */
.atr-seccion__head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 12px;
  margin-bottom: 20px;
}

.atr-vertodo { margin-left: auto }

/* 🔴 `align-items: flex-end` alinea CAJAS DE MARGEN, no lo que se ve. `gsj-section-header`
   trae su propio `margin-bottom` del DS, así que el botón quedaba **32px más abajo** que
   el título en vez de en su misma línea (medido: título bottom 1969, botón 2001). Se anula
   el margen del header cuando va DENTRO de la fila — el aire de la fila ya lo pone
   `.atr-seccion__head`. */
.atr-seccion__head > .gsj-section-header { margin-bottom: 0 }

/* La dirección va pegada al título, no al pie del mapa: es parte de "dónde está", no una
   nota. */
.atr-seccion__head .atr-direccion {
  margin: 4px 0 0;
  font-size: 0.9375rem;
  color: var(--gsj-color-text-secondary);
}


/* ────────────────────────────────────────────────────────────────────────────
   HUBS  (`hub-*`)
   El esqueleto de las pantallas de listado: `destinos.html`, `experiencias.html`
   y el bloque de cierre de `atractivos.html`. Un solo override
   (`com_content/category/blog.php`) lo dibuja para las 16 rutas de listado del
   sitio, así que lo que hay acá tiene que servir tanto al hub curado de 5 ítems
   como al sub-hub de SERVICIOS con 400.

   🔴 POR QUÉ `.hub-grid` LLEVA MODIFICADOR Y EN EL KIT NO LO LLEVABA.
   Las dos pantallas del kit definen `.hub-grid` **distinto** —destinos con 2→4
   columnas fijas, experiencias con `auto-fill minmax(260px)`, y hasta distinto
   `margin-top`—. En el kit no colisionan porque cada HTML trae su propio
   `<style>`; en una hoja única para todo el sitio, la segunda pisa a la primera.
   Así que la parte común queda en `.hub-grid` y lo que difiere en un
   modificador. **El kit se corrigió también** (`destinos.html` y
   `experiencias.html` ya emiten el modificador): si sólo se cambiara acá, el kit
   quedaría como segunda fuente de verdad y la auditoría de fidelidad reportaría
   la clase como "sólo en el kit" en cada corrida.
   ──────────────────────────────────────────────────────────────────────────── */

.hub-main { padding-bottom: 64px }

/* Agrupadores del hub de Experiencias (D1, 2026-09-22): secciones con cabecera de fila; la
   landing paraguas es la cabecera enlazada (`gsj-section-header__link`), no una tarjeta. */
.hub-grupo { margin-top: 44px; }
.hub-grupo .hub-grupo__cab { margin-bottom: 0; }
.hub-grupo__intro { max-width: 62ch; }
.hub-grupo .hub-grid { margin-top: 18px; }

/* En móvil el hub agrupado va a DOS columnas (decisión [U] 2026-09-22, a prueba): con una
   columna las 17 experiencias medían 9.641 px de alto a 390 px, quince pantallas para elegir.
   Sólo en el hub agrupado: los sub-hubs de Servicios siguen con su `auto-fill`. */
@media (max-width: 559px) {
  /* PRUEBA B (2026-09-22): una columna de tarjetas HORIZONTALES —foto a la izquierda, título a
     la derecha—, la tarjeta de lista de las guías. Alternativa a la prueba A (dos columnas). */
  .hub-grupo .hub-grid--auto { grid-template-columns: minmax(0, 1fr); gap: 10px; }
  /* `!important` porque `SjturCards::deArticulo()` emite `style="display:block"` inline en la
     tarjeta, y sin él la grilla no se aplica (medido: el título quedaba debajo de la foto, fuera
     de la caja de 181 px). */
  .hub-grupo .hub-grid--auto .gsj-card {
    display: grid !important;
    grid-template-columns: 124px minmax(0, 1fr);
    align-items: center;
    border-radius: 16px;
    overflow: hidden;
  }
  .hub-grupo .hub-grid--auto .gsj-card__image { width: 124px; height: 100%; min-height: 96px; aspect-ratio: auto; object-fit: cover; }
  .hub-grupo .hub-grid--auto .gsj-card__body { padding: 12px 14px; }
  .hub-grupo .hub-grid--auto .gsj-card__text { display: none; }
  .hub-grupo .hub-grid--auto .gsj-card__title { font-size: 1.0625rem; line-height: 1.25; margin: 0; }
  .hub-grupo .hub-grid--auto .gsj-badge { margin-bottom: 6px; }
}
}

/* El encabezado va como selector contextual y NO como clase nueva sobre el
   elemento: el kit escribe `<div class="gsj-section-header" style="margin-top:20px">`,
   y agregarle una clase `hub-*` haría que la auditoría lo viera como un elemento
   distinto del kit (compara por el juego completo de clases de diseño) y lo
   reportara como divergencia en cada corrida sin que nada esté mal. */
.hub-main > .gsj-section-header { margin-top: 20px }

/* La bajada del hub. `hub-intro` sí es clase porque el kit también la pone así. */
.hub-intro { max-width: 66ch }

/* El destacado: la primera tarjeta ocupa el ancho como pieza de entrada. Lo que
   la hace destacado es venir en `lead_items` (params del ítem de menú), no una
   decisión de la plantilla — ver PLAN-H2 §H2.6. */
.hub-destacado { margin-top: 28px }

/* 🔴 La banda ancha es una regla de CONTEXTO, no de la tarjeta: la misma
   `gsj-card--destino` es 4/5 en la grilla y 21/9 acá. Por eso va como
   descendiente y no como modificador de la card. */
.hub-destacado .gsj-card--destino { aspect-ratio: 21 / 9 }

/* El destacado sube un escalón tipográfico, y no es capricho: salía con la MISMA
   tipografía que una tarjeta de la grilla (24px/15px) dentro de una caja **cinco veces
   más ancha** (1184px contra 242px), así que se leía chico. Lo marcó el usuario en
   pantalla, no la auditoría — que compara la clase contra el kit y por lo tanto daba
   idéntico, porque el kit tenía el mismo desbalance.

   Los dos tamaños son REUSADOS, no inventados: el título toma la escala de título de
   sección (`.exp-h2`, 32px a 1280 / 22,4 a 390) y la bajada la de la bajada de página en
   Lora (18 / 16,2), que es además la fuente del contenido del hero de la ficha.
   ⚠️ NO se copia el hero de la ficha (54,4px) aunque el tratamiento sea parecido: ahí el
   hero ES el `h1` de la página, y acá el `h1` es el título del hub (48px). Una tarjeta
   más grande que el título de su propia página invierte la jerarquía. Queda
   h1 48 > destacado 32 > tarjetas 24.  [decisión del usuario, 2026-07-30] */
.hub-destacado .gsj-card--destino__title { font-size: clamp(1.4rem, 4vw, 2rem) }

.hub-destacado .gsj-card--destino__location {
  font-family: var(--gsj-font-body);
  font-size: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
}

@media (max-width: 720px) {
  .hub-destacado .gsj-card--destino { aspect-ratio: 4 / 5 }
}

.hub-grid {
  display: grid;
  gap: 20px;
  margin-top: 20px;
}

@media (min-width: 900px) {
  .hub-grid { gap: 24px }
}

/* Destinos: grilla FIJA de 2→4 columnas. Con 4 ítems exactos bajo el destacado,
   `auto-fill` los dejaría en 3+1 a ciertos anchos. */
.hub-grid--fija { grid-template-columns: repeat(2, minmax(0, 1fr)) }

@media (min-width: 900px) {
  .hub-grid--fija { grid-template-columns: repeat(4, minmax(0, 1fr)) }
}

/* Experiencias y los listados genéricos: cantidad desconocida y variable (17 en
   Experiencias, ~400 en un sub-hub de SERVICIOS) → `auto-fill`. El `margin-top`
   mayor es del kit: acá no hay destacado arriba que ya haya puesto aire. */
.hub-grid--auto {
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  margin-top: 28px;
}

/* Cierre: las salidas laterales del hub. El hub no es un callejón — quien no
   sabe por dónde empezar entra por tema o por lugar puntual. Cierra el triángulo
   Destinos / Experiencias / Atractivos: las tres formas de recorrer el mismo
   catálogo (por zona, por tema, por lugar). */
.hub-cierre {
  margin-top: 48px;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 16px;
}

@media (min-width: 760px) {
  .hub-cierre {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 24px;
  }
}

.hub-puerta {
  display: block;
  background: var(--gsj-color-bg-muted);
  border: .5px solid var(--gsj-color-border);
  border-radius: var(--gsj-radius-card);
  padding: 24px;
  text-decoration: none;
  transition: border-color var(--gsj-duration-base) var(--gsj-ease-standard);
}

.hub-puerta:hover {
  border-color: var(--gsj-color-primary);
  text-decoration: none;
}

.hub-puerta__title {
  font-family: var(--gsj-font-heading);
  font-size: 1.125rem;
  font-weight: 700;
  margin: 0 0 6px;
  color: var(--gsj-color-text);
}

.hub-puerta__text {
  margin: 0 0 10px;
  font-size: .9375rem;
  line-height: 1.5;
  color: var(--gsj-color-text-secondary);
}

.hub-puerta__cta {
  font-family: var(--gsj-font-heading);
  font-weight: 600;
  font-size: .9375rem;
  color: var(--gsj-color-text-link);
}

/* El aire de la tarjeta genérica dentro de un hub: 22px, que es lo que canoniza
   `experiencias.html`. El default (28px) vive en `turismo-extend.css`. */
.hub-grid .gsj-card__body { padding: 22px }

/* La foto de la tarjeta genérica. El DS la deja en `aspect-ratio:16/9`, que a los ~300px
   de columna que da la grilla a 1280 cae en ~169px — pero en mobile, con una sola columna
   de 366px, se iría a 206px. El kit fija 170px, así que la tira de fotos mantiene la misma
   altura en toda la grilla y a todo ancho. Es seguro porque `.gsj-card__image` ya trae
   `object-fit: cover`: recorta, no deforma. */
.hub-grid .gsj-card__image,
.hub-grid .gsj-card__image-placeholder {
  height: 170px;
  aspect-ratio: auto;
}
/* 🔴 El PLACEHOLDER va en la misma regla y no es un detalle: es otra clase
   (`gsj-card__image-placeholder`), así que sin esto se quedaba con el `16/9` del DS y
   medía **162px contra los 170 de las fotos** — 8px de escalón entre tarjetas vecinas de
   la misma fila. Se ve en cuanto una tarjeta sin foto cae al lado de una con foto, que en
   Experiencias son 4 de 17. Medido, no deducido: la auditoría no lo agarra porque el kit
   dibuja las 17 con `image-slot` y nunca tiene una tarjeta sin imagen. */

/* Categoría sin artículos. Ninguna pantalla del kit lo dibuja —los 3 hubs tienen
   contenido— pero cuatro rutas reales caen acá: `/servicios` y `/planifica-tu-viaje` son
   contenedores cuyo contenido cuelga de subcategorías, y `bodegas-y-productores` y
   `guias-y-aventura` están sin cargar. Lleva margen propio porque es un `<p>` y el
   `p { margin: 1.5rem 0 }` de Gantry se lo pondría igual, pero por accidente.
   ⚠️ El texto es el string del core («…Si se muestran las subcategorías en esta página,
   puede que tengan artículos»), que le habla al administrador y no al visitante.
   Reemplazarlo es decisión de contenido → PENDIENTES §B. */
.hub-vacio {
  margin: 28px 0 0;
  color: var(--gsj-color-text-secondary);
}

/* El paginador del core cuando el listado no entra en una página. No está en
   ninguna pantalla del kit —los 3 hubs entran enteros— pero sí lo necesitan los
   sub-hubs de SERVICIOS, que es donde viven ~600 artículos. */
.hub-paginacion {
  margin-top: 40px;
  display: flex;
  justify-content: center;
}

/* ═══════════════════════════════════════════════════════════════════════════════
   DIRECTORIO DE ATRACTIVOS — `dir-*` (esqueleto rail + panel) y `at-*` (resultados)
   H2.6 etapa 2. Portado de `sjtur-ds/ui_kits/sitio/atractivos.html`.

   Los dos prefijos NO son lo mismo y por eso son dos: `dir-*` es el esqueleto de
   directorio que el kit comparte con `servicios.html` y `busqueda.html` (rail + barra
   mobile + panel), y `at-*` es lo propio de esta pantalla (la grilla y su cabecera de
   resultados). Cuando le toque el turno a Servicios, `dir-*` ya está escrito.

   ⚠️ Al sumar estos prefijos hay que sumarlos también a `scratchpad/auditar_fidelidad.js`,
   o la pantalla queda fuera de la auditoría sin que nada avise. Es la lección de la
   etapa 1, cuando faltaban `hub-` y `at-`.
   ═════════════════════════════════════════════════════════════════════════════ */

.dir-layout { display: flex; flex-direction: column; gap: 20px }

/* 🔴 TRES REGLAS QUE EL KIT NO PUEDE TENER, porque el kit no tiene estado sin JavaScript.

   1. EL RAIL ARRANCA VISIBLE. El kit lo esconde abajo de 900px (`.dir-rail{display:none}`)
      dando por hecho que el panel mobile lo reemplaza — pero el panel lo abre un botón que
      necesita JS. Si el script no corre y el rail está escondido, en un teléfono no hay
      NINGUNA forma de filtrar: ni rail ni panel. Así que el estado base es «visible» y es
      `sjtur-directorio.js` el que, al arrancar, pone `dir-layout--js` y habilita el
      comportamiento del kit. Con JS —que es como se mide la fidelidad— el computado es
      idéntico al del kit a los dos anchos.
   2. `[hidden]` NECESITA `!important`, Y EL ALCANCE ES `.at-main` Y NO `.dir-layout`.
      El atributo `hidden` vale `display:none` con especificidad de hoja de usuario-agente,
      y le ganan `.gsj-card--destino{display:block}`, `.dir-mobile-bar{display:flex}` y
      —la que costó— `.gsj-sheet{position:fixed;inset:0;display:flex}`.
      🔴 El primer intento acotó la regla a `.dir-layout`, y el panel mobile cuelga de
      `.at-main`: quedaba con `display:flex` pese al `hidden`, o sea un scrim a pantalla
      completa TAPANDO LA PÁGINA ENTERA en los dos anchos. No se veía en la auditoría de
      fidelidad —que mide propiedades de elementos, no quién tapa a quién— y lo destapó la
      prueba de comportamiento, al no poder hacer clic en «Ver más».
   3. El acomodo del rail dentro del panel mobile: al abrirlo, el JS MUEVE los bloques del
      rail al `.gsj-sheet__body`, donde ya no tienen la caja del rail. */
.dir-rail { display: block }
.dir-layout--js .dir-rail { display: none }
.at-main [hidden] { display: none !important }
.gsj-sheet__body > .dir-tipos { margin-bottom: 24px }

.dir-mobile-bar { display: flex; flex-direction: column; gap: 10px }
.dir-mobile-actions { display: flex; gap: 8px }

/* Móvil (2026-09-22, medido a 320 px con [U]):
   1 · los controles de la barra medían 36 px: el toque pide 44, y un select con texto <16 px
       dispara el zoom automático de Safari iOS al enfocarlo;
   3 · la bajada del directorio son 6 líneas (156 px) antes del buscador y la primera tarjeta
       arrancaba a 642 px — la primera pantalla entera era cabecera. Mismo criterio que C4 en
       Planificá: en móvil no se dibuja (título, buscador y «N resultados» ya lo dicen);
   4 · la insignia de tipo por fila no se dibuja cuando la lista es homogénea (ver
       `default_results.php`): decía «Prestador» 20 veces por página. */
@media (max-width: 575px) {
  .dir-mobile-actions .gsj-button,
  .dir-mobile-actions .gsj-select,
  .bus-orden .gsj-select,
  .bus-orden .gsj-button { min-height: 44px; }
  .dir-mobile-actions .gsj-select,
  .bus-orden .gsj-select { font-size: 16px; }
  /* Con el select a 16 px el botón «Filtros» quedaba en 88 px y el flex le comprimía el ícono a
     0 de ancho (medido). El ícono no se encoge. */
  .dir-filtros-btn svg { flex: none; }
  .sj-directorio-bajada { display: none; }
  .gsj-results-list--homogenea .gsj-results-kind { display: none; }
}
/* A menos de 360 px el rótulo «Orden:» sobra: el select ya muestra «A → Z» con su flecha.
   🔴 Bloque APARTE, y después del de 575: la primera versión lo abrió en medio del bloque
   anterior y dejó adentro la bajada y la insignia — a 320 andaba y a 425 no. */
@media (max-width: 359px) {
  .dir-mobile-actions .bus-orden__label { display: none; }
}
.dir-filtros-btn { flex: 1; justify-content: center; gap: 8px }
.dir-filtros-btn__n {
  background: var(--gsj-color-primary-fill);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  min-width: 18px;
  height: 18px;
  border-radius: var(--gsj-radius-full);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0 5px;
}

/* `margin:0` por lo mismo que `.gsj-facets__option`: es un `<label>` y nucleus le mete
   6px abajo, que acá descolocaban el selector respecto del botón «Filtros» de al lado. */
.dir-orden { position: relative; flex: 0 0 auto; margin: 0 }
.dir-orden__label {
  position: absolute;
  left: 12px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 11px;
  font-family: var(--gsj-font-heading);
  font-weight: 600;
  color: var(--gsj-color-text-muted);
  pointer-events: none;
}
.dir-orden select {
  min-height: 36px;
  padding: 0 34px 0 58px;
  font-family: var(--gsj-font-heading);
  font-size: 13px;
  font-weight: 600;
  border-radius: 8px;
}

.dir-tipos { display: flex; flex-direction: column; gap: 2px; margin-bottom: 20px }
.dir-tipo {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  text-align: left;
  font-family: var(--gsj-font-heading);
  font-size: 14px;
  padding: 9px 12px;
  border-radius: 8px;
  cursor: pointer;
  border: none;
  background: transparent;
  color: var(--gsj-color-text-secondary);
  font-weight: 500;
  text-decoration: none;
}
.dir-tipo:hover { background: var(--gsj-color-fill-primary) }
.dir-tipo.is-active {
  background: var(--gsj-color-primary-container);
  color: var(--gsj-color-on-primary-container);
  font-weight: 700;
}
/* El contador del subtipo, atenuado: es un dato de apoyo, no la etiqueta. */
.dir-tipo span:last-child { opacity: .7; font-weight: 400 }

/* Los controles que en mobile viven en la barra y en desktop en la fila de resultados.
   El `gap`/`align-items` estaban inline en el kit y se pasaron a la clase en los dos
   lados: un estilo inline no lo puede auditar la guardia de fidelidad. */
.dir-solo-desktop { display: none; gap: 12px; align-items: center }

.at-resultados {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 18px;
}
/* `margin:0` explícito: es un `<p>` y el `p{margin:1.5rem 0}` de nucleus lo infla. */
.at-resultados__n {
  font-family: var(--gsj-font-heading);
  font-size: .9375rem;
  color: var(--gsj-color-text-secondary);
  margin: 0;
}

.at-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px }
@media (min-width: 640px) {
  .at-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px }
}
/* 2026-09-23 (decisión de [U]): el directorio de atractivos queda en 3 columnas también en escritorio. Con 4, al lado
   del riel de filtros la tarjeta medía 198 px y 5 de 11 títulos de Espacios Culturales se cortaban (línea máxima 3);
   con 3 mide 271 px y no se corta ninguno. La tanda de 24 sigue siendo divisible. */
/* 🔴 La tarjeta del directorio es 3/4 y no el 4/5 del DS. Esta regla no tenía efecto
   mientras `SjturCards::atractivo()` escribía `style="aspect-ratio:4/5"` inline: un
   inline le gana a cualquier hoja. Por eso el inline se sacó de PHP — era redundante
   con el valor que el DS ya le da a `.gsj-card--destino`, así que las 3 fichas no se
   movieron. Medido antes y después con `scratchpad/medir_cards_atractivo.js`. */
.at-grid .gsj-card--destino { aspect-ratio: 3 / 4 }

/* El botón de cola. Estaba como `<div style="display:flex;…">` en el kit y pasó a clase
   en los dos lados, por lo mismo que `.dir-solo-desktop`. */
.at-mas { display: flex; justify-content: center; margin-top: 32px }

/* 🔴 EL TÍTULO DE 18px ES DE LAS FICHAS, NO DE LA TARJETA, y por eso vive acá. El kit lo
   escribe inline en `destino.html`, `experiencia.html` y `atractivo.html` —donde la
   tarjeta es chica— y NO lo escribe en el directorio, donde toma la escala del DS
   (`title-3`). Mientras estuvo inline en PHP, el directorio no podía diferenciarse.
   Estas dos grillas son los tres contextos de ficha: `.exp-grid-atr` la usan la ficha de
   Destino y la de Experiencia, `.atr-relgrid` el «Cerca de acá» de la ficha de Atractivo. */
.exp-grid-atr .gsj-card--destino__title,
.atr-relgrid .gsj-card--destino__title { font-size: 1.125rem }

@media (min-width: 900px) {
  .dir-layout { flex-direction: row; gap: 32px; align-items: flex-start }
  .dir-layout--js .dir-rail,
  .dir-rail {
    display: block;
    flex: 0 0 260px;
    position: sticky;
    top: 20px;
    background: var(--gsj-color-surface);
    border: 1px solid var(--gsj-color-border);
    border-radius: 20px;
    padding: 20px;
  }
  .dir-main { flex: 1; min-width: 0 }
  .dir-mobile-bar { display: none }
  .dir-solo-desktop { display: flex }
}


/* ────────────────────────────────────────────────────────────────────────────
   HOME  (`home-*`)  — FASE H2.7
   La portada: hero de campaña estacional, rieles de tarjetas, banda destacada
   y el lightbox del film. Fuente de verdad: `ui_kits/sitio/index.html`.

   🔴 EL SCRIM Y EL BOTÓN DE PLAY NO SON LOS DEL `<style>` ORIGINAL DEL KIT, y
   la diferencia está medida, no estimada. El degradado original (.14 → .30 →
   .74) dejaba el `<h1>` en 2.0–2.9:1 sobre un póster claro, debajo del mínimo
   de 3 que aplica a texto grande, y el botón de play en 1.69:1. Se midió sobre
   PÓSTER BLANCO —el peor caso: el arte lo cambia el cliente cada temporada y el
   contraste no puede depender de que la foto sea oscura— y los valores de acá
   son los que pasan 6/6 a 1280 y a 390px (H2.4, `scratchpad/contraste_hero.js`).
   Los dos problemas se resuelven distinto a propósito: el título y los chips
   viven en la banda inferior, así que se sube el piso del degradado AHÍ y el
   techo queda casi como el kit —oscurecer de más apagaría la foto de campaña,
   que es lo que el hero está para mostrar—; el play flota arriba, fuera del
   degradado, y por eso lleva superficie propia en vez de costar un techo negro.
   ──────────────────────────────────────────────────────────────────────────── */

/* ---- Hero de campaña (slot campaign-agnostic) ---- */
.home-hero {
  position: relative;
  min-height: 560px;
  display: flex;
  flex-direction: column;
  /* Dónde se para el bloque en vertical: parámetro de campaña, `abajo` por defecto. */
  justify-content: var(--sjtur-vertical, flex-end);

  /* Los tres scrims posibles, definidos ACÁ y no en el Twig: el particle sólo elige cuál, con
     `--sjtur-scrim: var(--scrim-arriba)`. Un degradado no es un escalar y no tiene por qué
     viajar en un atributo `style`.

     🔴 Y NO ES DECORACIÓN: el scrim es lo único que sostiene el contraste del texto sobre una
     foto que cambia cada temporada. Por eso la banda oscura VIAJA CON EL BLOQUE — si el
     contenido sube y el degradado se queda pesando abajo, el texto termina sobre el 16% de
     alfa y, con un póster claro, el hero deja de cumplir AA sin que nadie toque una línea. */
  --scrim-abajo: linear-gradient(180deg,
    rgba(15, 15, 20, .16) 0%, rgba(15, 15, 20, .34) 30%, rgba(15, 15, 20, .52) 50%,
    rgba(15, 15, 20, .74) 78%, rgba(15, 15, 20, .80) 100%);
  --scrim-arriba: linear-gradient(0deg,
    rgba(15, 15, 20, .16) 0%, rgba(15, 15, 20, .34) 30%, rgba(15, 15, 20, .52) 50%,
    rgba(15, 15, 20, .74) 78%, rgba(15, 15, 20, .80) 100%);
  --scrim-centro: linear-gradient(180deg,
    rgba(15, 15, 20, .18) 0%, rgba(15, 15, 20, .58) 26%, rgba(15, 15, 20, .70) 50%,
    rgba(15, 15, 20, .58) 74%, rgba(15, 15, 20, .18) 100%);

  /* Los laterales oscurecen la COLUMNA del texto en vez de una banda de lado a lado. Nacieron de
     un caso concreto: con el contenido a la derecha y el protagonista de la foto a la izquierda,
     cualquier velo horizontal le pasa por la cara sin necesidad de taparla.
     Las paradas no son las verticales rotadas: el bloque de contenido arranca cerca del 38% del
     ancho (máx. 1200px centrados, columna de ~680), así que el velo tiene que estar CLARO hasta
     ahí y ya oscuro cuando empieza el texto. Rotar el degradado vertical dejaba el arranque del
     claim en el tramo suave. */
  --scrim-derecha: linear-gradient(90deg,
    rgba(15, 15, 20, .08) 0%, rgba(15, 15, 20, .20) 22%, rgba(15, 15, 20, .56) 44%,
    rgba(15, 15, 20, .74) 70%, rgba(15, 15, 20, .78) 100%);
  --scrim-izquierda: linear-gradient(270deg,
    rgba(15, 15, 20, .08) 0%, rgba(15, 15, 20, .20) 22%, rgba(15, 15, 20, .56) 44%,
    rgba(15, 15, 20, .74) 70%, rgba(15, 15, 20, .78) 100%);
  /* SIN overflow:hidden. Era defensivo (media/scrim son inset:0 + cover, nada desborda)
     y recortaba el panel de sugerencias del buscador, que cae por debajo del borde del
     hero (tramo 3). Si algun dia una pieza del hero necesita recorte, va en ESA pieza. */
  color: #fff;
}

.home-hero__media { position: absolute; inset: 0; z-index: 0 }

/* `image-slot` es el placeholder del kit; en el sitio el particle emite <picture>/<img>. */
.home-hero__media image-slot,
.home-hero__media picture,
.home-hero__media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Foco del recorte. El póster desktop es 2400x600 (4:1) y el hero ronda 2.3:1, así que `cover`
   descarta ~1000px a los costados: qué mitad se pierde es una decisión del ARTE de la temporada,
   no del layout, y por eso viaja como variable desde el particle. El corte de 768px es el mismo
   del `<source>` del <picture>: abajo de ahí ya se está viendo otra foto, con su propio foco. */
.home-hero__media img { object-position: var(--sjtur-foco-x, 50%) var(--sjtur-foco-y, 50%) }

@media (max-width: 768px) {
  .home-hero__media img {
    object-position: var(--sjtur-foco-x-m, var(--sjtur-foco-x, 50%))
                     var(--sjtur-foco-y-m, var(--sjtur-foco-y, 50%));
  }
}

.home-hero__scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: var(--sjtur-scrim, var(--scrim-abajo));
}

.home-hero__inner {
  /* 🔴 SIN `position: relative`, y es a propósito. El bloque contenedor de la fila del play
     tiene que ser `.home-hero` para poder soltarla contra el techo del hero (ver más abajo); si
     `__inner` estuviera posicionado, la fila se anclaría a ÉL y "arriba" seguiría al bloque en
     vez de al hero. El `z-index` no necesita `position`: `__inner` es un ítem flex, y ahí
     z-index aplica igual. Y el panel de sugerencias del buscador no se ve afectado: se ancla a
     `.gsj-suggest` (el formulario), no acá. */
  z-index: 2;
  width: 100%;
  max-width: 1200px;
  margin: 0 auto;
  padding: clamp(28px, 5vw, 56px) clamp(20px, 5vw, 64px) clamp(36px, 5vw, 64px);
  display: flex;
  flex-direction: column;
  gap: clamp(16px, 2.4vw, 22px);
}

/* ---- Alineación del bloque de contenido (parámetro de campaña) ----
   Mueve play + claim + buscador + chips COMO UNO SOLO. Es la otra mitad de `--sjtur-foco`: con
   el foco se elige qué parte de la foto sobrevive al recorte, y con esto, de qué lado se para el
   texto para no pisarla.

   🔴 Las piezas de ancho completo NO se alinean con `align-items`. `.home-hero__toprow` y
   `.home-chips` son filas flex y `.home-chips` además scrollea en horizontal: si se las dejara
   encoger a su contenido, en mobile los chips desbordarían el hero en vez de scrollear. Se les
   fija `width: 100%` y se las alinea por dentro con `justify-content`. Y va `safe` porque
   `flex-end` con contenido que desborda deja el PRIMER ítem fuera de alcance del scroll. */
.home-hero__inner { align-items: var(--sjtur-alinear, flex-start) }

.home-hero__search,
.home-chips { width: 100% }

/* La fila del play va a `stretch` y no a `width: 100%` porque tiene que poder despegarse: con un
   ancho declarado, `left` + `right` quedan sobredeterminados y el centrado del modo suelto se
   rompe. `align-self` lo ignora un elemento absoluto, así que sirve para los dos modos. */
.home-hero__toprow { align-self: stretch }

.home-hero__toprow,
.home-chips { justify-content: safe var(--sjtur-alinear, flex-start) }

/* ---- Play suelto: pegado al techo del hero, fuera del bloque ----
   Para qué: cuando el bloque de contenido está al centro o abajo, el techo de la foto queda
   vacío y el play puede vivir ahí en vez de comerse una línea del bloque. Lo pidió el uso real
   en mobile.

   🔴 TODA LA GEOMETRÍA DE ABAJO ES INERTE MIENTRAS `position` SEA `static`, y por eso alcanza con
   UNA sola variable para cambiar de modo: `top`/`left`/`right` no aplican a un elemento estático,
   `margin-inline: auto` no reparte nada sobre un ítem estirado, y el `max-width` nunca llega a
   morder porque `__inner` ya es más angosto. Escribirlo así evita las seis variables que haría
   falta declarar para togglear cada propiedad por separado.

   Las insets replican a mano el contenedor de `__inner` —máx. 1200 centrado, más su padding—
   porque el punto de anclaje pasó a ser el hero entero: sin eso el botón se pegaría al borde de
   la pantalla y no a la columna de la página.

   🔴 Y NO se hace con `max-width` + `margin-inline: auto`, que era lo obvio: si un margen del eje
   transversal es `auto`, el flex ignora `align-self: stretch` y encoge el ítem a su contenido.
   O sea que el atajo del modo suelto ROMPÍA el modo normal — el botón se iba al centro. Medido a
   508px: quedaba en x=146 cuando le tocaba x=25. Con las insets calculadas el modo estático no se
   entera de nada. */
.home-hero__toprow {
  position: var(--sjtur-play-pos, static);
  top: clamp(28px, 5vw, 56px);
  left: calc(max(0px, (100% - 1200px) / 2) + clamp(20px, 5vw, 64px));
  right: calc(max(0px, (100% - 1200px) / 2) + clamp(20px, 5vw, 64px));
  z-index: 2;
}

/* 🔴 El `text-align` va SÓLO en el título, no en `__inner`. Puesto en el contenedor se heredaba
   a todo: el placeholder del buscador quedaba alineado a la derecha —que se lee como un campo
   roto— y los chips reportaban divergencia contra el kit sin tener diferencia visible (son
   inline-flex: ahí manda `justify-content`, no `text-align`). El título es el único texto del
   hero que fluye en varias líneas y necesita saber de qué lado está su margen. */
.home-hero__title { text-align: var(--sjtur-alinear-texto, left) }

/* Mobile tiene su propio juego de perillas porque abajo de 768px el `<picture>` ya está sirviendo
   OTRA foto —el recorte vertical—, con su propio protagonista y su propio aire. Heredar de desktop
   sería heredar decisiones tomadas mirando una imagen que en mobile no se ve. */
@media (max-width: 768px) {
  .home-hero { justify-content: var(--sjtur-vertical-m, var(--sjtur-vertical, flex-end)) }
  .home-hero__scrim { background: var(--sjtur-scrim-m, var(--sjtur-scrim, var(--scrim-abajo))) }

  .home-hero__inner { align-items: var(--sjtur-alinear-m, var(--sjtur-alinear, flex-start)) }
  .home-hero__title { text-align: var(--sjtur-alinear-texto-m, var(--sjtur-alinear-texto, left)) }
  .home-hero__toprow,
  .home-chips { justify-content: safe var(--sjtur-alinear-m, var(--sjtur-alinear, flex-start)) }
  .home-hero__toprow { position: var(--sjtur-play-pos-m, var(--sjtur-play-pos, static)) }
}

.home-hero__toprow { display: flex; align-items: center; gap: 16px; flex-wrap: wrap }

.home-hero__play {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  padding: 0 18px 0 12px;
  border: 1px solid rgba(255, 255, 255, .28);
  border-radius: var(--gsj-radius-full);
  background: rgba(15, 15, 20, .72);
  backdrop-filter: blur(4px);
  color: #fff;
  font-family: var(--gsj-font-heading);
  font-weight: 500;
  font-size: 14px;
  cursor: pointer;
}

.home-hero__play:hover,
.home-hero__play:focus-visible { background: rgba(15, 15, 20, .86) }

.home-hero__play:focus-visible { outline: 3px solid #fff; outline-offset: 2px }

.home-hero__play-glyph {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: var(--gsj-radius-full);
  background: #fff;
  font-size: 11px;
}

/* El acento de la temporada, confinado al hero: lo emite el particle como
   `--sjtur-acento` en el `style` de la sección y nunca toca al resto del sitio. */
.home-hero .home-hero__play-glyph { color: var(--sjtur-acento, var(--gsj-color-primary-text)) }

.home-hero__title {
  margin: 0;
  font-family: var(--gsj-font-heading);
  font-weight: 700;
  font-size: clamp(2rem, 4.8vw, 3.4rem);
  line-height: 1.04;
  color: #fff;
  text-shadow: 0 1px 14px rgba(0, 0, 0, .38);
  text-wrap: balance;
  max-width: 16ch;
}

.home-hero__claim-img { max-width: min(560px, 80%); height: auto }

.home-hero__search { max-width: 680px; width: 100% }

/* Chips = las 3 preguntas del viajero, integradas al gesto de buscar. */
.home-chips { display: flex; gap: 10px; overflow-x: auto; scrollbar-width: none;
  /* Aire para el anillo de foco (outline 3 px + offset 2 px = 5 px): un contenedor con overflow lo
     RECORTA, y un foco mordido es una alerta de accesibilidad (WCAG 2.4.7). 6 px de padding y el
     mismo margen negativo: el foco entra entero y la fila no se mueve de lugar. (2026-09-25) */
  padding: 6px; margin: -6px; width: calc(100% + 12px) }
.home-chips::-webkit-scrollbar { display: none }

/* Mobile: la fila SANGRA hasta el borde de la pantalla (2026-09-25, iPhone 15 de [U]). Dentro del padding
   de `__inner` el último chip quedaba cortado en seco a 20 px del borde, sobre la foto: se leía como un
   error y no como algo que se desliza. Ahora arranca alineada con el buscador (padding = el gutter de
   `__inner`), corre hasta el borde real y se desvanece SÓLO en el gutter final (accesibilidad: al llegar al final del scroll ningún texto queda bajo el desvanecido, así el contraste no baja). El gutter repite el clamp de
   `.home-hero__inner`: si ése cambia, cambia acá. `scroll-padding` deja el primer chip alineado al volver. */
@media (max-width: 767px) {
  .home-chips {
    --chips-gutter: clamp(20px, 5vw, 64px);
    width: calc(100% + 2 * var(--chips-gutter));
    margin-inline: calc(-1 * var(--chips-gutter));
    padding-inline: var(--chips-gutter);
    scroll-padding-inline: var(--chips-gutter);
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - var(--chips-gutter)), transparent);
            mask-image: linear-gradient(to right, #000 calc(100% - var(--chips-gutter)), transparent);
  }
  /* Con TRES chips la sangría sola no alcanza: «Alojamiento» asomaba cortado por ~20 px y seguía
     pareciendo un error. Medido (texto 63+91+88 px, borde 1): hoy necesitan 376 px y en un iPhone
     de 390–393 hay 350–353. Con 13 px de relleno y 8 de separación → 342 (entran con margen para
     el render de Safari). El desvanecido queda para lo que siga sin entrar. */
  .home-chips { gap: 8px }
  .home-chips .home-chip { padding-inline: 13px }  /* doble clase: la regla base de `.home-chip` va DESPUÉS */
}
/* iPhone SE / mini (375 → 335 útiles): 11 + 6 → 326. Por debajo de 360 desborda y manda el desvanecido. */
@media (max-width: 389px) {
  .home-chips { gap: 6px }
  .home-chips .home-chip { padding-inline: 11px }
}

.home-chip {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  padding: 9px 18px;
  border-radius: var(--gsj-radius-full);
  background: rgba(255, 255, 255, .92);
  color: var(--gsj-color-text);
  text-decoration: none;
  border: 1px solid rgba(255, 255, 255, .5);
  font-family: var(--gsj-font-heading);
  font-weight: 600;
  font-size: 15px;
}

.home-chip:hover { background: #fff }
.home-chip:focus-visible { outline: 3px solid #fff; outline-offset: 2px }

@media (max-width: 900px) {
  .home-hero__title { font-size: clamp(1.9rem, 7vw, 2.2rem) }
}

/* ---- Rieles (carruseles horizontales de tarjetas) ----
   El ancho del ítem es maquetación de PÁGINA y no de la tarjeta: la misma card
   sale más angosta en un riel de la home que en la grilla de un hub. */
.home-rail__item { scroll-snap-align: start }

/* Reserva el espacio de los puntos (que van `position:absolute; bottom:12px` en
   el DS) SÓLO cuando hay puntos. La clase la pone `sjtur-carousel.js` al medir
   el ancho real: un riel sin desborde no debe pagar 44px de aire. */
main .gsj-carousel.has-dots { padding-bottom: 44px }

.home-rail--destinos .home-rail__item { flex: 1 1 220px; min-width: 220px }

/* 🔴 `1 1` y no el `0 0 300px` del kit, y la diferencia se ve con CUATRO tarjetas: con ancho
   fijo, 4×300 + 3 gaps = 1224 contra 1216 de área útil ⇒ **desborda 8 píxeles**, y por esos
   8px el carrusel dibuja flechas y puntos que no llevan a ninguna parte. El kit no lo revela
   porque su mock trae 5, donde el desborde es real. Es el mismo arreglo que el riel de
   atractivos ya tenía —ahí el ancho fijo dejaba 120px muertos a la derecha—: el ancho de la
   tarjeta lo decide el riel, no un número copiado. `min-width` es lo que conserva el
   comportamiento con 5 o más (encogen hasta 280 y recién entonces scrollean). */
.home-rail--exp .home-rail__item { flex: 1 1 300px; min-width: 280px }

/* `flex: 1 1` (no `0 0`) como el riel de destinos: con 4 ítems de ancho fijo
   sobraban 120px muertos a la derecha en 1280 y 1440px, que se leían como un
   error de layout. Ahora crecen para llenar el riel, y el `min-width` los deja
   desbordar —y scrollear, que es para lo que está el carrusel— recién cuando no
   entran. */
.home-rail--atr .home-rail__item { flex: 1 1 268px; min-width: 268px }

/* El riel de atractivos usa la tarjeta de destino en formato alto y con el
   título en la escala chica. En el kit esto va inline sobre cada tarjeta; acá
   es una regla de contexto, por el mismo criterio que `.exp-grid-atr`: el
   contexto lo declara la pantalla, no la card. */
.home-rail--atr .gsj-card--destino { aspect-ratio: 4/5 }
.home-rail--atr .gsj-card--destino__title { font-size: 1.125rem }

/* Las tarjetas de Experiencia del kit llevan el cuerpo con más aire que en un hub. */
.home-rail--exp .gsj-card__body { padding: 28px }

/* 🔴 ESTA REGLA NO ESTÁ EN EL KIT Y NO ES UN OLVIDO: el kit no la necesita porque su
   mock escribe bajadas parejas de dos líneas. Con el contenido real, los cinco teasers
   miden distinto —«Astroturismo: San Juan capital nacional del turismo astronómico» se
   lleva tres líneas de título— y las tarjetas quedaban de 409, 501, 431, 409 y 409px:
   cinco fondos blancos escalonados dentro de la misma banda. `gsj-card--destino` no
   sufre esto porque tiene `aspect-ratio` fijo; `gsj-card` crece con su contenido.
   El ítem del riel pasa a ser contenedor flex y la tarjeta se estira al alto del riel. */
.home-rail--exp .home-rail__item { display: flex }
.home-rail--exp .home-rail__item > .gsj-card { width: 100% }

.home-rail__cierre {
  margin: 12px 0 0;
  font-size: 15px;
  color: var(--gsj-color-text-secondary);
}

@media (max-width: 720px) {
  .home-rail--destinos .home-rail__item { flex: 0 0 240px }
  /* En mobile no hay espacio que repartir —entra una tarjeta y media— así que vuelve al
     ancho fijo del kit: dejarla flexible la encogería a 280 sin ganar nada. */
  .home-rail--exp .home-rail__item { flex: 0 0 300px }
}

@media (prefers-reduced-motion: reduce) {
  .gsj-carousel__track { scroll-behavior: auto }
}

/* ---- Banda destacada (un solo contenido a dos columnas) ---- */
.home-band {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: stretch;
  border-radius: var(--gsj-radius-lg);
  overflow: hidden;
}

.home-band__media { position: relative; min-height: 360px }

.home-band__media image-slot,
.home-band__media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.home-band__body {
  display: flex;
  flex-direction: column;
  gap: 14px;
  justify-content: center;
  padding: clamp(28px, 4vw, 48px);
  background: var(--gsj-color-bg-subtle);
}

.home-band__badges { display: flex; gap: 8px; flex-wrap: wrap }

.home-band__title {
  margin: 0;
  font-family: var(--gsj-font-heading);
  font-weight: 700;
  font-size: clamp(1.8rem, 3vw, 2.25rem);
  line-height: 1.08;
  color: var(--gsj-color-text);
}

.home-band__text {
  margin: 0;
  font-size: 16px;
  line-height: 1.65;
  color: var(--gsj-color-text-secondary);
  max-width: 48ch;
  text-wrap: pretty;
}

.home-band__acciones { display: flex; gap: 12px; flex-wrap: wrap; padding-top: 4px }

/* La banda va pegada al riel de arriba: son el mismo bloque de lectura. */
.home-seccion--pegada { padding-top: 0 }

@media (max-width: 720px) {
  .home-band { grid-template-columns: 1fr }
  .home-band__media { min-height: 220px }
}

/* ---- Lightbox del film (facade: el iframe se inyecta al abrir) ---- */
.home-overlay[hidden] { display: none }

.home-lightbox {
  position: fixed;
  inset: 0;
  z-index: 1000;
  background: rgba(10, 10, 12, .9);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(16px, 5vw, 64px);
}

.home-lightbox__panel {
  width: 100%;
  max-width: 960px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.home-lightbox__frame {
  position: relative;
  aspect-ratio: 16/9;
  border-radius: var(--gsj-radius-lg);
  overflow: hidden;
  background: #0c0c10;
  display: flex;
  align-items: center;
  justify-content: center;
  color: rgba(255, 255, 255, .75);
}

.home-lightbox__frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0 }


/* ────────────────────────────────────────────────────────────────────────────
   BÚSQUEDA  (`bus-*`, `sj-busqueda-*`)  — FASE H2.7
   La página de resultados de Smart Search. Fuente de verdad:
   `ui_kits/sitio/busqueda.html` y `busqueda-estados.html`.

   El prefijo es doble a propósito: `bus-*` es lo que el kit ya nombraba
   (layout de dos columnas, rail, barra mobile, orden) y `sj-busqueda-*` es lo
   que el kit resolvía con `style=""` inline y acá necesita clase porque lo
   emite un override de PHP, no un HTML suelto.
   ──────────────────────────────────────────────────────────────────────────── */

/* ---- Cabecera: buscador + h1 + bajada ---- */
.sj-busqueda-cabecera { padding-top: 28px; padding-bottom: 28px }
.sj-busqueda-form { max-width: 640px }

/* Escala estándar del DS (48/32). El kit lo anota: a 24px era el h1 más chico
   del kit, la mitad que servicios, que es la misma clase de página. */
/* El `margin-bottom` es el canon de la fila 11 (12px de gap h1→bajada, en las 5 pantallas).
   El `margin-top` de 24 NO es el canon de 20 y es a propósito: acá arriba del h1 no hay
   breadcrumb sino el buscador, que es el control de esta página. Ver la nota de la fila 11. */
.sj-busqueda-titulo { margin: 24px 0 12px; text-wrap: balance }
.sj-busqueda-bajada { color: var(--gsj-color-text-secondary); margin: 0 }

/* 🔴 `padding-top` explícito: sin él la bajada queda a 0px del cambio de fondo a
   `bg-subtle`, con los descendentes de la tipografía tocando la línea. El kit lo
   documenta en dos pantallas (ésta y servicios). */
.sj-busqueda-cuerpo { padding-top: 28px; background: var(--gsj-color-bg-subtle) }

/* ---- Layout de dos columnas ---- */
.bus-layout { display: flex; flex-direction: column; gap: 20px }
/* 🔴 EL RAIL ARRANCA VISIBLE también en mobile (contrato progresivo del bloque dir-*):
   esconderlo de base contaba con un panel que sólo existe con JS — sin JS no había forma
   de filtrar en un teléfono, y el toggle viejo ni se veía (`display:none` de esta regla
   le ganaba al atributo `hidden` que el JS sacaba). `sjtur-buscador.js` pone
   `dir-layout--js` cuando el bottom-sheet está operativo, y recién entonces se esconde. */
.bus-rail { display: block }
.dir-layout--js.bus-layout .bus-rail { display: none }
.bus-mobile-bar { display: flex; flex-direction: column; gap: 10px }
.bus-mobile-bar__fila { display: flex; gap: 8px }
.bus-mobile-bar__filtros { flex: 1; justify-content: center; gap: 8px }

/* El selector de orden existe dos veces (barra mobile y barra de resultados
   desktop): sólo uno se muestra por breakpoint. */
.bus-solo-desktop { display: none }

/* 🔴 EL KIT TIENE DOS TRATAMIENTOS DEL SELECTOR, NO UNO. En la barra mobile la etiqueta
   va DENTRO del control («Orden:», absoluta sobre el select, que le reserva la sangría) y
   en la barra de resultados va al lado («Ordenar:»). No es cosmético: a 390 el control con
   la etiqueta afuera medía 188px contra los 161px del kit, y esos 27px se los sacaba al
   botón «Filtros», que comparte la fila — medido, 173px en el kit contra 146px acá.
   La variante la decide el LLAMADOR (`$this->sjturOrdenVariante` en `default_results.php`)
   y viaja como clase modificadora, no como media query: cada instancia se muestra a un
   solo ancho, así que atarlo al breakpoint sería describir dos veces la misma condición. */
.bus-orden { position: relative; flex: 0 0 auto; display: flex; align-items: center; gap: 8px }

.bus-orden__label {
  /* El `margin-bottom: 6px` que traen los `<label>` del sitio no es inocuo acá: como ítem
     flex con `align-items: center`, el margen entra en el centrado y sube la etiqueta 3px
     respecto del select. En el kit la etiqueta es un `<span>` y no lo arrastra. */
  margin: 0;
  font-family: var(--gsj-font-heading);
  font-size: 13px;
  font-weight: 600;
  color: var(--gsj-color-text-muted);
}

/* 🔴 `.gsj-select` NO EXISTE EN EL KIT — está sólo en `portal.css`, del lado del sitio —,
   así que el mock dibuja el `<select>` pelado del navegador y acá sale el componente del
   DS. Es el sitio el que tiene razón, pero trae `padding: 10px 40px 10px 16px` y con eso
   el control se iba a 43px de alto contra los 40 que el kit declara. El `min-height` solo
   no alcanza: mientras el padding vertical mande, la altura la pone el contenido. Se anula
   el vertical y se deja el horizontal, que es el que reserva el lugar del chevron.
   `width: auto` porque `.gsj-select` es `display:block; width:100%` — correcto para un
   campo de formulario, no para un control que en esta fila se dimensiona por su contenido. */
.bus-orden select {
  width: auto;
  min-height: 40px;
  padding-top: 0;
  padding-bottom: 0;
  font-family: var(--gsj-font-heading);
  font-size: 14px;
  font-weight: 600;
  line-height: normal;
  border-radius: 8px;
}

/* La variante de la barra mobile: etiqueta sobre el control. */
.bus-orden--inset .bus-orden__label {
  position: absolute;
  left: 12px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 11px;
  pointer-events: none; /* está ENCIMA del select: sin esto se come el clic */
}

.bus-orden--inset select {
  min-height: 36px;
  padding-left: 58px;
  font-size: 13px;
}

.bus-nota {
  font-size: var(--gsj-font-size-caption-1);
  color: var(--gsj-color-text-muted);
  line-height: 1.5;
  margin: 6px 0 0;
}

.bus-rail__form { display: flex; flex-direction: column; gap: 16px }
.bus-rail__aplicar { align-self: flex-start }

/* 🔴 `[hidden]` NO ALCANZA CUANDO EL COMPONENTE DECLARA `display`. El JS oculta los dos
   fallbacks (aplicar filtros / ir) poniéndoles `hidden`, pero `.gsj-button` trae
   `display:inline-flex` y le gana al `[hidden]{display:none}` del navegador, que es una
   regla de user-agent. Resultado medido: `el.hidden === true` y el botón igual se veía.
   Se ve en la captura, no en la propiedad. */
.bus-rail__aplicar[hidden],
.bus-orden__ir[hidden] { display: none }

/* El rail lista TODOS los valores del índice, y con este catálogo eso son 31 actividades y
   19 departamentos: medido, el rail quedaba en 3424px contra 3830px de resultados — un
   filtro más largo que lo que filtra. Cada rama muestra las primeras y esconde el resto
   tras un `<details>`, que es el «ver más» que pide el kit y no necesita JavaScript. */
.gsj-facets__mas { margin-top: 2px }

.gsj-facets__mas > summary {
  cursor: pointer;
  font-family: var(--gsj-font-heading);
  font-size: 13px;
  font-weight: 600;
  color: var(--gsj-color-primary-text);
  list-style: none;
  padding: 4px 0;
}

.gsj-facets__mas > summary::-webkit-details-marker { display: none }
.gsj-facets__mas > summary:focus-visible { outline: 2px solid var(--gsj-color-primary); outline-offset: 2px }
.gsj-facets__mas[open] > summary { margin-bottom: 4px }

/* ---- Autocompletado (awesomplete, del core) ----
   ⚠️ MÍNIMO DE MARCA, NO EL DISEÑO DEL KIT. `busqueda-estados.html` especifica otra cosa
   —sugerencias agrupadas por entidad, con badge y subtítulo, y un «Ver todos los
   resultados de “x”» al pie— y el core devuelve una lista plana de TÉRMINOS del índice.
   Esto sólo evita que el desplegable salga crudo: el `<mark>` de awesomplete quedaba con
   el amarillo por defecto del navegador, porque nadie estilaba `mark` en el DS.
   El estilo del core (`com_finder.finder`) NO se carga a propósito: ver el porqué en
   `html/com_finder/search/default.php`. */
/* 🔴 AWESOMPLETE ENVUELVE EL `<input>` EN UN `<div>`, y eso rompe en silencio cualquier
   layout flex que contara con que el campo era hijo directo. `.gsj-hero__search-form` es
   flex y su `.gsj-input` tiene `width:100%`: como ítem flex crecía y empujaba el botón
   «Buscar» al borde. Al montarse el autocompletado el ítem pasó a ser el wrapper —sin
   `flex`—, el campo se desplomó a 196px de los 653 del formulario y el botón se fue al
   medio de la barra. Se ve en la captura, no en la lista de sugerencias. */
.gsj-hero__search-form .awesomplete {
  flex: 1;
  min-width: 0;
}

.awesomplete > ul {
  background: var(--gsj-color-surface);
  border: 1px solid var(--gsj-color-border);
  border-radius: var(--gsj-radius-lg);
  box-shadow: 0 8px 24px rgba(60, 60, 67, 0.14);
  padding: 6px;
  margin-top: 6px;
}

.awesomplete > ul > li {
  padding: 9px 12px;
  border-radius: var(--gsj-radius-sm);
  font-family: var(--gsj-font-body);
  font-size: 15px;
  color: var(--gsj-color-text);
}

.awesomplete > ul > li:hover,
.awesomplete > ul > li[aria-selected="true"] {
  background: var(--gsj-color-primary-light);
  color: var(--gsj-color-text);
}

/* El resaltado del tramo que coincide. `background: transparent` no alcanza: el amarillo
   viene del user-agent sobre `<mark>`, y sin declarar `color` el texto queda ilegible
   cuando la fila está resaltada. */
.awesomplete mark,
.awesomplete > ul > li[aria-selected="true"] mark {
  background: transparent;
  color: inherit;
  font-weight: 700;
}

/* ---- Estado sin resultados ---- */
.sj-busqueda-vacio { max-width: 60ch; padding: 8px 0 24px }

.sj-busqueda-vacio__titulo {
  font-family: var(--gsj-font-heading);
  font-weight: 700;
  font-size: clamp(1.5rem, 3vw, 1.75rem);
  line-height: 1.15;
  color: var(--gsj-color-text);
  margin: 0 0 10px;
}

.sj-busqueda-vacio__texto {
  font-size: 16px;
  line-height: 1.65;
  color: var(--gsj-color-text-secondary);
  margin: 0;
  text-wrap: pretty;
}

.sj-busqueda-vacio__sugerencia { margin: 14px 0 0; font-size: 16px }
.sj-busqueda-vacio__salidas { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 24px }

/* 🔴 El kit sube el gap del componente en ESTA pantalla: `busqueda.html` escribe
   `gap:16px` inline sobre `.gsj-results-list`, que en `turismo-components.css` vale 14.
   No es ruido del mock — `servicios.html` usa la misma lista y se queda en 14: acá cada
   fila lleva ENCIMA su rótulo de tipo («Atractivo · Lugar para visitar»), y con 14 ese
   rótulo quedaba casi tan cerca de la tarjeta de arriba como de la suya. */
.sj-busqueda-cuerpo .gsj-results-list { gap: 16px }

.sj-busqueda-paginacion { margin-top: 28px }

@media (min-width: 900px) {
  .bus-layout { flex-direction: row; gap: 32px; align-items: flex-start }

  /* El par con `dir-layout--js` es OBLIGATORIO acá (espejo de la regla del bloque dir-*,
     linea ~1082): sin el, el `display:none` de `.dir-layout--js.bus-layout .bus-rail` le
     gana por especificidad y el rail desaparece TAMBIEN en escritorio en cuanto corre el
     JS del sheet. Medido 2026-08-03 (tramo 4): rail oculto a 1280 en /busqueda-avanzada. */
  .dir-layout--js.bus-layout .bus-rail,
  .bus-rail {
    display: block;
    flex: 0 0 260px;
    position: sticky;
    top: 20px;
    background: var(--gsj-color-surface);
    border: 1px solid var(--gsj-color-border);
    border-radius: 20px;
    padding: 20px;
  }

  .bus-main { flex: 1; min-width: 0 }
  .bus-mobile-bar { display: none }
  .bus-solo-desktop { display: flex; align-items: center; gap: 8px }

  /* Con JS el rail se pliega en mobile poniéndole `hidden`; en desktop ese atributo
     no debe sobrevivir. El JS lo limpia, y esto es la red por si no corre. */
  .bus-rail[hidden] { display: block }
}

/* ═══════════════════════════════════════════════════════════════════════════════════════
   DIRECTORIO DE SERVICIOS — `sj-directorio-*` + lo que el bloque dir-* de Atractivos no
   traía (H2.7, tramo 2). Fuente: `servicios.html`. El esqueleto del rail, la barra mobile,
   la nav de tipos y el sheet ya estaban escritos arriba (`dir-*`); acá va sólo lo nuevo:
   la cabecera, el buscador del directorio, la descarga, el estado vacío y los chips.
   ═══════════════════════════════════════════════════════════════════════════════════════ */

/* CANON DE CABECERA (fila 11). `padding-top: 0`, no 20: en el SITIO el breadcrumb es un
   módulo de Joomla que vive FUERA de este contenedor, así que su padding caía DEBAJO de la
   miga y se sumaba al margen del h1 (20+16=36 ⇒ h1 en 185, contra 169 de atractivos y
   experiencias — el salto que se ve al navegar). En el KIT la miga va DENTRO del contenedor
   y ese mismo padding se consume ARRIBA de ella: por eso el kit daba 165 y el sitio 185 con
   el mismo CSS. El canon pone los 20px donde significan lo mismo en los dos: el margin-top
   del h1, igual que en `.ag-h1`. */
.sj-directorio-cabecera { padding-top: 0; padding-bottom: 32px }
.sj-directorio-titulo { margin: 20px 0 12px }
.sj-directorio-bajada { color: var(--gsj-color-text-secondary); max-width: 620px; margin: 0 0 16px }

/* padding-top explícito, mismo motivo documentado en `.sj-busqueda-cuerpo`: es aire de
   los filtros, no del buscador, que ya empuja con el padding-bottom de la cabecera. */
.sj-directorio-cuerpo { padding-top: 32px; background: var(--gsj-color-bg-subtle) }

/* Buscador del directorio: barra-botón en mobile (navega a la búsqueda), formulario
   inline en desktop. Del kit, literal. */
.dir-buscar-mobile {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  margin-top: 20px;
  background: var(--gsj-color-surface);
  border: 1px solid var(--gsj-color-border);
  border-radius: var(--gsj-radius-full);
  box-shadow: 0 1px 3px rgba(0, 0, 0, .08);
  padding: 0 16px;
  min-height: 48px;
  text-decoration: none;
  font-family: var(--gsj-font-heading);
  font-size: 15px;
  color: var(--gsj-color-text-muted);
}
.dir-buscar-desktop { display: none; max-width: 560px }

.dir-descarga {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: none;
  border: none;
  color: var(--gsj-color-text-muted);
  font-family: var(--gsj-font-heading);
  font-size: 13px;
  font-weight: 600;
  line-height: normal; /* hereda 1.625 del body y el botón crece a 29px; el kit mide 23 */
  opacity: .55;
  cursor: not-allowed;
  padding: 4px;
}
.dir-descarga svg { width: 15px; height: 15px }

.dir-nota {
  font-size: var(--gsj-font-size-caption-1);
  color: var(--gsj-color-text-muted);
  line-height: 1.5;
  margin: 6px 0 0;
}

/* El estado vacío del directorio vive DENTRO de `dir-main`: el rail con la nav de tipos
   se queda (es navegación), y los chips de arriba muestran qué filtros hay puestos. */
.dir-vacio { max-width: 60ch; padding: 8px 0 24px }

/* 🔴 `[hidden]` NECESITA `!important` EN LAS PANTALLAS DEL BUSCADOR, y es la MISMA regla
   que ya está escrita para `.at-main` (ver el bloque del directorio de Atractivos): todo
   componente que declara su `display` (`.gsj-sheet`, `.dir-mobile-bar`, `.gsj-button`) le
   gana al `[hidden]` del navegador, que es regla de user-agent. Medido acá: el sheet
   «cerrado» seguía interceptando TODOS los clicks de la página en mobile — el scrim
   invisible tapaba el botón que debía abrirlo. El alcance es `.com-finder` porque el
   sheet y la barra viven dentro del componente en las dos ramas (búsqueda y directorio). */
.com-finder [hidden] { display: none !important }

/* Chips de filtros activos (desktop, entre la barra de resultados y la lista). En la
   barra mobile van con la variante `--scroll`, que ya está en components. */
.sj-chips-desktop { margin-bottom: 20px; gap: 8px } /* el gap:12 de .dir-solo-desktop no es para chips */
.sj-busqueda-vacio .gsj-facets__chips { margin-top: 16px }

/* Los chips del sitio son ENLACES (funcionan sin JS); los del kit, botones. El texto
   centrado es del botón, no de la clase — se repone en el anchor. */
.gsj-facets__chips a.gsj-chip,
.gsj-facets__chips a.gsj-facets__clear { text-align: center }

/* El selector de orden dentro del directorio, ajustado al trazo del kit (`servicios.html`
   dibuja los dos selects con 34px de sangría derecha y el de desktop con 10px verticales;
   los de `bus-orden` traían los de la búsqueda). */
.sj-directorio .bus-orden select { max-width: none }
.sj-directorio .bus-orden--inset select { padding-right: 34px }
.sj-directorio .gsj-results-bar .bus-orden select { padding-top: 10px; padding-bottom: 10px }

/* La cola larga plegada por JS: sin JS llega desplegada y el botón `hidden`. El grupo de
   valores extra no necesita caja propia — hereda el gap del grupo. */
.gsj-facets__resto { display: flex; flex-direction: column; gap: inherit }
.gsj-facets__resto[hidden] { display: none }

@media (min-width: 900px) {
  .dir-buscar-mobile { display: none }
  .dir-buscar-desktop { display: flex; margin-top: 24px }
}
/* ══ Ficha de Prestador ═════════════════════════════════════════════════════
   Pantalla: `ui_kits/sitio/prestador.html` (estado a) + los estados b/c/d/e del
   draft `design-drafts/prestador/`. Ver el docblock de `default_prestador.php`,
   que trae los conteos que fundamentan cada decisión.

   🔴 LA HOJA SON TRES HIJOS DE GRILLA, NO UN CONTENEDOR CON UN ASIDE AL LADO.
   El kit resolvía el mobile con `order:-1` sobre el aside: eso lo sube
   visualmente pero NO en el DOM, así que el foco de teclado recorría el título,
   la nav rápida y todas las secciones ANTES de llegar a los botones que se ven
   primeros (WCAG 2.4.3 Focus Order, y 1.3.2 Meaningful Sequence). Acá el orden
   del DOM —`pr-head` → `pr-aside` → `pr-body`— YA ES el orden del draft en
   mobile, y en desktop la grilla manda el aside a la segunda columna sin mover
   nada. Cero `order`.

   La superficie blanca continua la pinta `.pr-grid::before`, que es un ítem de
   grilla más: así head y body comparten UNA sola caja con UNA sola sombra y no
   queda la costura que dejarían dos `box-shadow` adyacentes.
   ═══════════════════════════════════════════════════════════════════════════ */

.pr-main{padding-bottom:40px;position:relative}

/* El fondo tenue de página que el kit pone en `body` y que el sitio no reponía:
   sin esto la hoja blanca queda sobre blanco y el patrón de "hoja flotante" se
   apoya sólo en la sombra. A sangre completa, porque `.gsj-page-main` está
   acotado a 1280 y un fondo de 1280 se lee como una banda. */
.pr-main::before{content:"";position:absolute;z-index:0;inset-block:0;inset-inline:calc(50% - 50vw);background:var(--gsj-color-bg-subtle)}
.pr-main > *{position:relative;z-index:1}

/* Hero: franja completa con foto. Sin foto es una CINTA (72px) — el draft lo
   fija explícito, y son 161 de 726 fichas (Agencias, Transporte y Alquiler de
   Autos enteros). El degradé es el del draft, suave: la banda no lleva texto
   encima, así que no necesita el naranja oscuro de `gsj-entity-hero--marca`. */
.pr-hero{height:280px;border-radius:24px;overflow:hidden;position:relative;margin-top:16px}
.pr-hero img{display:block;width:100%;height:100%;object-fit:cover}
.pr-hero--marca{height:72px;background:linear-gradient(140deg,var(--gsj-color-bg-muted),var(--gsj-color-primary-container))}

.pr-grid{display:grid;grid-template-columns:minmax(0,1fr) 360px;column-gap:24px;row-gap:0;align-items:start;margin-top:-56px;padding:0 32px;position:relative;z-index:1}
.pr-grid::before{content:"";grid-column:1;grid-row:1/3;align-self:stretch;background:var(--gsj-color-bg-page);border-radius:24px;box-shadow:0 2px 16px rgba(0,0,0,.08)}
/* Con la cinta de 72px el solape de -56px dejaría 16px de banda: se afloja. */
.pr-grid--cinta{margin-top:-24px}

.pr-head{grid-column:1;grid-row:1;min-width:0;padding:32px 32px 0;display:flex;flex-direction:column;gap:10px}
.pr-body{grid-column:1;grid-row:2;min-width:0;padding:28px 32px 32px;display:flex;flex-direction:column;gap:28px}
.pr-aside{grid-column:2;grid-row:1/3;align-self:start;background:var(--gsj-color-bg-page);border-radius:24px;box-shadow:0 2px 16px rgba(0,0,0,.08);padding:24px;display:flex;flex-direction:column;gap:16px;position:sticky;top:24px}
.pr-aside-actions{display:flex;flex-direction:column;gap:8px}

.pr-head__meta{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.pr-block{display:flex;flex-direction:column;gap:12px;scroll-margin-top:72px}
.pr-h2{margin:0;font-family:var(--gsj-font-heading);font-size:1.375rem;font-weight:500;color:var(--gsj-color-text)}
.pr-h2--menor{font-size:1.25rem}
.pr-loc{margin:0;display:flex;align-items:center;gap:6px;font-family:var(--gsj-font-heading);font-size:1rem;color:var(--gsj-color-text-secondary)}
.pr-loc svg{flex:0 0 16px}

/* 🔴 LA PROSA DECLARA SUS PROPIOS MÁRGENES — 13.ª aparición del bug que el kit
   no puede revelar. El kit corre pelado; el sitio carga además nucleus, que trae
   `p{margin:1.5rem 0}` y `ul{margin-left:1.5rem}`. `portal.css` sólo pisa el
   `margin-bottom`, así que el `margin-top:24px` sobrevive: los párrafos del
   cuerpo se separaban 24px donde el kit los separa 12, y una lista libre sumaba
   ~48px de sangría (nucleus + el padding de portal). Se resuelve con el mismo
   idioma del kit —gap del contenedor y márgenes en cero— y alcanza a cualquier
   etiqueta que el editor haya dejado en el texto. */
.pr-prosa{display:flex;flex-direction:column;gap:12px;font-size:1.0625rem;line-height:var(--gsj-line-height-relaxed)}
.pr-prosa > *{margin:0}
.pr-prosa :where(ul,ol){margin:0;padding-left:24px}
.pr-fuente{margin:0;font-size:.8125rem;color:var(--gsj-color-text-muted)}

/* `gsj-alert` sin modificador no declara fondo ni color: lleva `--info`. Y su
   `<p>` interno necesita el margin en cero por el mismo motivo que la prosa. */
.pr-alert p{margin:0}

.pr-info{display:flex;flex-direction:column;gap:12px}

/* Horarios de atención (fila 45). Mismo tratamiento de ícono que `.pr-ubicacion-card__dir`
   —18px, color primario, alineado al tope— para que el reloj y el pin se lean como piezas
   del mismo sistema. Las líneas son `<p>` y no un `<br>` corrido: cada tramo del horario es
   una unidad («Lunes a viernes de 9 a 13», «Sábados de 9 a 13») y así se puede leer de un
   vistazo, que es para lo que se consulta un horario. */
.pr-horarios{display:flex;gap:10px;align-items:flex-start}
.pr-horarios > svg{flex:0 0 18px;width:18px;height:18px;margin-top:3px;color:var(--gsj-color-primary)}
.pr-horarios__lineas{display:flex;flex-direction:column;gap:4px}
.pr-horarios__linea{margin:0;font-size:1.0625rem;line-height:var(--gsj-line-height-relaxed)}
.pr-chips{display:flex;flex-wrap:wrap;gap:8px}
.pr-ambito{margin:0;display:flex;align-items:center;gap:8px;flex-wrap:wrap;font-family:var(--gsj-font-heading);font-size:.875rem;color:var(--gsj-color-text-secondary)}

/* Ubicación sin coordenadas — estado b del draft. Son 502 de 726 fichas, o sea
   el caso mayoritario: dejar sólo un botón suelto bajo el `h2` no dice por qué
   no hay mapa. */
.pr-ubicacion-card{border:1px solid var(--gsj-color-border);border-radius:12px;padding:16px;display:flex;flex-direction:column;gap:12px;background:var(--gsj-color-bg-subtle)}
.pr-ubicacion-card__dir{margin:0;display:flex;gap:10px;align-items:flex-start}
.pr-ubicacion-card__dir svg{flex:0 0 18px;width:18px;height:18px;margin-top:2px;color:var(--gsj-color-primary)}
.pr-ubicacion-card__dir > span{display:flex;flex-direction:column;gap:2px}
.pr-ubicacion-card__dir strong{font-family:var(--gsj-font-heading);font-weight:500}
.pr-ubicacion-card__depto{font-size:.8125rem;color:var(--gsj-color-text-secondary)}
.pr-ubicacion-card__nota{margin:0;font-size:.8125rem;color:var(--gsj-color-text-muted)}
.pr-ubicacion-card .gsj-button{align-self:flex-start}

.pr-contact-empty{margin:0;color:var(--gsj-color-text-secondary);line-height:var(--gsj-line-height-relaxed)}
.pr-map-link{align-self:flex-start}
.pr-explorar{display:flex;flex-wrap:wrap;gap:8px}
.pr-rel{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:24px;align-items:start}
.pr-rel>*{min-width:0}
.pr-quicknav{display:none}

/* Ficha mínima (estado c del draft): 339 de 726 no tienen cuerpo, y dos columnas
   con la izquierda vacía se leen como una página rota. Columna única centrada. */
.pr-grid--simple{grid-template-columns:minmax(0,720px);justify-content:center}
.pr-grid--simple::before{grid-column:1;grid-row:1/4}
.pr-grid--simple .pr-head{grid-column:1;grid-row:1}
.pr-grid--simple .pr-aside{grid-column:1;grid-row:2;position:static;background:none;box-shadow:none;border-radius:0;padding:20px 32px 0}
.pr-grid--simple .pr-body{grid-column:1;grid-row:3}

@media (max-width:900px){
  /* Una sola columna y UNA sola superficie continua detrás de los tres hijos,
     que es como lo dibuja el draft: la hoja arranca redondeada bajo el hero y
     baja hasta el final del contenido. */
  .pr-grid,.pr-grid--simple{grid-template-columns:1fr;justify-content:normal;margin-top:-32px;padding:0 16px}
  .pr-grid::before,.pr-grid--simple::before{grid-column:1;grid-row:1/4;border-radius:24px 24px 0 0}
  .pr-head,.pr-grid--simple .pr-head{grid-column:1;grid-row:1;padding:20px 16px 0}
  .pr-aside,.pr-grid--simple .pr-aside{grid-column:1;grid-row:2;position:static;background:none;box-shadow:none;border-radius:0;padding:16px 16px 0;gap:12px}
  .pr-body,.pr-grid--simple .pr-body{grid-column:1;grid-row:3;padding:24px 16px 32px;gap:24px}
  .pr-grid--cinta{margin-top:-24px}
  /* Las acciones van en fila en mobile: son la razón de ser de la ficha y
     entran las tres a 390 (el draft las pone así). */
  .pr-aside-actions{flex-direction:row;gap:8px}
  .pr-aside-actions .gsj-button{flex:1;padding:0 10px;white-space:nowrap}
  .pr-quicknav{display:flex;gap:16px;flex-wrap:wrap}
  /* `padding:10px 0` es del draft y no es decorativo: sin él el enlace mide
     ~20px de alto y no llega al área táctil mínima (WCAG 2.5.8). El kit lo
     perdió al canonizar. */
  .pr-quicknav a{font-family:var(--gsj-font-heading);font-size:.875rem;font-weight:500;color:var(--gsj-color-text-link);text-decoration:underline;text-underline-offset:3px;padding:10px 0;display:inline-block}
  .pr-loc{font-size:.9375rem}
  .pr-h2{font-size:1.25rem}
  .pr-h2--menor{font-size:1.125rem}
  .pr-rel{grid-template-columns:1fr}
}


/* ────────────────────────────────────────────────────────────────────────────
   PLANIFICÁ TU VIAJE  (`pl-*`)  — FASE H2.7
   La landing launchpad: hero compacto con la miga adentro, tiles de transporte
   + Red Tulum, teasers a Sobre San Juan / Oficinas / Folletos y la puerta a
   Promociones. Fuente de verdad: `ui_kits/sitio/planifica-tu-viaje.html`.

   DOS DIVERGENCIAS DECLARADAS respecto del `<style>` del kit, las dos porque el
   kit es HTML suelto y el sitio no:
     · `.pl-fcover image-slot` → `.pl-fcover img`. `<image-slot>` es el
       placeholder de Claude Design; el sitio sirve el `image_intro` real de
       cada folleto en un `<img>`.
     · `.pl-redtulum__photo` deja de ser un `background:url(…)` y pasa a ser un
       `<img>` con `object-fit`. Un `url()` relativo no puede ser válido a la vez
       en `sjtur-ds/` (raíz del kit) y en `custom/css/` (raíz del theme), y las
       tres capas del sitio hoy tienen CERO `url()`: la ruta la resuelve el Twig
       con `url('gantry-theme://custom/images/ds/redtulum-buses.png')`, que es
       donde el asset ya vive.
   ──────────────────────────────────────────────────────────────────────────── */

/* ---- Hero compacto ---- */
/* Degradé de marca (mismo token de naranja oscuro que destino/experiencia), no una franja plana. */
.pl-hero {
  background-image: linear-gradient(160deg, var(--gsj-color-primary-fill), var(--gsj-brand-orange-dark, #7c2d12));
  /* padding-top 20px = el que tenía el contenedor del breadcrumb, que acá vive ADENTRO del hero.
     El aire lo da el margin-top de __inner, así la miga queda a la misma altura que en las otras
     pantallas. Por eso este outline NO lleva `position-breadcrumbs`: la miga la emite el particle. */
  padding: 20px 0 clamp(52px, 8vw, 84px);
  border-bottom-left-radius: var(--gsj-radius-xl);
  border-bottom-right-radius: var(--gsj-radius-xl);
}

.pl-hero .gsj-hero__inner { margin-top: clamp(32px, 5vw, 64px); }
.pl-hero .gsj-hero__title { text-wrap: balance; }
.pl-hero .gsj-hero__subtitle { text-wrap: pretty; }

/* Miga sobre el degradé de marca: el color del kit está pensado para fondo claro (rojo oscuro
   sobre blanco) y acá daría un contraste malísimo. Blanco al 82% sobre el tramo más claro del
   degradé (#c54500) da 4.0:1; el `current`, al 100%, 4.96:1. */
.pl-hero__bc .gsj-breadcrumb__link { color: rgba(255, 255, 255, .82); }
.pl-hero__bc .gsj-breadcrumb__link:hover { color: #fff; }
.pl-hero__bc .gsj-breadcrumb__current { color: #fff; }
.pl-hero__bc .gsj-breadcrumb__item:not(:last-child)::after { color: rgba(255, 255, 255, .6); }

/* ---- Interacción compartida: las cards-enlace levantan al hover ---- */
a.gsj-card,
a.pl-tile {
  transition: box-shadow .25s cubic-bezier(.2, .8, .2, 1), transform .25s cubic-bezier(.2, .8, .2, 1);
}

a.gsj-card:hover,
a.pl-tile:hover {
  box-shadow: 0 14px 24px -14px rgba(0, 0, 0, .3);
  transform: translateY(-3px);
}

@media (prefers-reduced-motion: reduce) {
  a.gsj-card,
  a.pl-tile { transition: none; }

  a.gsj-card:hover,
  a.pl-tile:hover { transform: none; }
}

/* ---- Cómo llegar: tiles de transporte (InfoPractica dentro de un enlace) ---- */
.pl-tile {
  display: flex;
  flex-direction: column;
  gap: 16px;
  justify-content: space-between;
  padding: 24px;
  border: 1px solid var(--gsj-color-border);
  border-radius: var(--gsj-radius-card);
  background: var(--gsj-color-surface, #fff);
  text-decoration: none;
  color: inherit;
}

.pl-tile__link {
  font-family: var(--gsj-font-heading);
  font-size: .8125rem;
  font-weight: 600;
  color: var(--gsj-color-primary-text);
}

.pl-tile__note {
  font-family: var(--gsj-font-heading);
  font-size: .8125rem;
  font-weight: 600;
  color: var(--gsj-color-text-secondary);
}

/* ---- Cómo moverse: bloque plano (NO card), así no hay card-dentro-de-card ---- */
.pl-moverse { margin-top: 28px; }

.pl-moverse h3 {
  font-family: var(--gsj-font-heading);
  font-size: 1.25rem;
  font-weight: 700;
  margin: 0 0 8px;
  color: var(--gsj-color-text);
}

/* `> p` (hijo directo) a propósito: así esta regla NO pisa el color del tagline de Red Tulum,
   que es un <p> anidado. Fue un bug real de especificidad al canonizar. */
.pl-moverse > p {
  font-size: 1.0625rem;
  line-height: 1.65;
  color: var(--gsj-color-text-secondary);
  margin: 0 0 16px;
  max-width: 70ch;
}

.pl-moverse > p a {
  color: var(--gsj-color-primary-text);
  font-weight: 600;
  text-decoration: none;
}

.pl-moverse > p a:hover { text-decoration: underline; }

/* ---- Red Tulum (transporte público provincial, tercero) ----
   Foto de colectivos a sangre a la izquierda + contenido sobre su color de marca
   (#E50063; blanco encima = 4.65:1, WCAG AA). */
.pl-redtulum {
  margin-top: 20px;
  border-radius: var(--gsj-radius-card);
  overflow: hidden;
  display: grid;
  grid-template-columns: 1fr;
  background: #e50063;
}

@media (min-width: 640px) {
  .pl-redtulum { grid-template-columns: minmax(150px, .72fr) 1.28fr; }
}

/* 🔴 ES UN `<div>` CON FONDO, NO UN `<img>`, y la diferencia se vio en pantalla.
   La primera versión lo pasó a `<img>` para sacar el `url()` del CSS. Se veía mal: un
   `<img>` es un elemento reemplazado, así que en una celda de grilla de alto automático
   impone SU proporción natural y estira la fila — el banner pasaba de ~200px a más de
   400. El `background-size:cover` no tiene ese problema: la altura la sigue mandando la
   columna de contenido, que es lo que el diseño quiere.
   La URL la inyecta la partícula en un `style` inline porque una ruta relativa no puede
   ser válida a la vez en la copia del DS y en la del theme; el resto del tratamiento vive
   acá. Es el único `url()` que no está en esta capa, y está por eso. */
.pl-redtulum__photo {
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
  min-height: 160px;
}

.pl-redtulum__content {
  padding: 26px 28px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.pl-redtulum__logo {
  height: 38px;
  width: auto;
  display: block;
}

.pl-redtulum__tag {
  font-family: var(--gsj-font-heading);
  font-size: .95rem;
  font-weight: 600;
  line-height: 1.5;
  color: #fff;
  margin: 0;
  max-width: 46ch;
}

.pl-redtulum__links {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 18px;
}

.pl-redtulum__links a {
  font-family: var(--gsj-font-heading);
  font-size: .85rem;
  font-weight: 600;
  color: #fff;
  text-decoration: none;
  border-bottom: 1px solid rgba(255, 255, 255, .45);
  padding-bottom: 2px;
}

.pl-redtulum__links a:hover { border-bottom-color: #fff; }

/* ---- Sobre San Juan: 3 teasers a los artículos de la cat 45 ----
   El kit trae estos dos valores como `style=""` en cada card. Acá se declaran una vez:
   son maquetación de la sección, no decisión de cada tarjeta. */
.pl-sobre .gsj-card__body { padding: 32px; }
.pl-sobre .gsj-card__text { margin-bottom: 18px; }

/* En una columna la bajada no se dibuja: título + «Leer más» alcanzan — «Ubicación»,
   «Geografía y clima» e «Historia» se explican solos, y con bajada las 3 tarjetas
   apiladas medían 1.014px = 1,20 pantallas a 390 (C4, 2026-08-28). El corte es el
   mismo 768 en que gsj-grid-3 pasa a 2 columnas. */
@media (max-width: 767px) {
  .pl-sobre .gsj-card__text { display: none; }
}

/* ---- Oficinas: panel en 2 columnas con preview real de la oficina principal ----
   Ojo: la card de este panel NO es `gsj-oficina-card` (el componente del DS, que se usa
   entero en /planifica-tu-viaje/oficinas-de-turismo). Acá es un preview de 3 campos. */
.pl-of {
  display: grid;
  gap: clamp(24px, 4vw, 40px);
  grid-template-columns: 1fr;
  align-items: center;
  background: var(--gsj-color-bg-subtle);
  border: 1px solid var(--gsj-color-border);
  border-radius: var(--gsj-radius-xl);
  padding: clamp(24px, 4vw, 40px);
}

@media (min-width: 820px) {
  .pl-of { grid-template-columns: 1.05fr .95fr; }
}

.pl-of__stat {
  font-family: var(--gsj-font-heading);
  font-weight: 600;
  color: var(--gsj-color-primary-text);
  font-size: .8rem;
  letter-spacing: .03em;
  text-transform: uppercase;
  margin: 0;
}

.pl-of h2 {
  font-family: var(--gsj-font-heading);
  font-size: clamp(1.5rem, 3.5vw, 2rem);
  font-weight: 700;
  margin: 8px 0 12px;
  color: var(--gsj-color-text);
  text-wrap: balance;
}

.pl-of__lead {
  font-size: 1.05rem;
  line-height: 1.6;
  color: var(--gsj-color-text-secondary);
  margin: 0 0 22px;
  max-width: 52ch;
}

.pl-of__card {
  background: var(--gsj-color-surface, #fff);
  border: 1px solid var(--gsj-color-border);
  border-radius: var(--gsj-radius-card);
  padding: 22px;
}

.pl-of__eyebrow {
  font-family: var(--gsj-font-heading);
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--gsj-color-primary-text);
  margin: 0;
}

.pl-of__name {
  font-family: var(--gsj-font-heading);
  font-size: 1.2rem;
  font-weight: 700;
  margin: 4px 0 12px;
  color: var(--gsj-color-text);
}

.pl-of__line {
  display: flex;
  gap: 8px;
  align-items: center;
  font-size: .92rem;
  color: var(--gsj-color-text-secondary);
  margin: 0 0 6px;
}

.pl-of__line svg {
  width: 15px;
  height: 15px;
  flex-shrink: 0;
  color: var(--gsj-color-primary);
}

.pl-of__coverage {
  margin: 16px 0 0;
  padding: 16px 0 0;
  border-top: 1px solid var(--gsj-color-border);
  font-size: .9rem;
  line-height: 1.5;
  color: var(--gsj-color-text-secondary);
}

.pl-of__coverage strong {
  color: var(--gsj-color-text);
  font-weight: 600;
}

/* ---- Folletos: tapas con overlay ---- */
/* Misma corrección que `.fo-card__cover`, y por el mismo motivo: son las MISMAS tapas
   (los folletos de la cat 138) en la misma grilla de 4. El `height:300px` del kit no
   seguía al ancho de la columna y a 390 dejaba una tira de 163×300. Ver la nota larga
   del bloque de folletos. */
.pl-fcover {
  display: block;
  width: 100%;
  min-width: 0;
  aspect-ratio: 210 / 297;
  border-radius: var(--gsj-radius-lg);
  overflow: hidden;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .12);
  position: relative;
}

/* Divergencia declarada: el kit tiene `<image-slot>` acá. Ver la cabecera. */
.pl-fcover img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.pl-fcover::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(0, 0, 0, .62), transparent 50%);
  z-index: 0;
}

.pl-fcover__label {
  position: absolute;
  left: 16px;
  right: 16px;
  bottom: 16px;
  font-family: var(--gsj-font-heading);
  font-weight: 700;
  font-size: 1.05rem;
  color: #fff;
  z-index: 1;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .4);
}

.pl-fcover__label span {
  display: block;
  font-weight: 400;
  font-size: .85rem;
  opacity: .9;
}


/* ────────────────────────────────────────────────────────────────────────────
   OFICINAS DE TURISMO  (`of-*`)  — FASE H2.7
   `/planifica-tu-viaje/oficinas-de-turismo`: el directorio de las 8 oficinas en
   3 grupos (principal · en los destinos · otros puntos). La tarjeta es el
   componente del DS `gsj-oficina-card` (turismo-components.css); acá vive sólo
   la maquetación de la página. Fuente de verdad: `ui_kits/sitio/oficinas-de-turismo.html`.
   ──────────────────────────────────────────────────────────────────────────── */

.of-main { padding-bottom: 80px; }

.of-intro {
  font-size: 1.05rem;
  line-height: 1.6;
  color: var(--gsj-color-text-secondary);
  max-width: 64ch;
  margin: 0 0 40px;
}

/* El kit trae este margen como `style=""` en el encabezado de página. Se declara acá
   con el mismo criterio que `.art-main .gsj-prosa > header`: es aire de la página. */
.of-main > .gsj-section-header { margin: 28px 0 8px; }

.of-h2 {
  font-family: var(--gsj-font-heading);
  font-size: 1.4rem;
  font-weight: 700;
  color: var(--gsj-color-text);
  margin: 48px 0 20px;
}

/* El h2 que sigue a la oficina destacada respira menos: la card ya trae su propio
   `margin-bottom`. En el kit era `style="margin-top:36px"` sobre ese h2 y sólo ese. */
.gsj-oficina-card--destacada + .of-h2 { margin-top: 36px; }

/* Grilla responsive 1/2 col — misma card para destinos y capital (sin aside fijo). */
.of-grid {
  display: grid;
  gap: 20px;
  grid-template-columns: 1fr;
}

@media (min-width: 720px) {
  .of-grid { grid-template-columns: repeat(2, 1fr); }
}


/* ────────────────────────────────────────────────────────────────────────────
   FOLLETOS  (`fo-*`)  — FASE H2.7
   `/planifica-tu-viaje/folletos`: la biblioteca de los 13 folletos, cada uno con
   su tapa, «Ver online» (al artículo) y «Descargar PDF». Fuente de verdad:
   `ui_kits/sitio/folletos.html`.

   Misma divergencia declarada que en `pl-fcover`: el kit dibuja la tapa con
   `<image-slot>`, que es el placeholder de Claude Design; el sitio sirve el
   `image_intro` real en un `<img>`.
   ──────────────────────────────────────────────────────────────────────────── */

.fo-main { padding-bottom: 80px; }

.fo-intro {
  font-size: 1.05rem;
  line-height: 1.6;
  color: var(--gsj-color-text-secondary);
  max-width: 64ch;
  margin: 0 0 40px;
}

/* El mismo margen del encabezado de página que en el directorio de oficinas. */
.fo-main > .gsj-section-header { margin: 28px 0 8px; }

/* 🔴 MÁS AIRE ENTRE FILAS QUE ENTRE COLUMNAS, y no es simetría rota por gusto.
   `gsj-grid-4` reparte 24px iguales en los dos ejes (16 en angosto), y eso alcanza en
   HORIZONTAL —ahí cada tarjeta tiene al lado otra igual, tapa contra tapa y botones
   contra botones, así que el gap sólo separa piezas equivalentes—. En VERTICAL el
   límite cruza de «fin de una tarjeta» a «principio de otra», y estas tarjetas no
   tienen borde ni fondo que las cierre: terminan en una fila de botones liviana y lo que
   sigue es una tapa grande. Con 24px contra los 14px de separación interna (1,7×) el ojo
   agrupa mal y los botones se leen como pie de la tapa de abajo. A 390 era 16 contra 14,
   o sea 1,14×.
   48 y 32 dejan la separación entre tarjetas 3,4× y 2,3× por encima de la interna, que es
   la distancia a la que el agrupamiento deja de ser ambiguo. Va acotado a esta pantalla:
   `gsj-grid-4` es una primitiva del DS y la usan otras. */
.fo-main > .gsj-grid-4 { row-gap: 32px; }

@media (min-width: 1024px) {
  .fo-main > .gsj-grid-4 { row-gap: 48px; }
}

.fo-card {
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-width: 0;
}

/* Los CTAs al pie de la tarjeta, no pegados al título: con títulos de una y de dos líneas
   conviviendo en la misma fila, sin esto los botones quedan a distinta altura entre
   tarjetas vecinas y el borde inferior de la fila sale dentado. Se ve a 390, donde
   «Cuatro circuitos» y «Aventura y naturaleza» ocupan 1 y 2 líneas. */
.fo-card__actions { margin-top: auto; }

/* 🔴 PROPORCIÓN, NO ALTO FIJO. El `height:300px` del kit no escala: la caja no sigue al
   ancho de la columna, así que a 1280 daba 290×300 (casi cuadrada) y a 390 daba **163×300**
   —una tira vertical que recortaba la mitad de la tapa—. Con `aspect-ratio` la caja sigue a
   la columna y el encuadre es el mismo a todo ancho.

   POR QUÉ 210/297 Y NO OTRA COSA: **los folletos son A4 vertical**, y la miniatura de un
   documento tiene que tener la forma del documento. Eso es información —le dice al
   visitante qué va a abrir— y no decoración. Se escribe como la medida literal del A4 en
   milímetros, no como un decimal, para que la próxima persona que lo lea sepa de dónde
   sale sin tener que calcular.
   Es a propósito distinta del 4/5 de `.gsj-card--destino`, la card fotográfica del DS: esa
   retrata un LUGAR y ésta un impreso.

   ⚠️ Las imágenes cargadas hoy son fotos CUADRADAS, no tapas de imprenta, así que entran
   con un recorte lateral de ~29%. Es transitorio y del dato, no del diseño: se corrige
   subiendo la tapa real del PDF. La proporción no se elige por lo que hay cargado. */
.fo-card__cover {
  display: block;
  width: 100%;
  aspect-ratio: 210 / 297;
  border-radius: 16px;
  overflow: hidden;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .12);
}

.fo-card__cover img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* El placeholder del DS trae `aspect-ratio:16/9` propio, que dentro de esta caja A4 dejaría
   una franja vacía abajo. Acá tiene que llenar la caja, que ya declara la proporción. */
.fo-card__cover .gsj-card__image-placeholder {
  height: 100%;
  aspect-ratio: auto;
}

.fo-card__title {
  font-family: var(--gsj-font-heading);
  font-weight: 700;
  font-size: 1.15rem;
  color: var(--gsj-color-text);
  margin: 0;
  line-height: 1.2;
}

.fo-card__title span {
  display: block;
  font-weight: 400;
  font-size: .85rem;
  color: var(--gsj-color-text-secondary);
}

/* Las dos acciones en una fila. Los dos botones van en `--sm --pill`: entran en 269 de
   los 290px de la tarjeta y la jerarquía la marca el relleno, no el tamaño —que es como
   el DS separa primario de secundario en el resto del sitio—. Con el primario en tamaño
   completo (203px de ancho) el par no entraba y el bloque se partía en dos filas: 88px
   sólo de botones sobre una tarjeta de 438. */
.fo-card__actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

/* En la grilla angosta la tarjeta mide 163px y NINGÚN par de botones entra al lado del
   otro. Ahí `flex-wrap` los deja partidos y desalineados, así que se apilan a propósito y
   a ancho completo: ocupa lo mismo que el wrap desprolijo y de paso el área táctil pasa a
   todo el ancho de la tarjeta, que es lo que conviene en mano. */
@media (max-width: 560px) {
  .fo-card__actions .gsj-button {
    flex: 1 1 100%;
    justify-content: center;
  }
}


/* ────────────────────────────────────────────────────────────────────────────
   CONTACTO  (`ct-*`)  — FASE H2.7
   `/contacto`: el formulario de `com_contact` (ficha 1, «Turismo San Juan») a la
   izquierda y los canales directos + la oficina principal a la derecha. Fuente de
   verdad: `ui_kits/sitio/contacto.html`.

   La página es HERMANA de `/planifica-tu-viaje/oficinas-de-turismo` y no la
   reemplaza: Contacto es «escribinos», Oficinas es «veníte a vernos». De ahí que
   acá aparezca UNA sola oficina —la principal, con dirección y horario— y el
   enlace al directorio completo, en vez de las 8.
   ──────────────────────────────────────────────────────────────────────────── */

.ct-main { padding-bottom: 64px; }

/* Mismo criterio que en `of-main`/`fo-main`: el kit lo trae como `style=""` en el
   encabezado de página y acá se declara, porque es aire de la página. */
.ct-main > .gsj-section-header { margin-top: 20px; }

/* La bajada de esta pantalla corre más ancha que los 600px del componente: son dos
   frases, y a 600px la segunda quedaba huérfana en una línea de 3 palabras. */
.ct-main .gsj-section-header__subtitle { max-width: 62ch; }

.ct-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 32px;
  align-items: start;
  margin-top: 28px;
}

@media (min-width: 900px) {
  .ct-grid {
    grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
    gap: 48px;
  }
}

/* La hoja del formulario se separa del fondo igual que el resto de los módulos del sitio. */
.ct-form {
  background: var(--gsj-color-surface);
  border: .5px solid var(--gsj-color-border);
  border-radius: var(--gsj-radius-card);
  padding: clamp(20px, 3vw, 32px);
}

/* El kit reusa `pr-h2` (el h2 de la ficha de prestador) y le suma 6px de aire abajo
   con un `style=""`. Se respeta la clase —es el mismo tratamiento tipográfico— y el
   margen se declara acá. */
.ct-form > .pr-h2 { margin-bottom: 6px; }

.ct-form__req {
  color: var(--gsj-color-error-text);
  font-weight: 700;
}

.ct-nota {
  font-size: .8125rem;
  color: var(--gsj-color-text-muted);
  margin: 0;
}

/* La nota de campos obligatorios abre el formulario: separa del primer campo. */
.ct-form > .ct-nota { margin-bottom: 24px; }

.ct-aside {
  display: flex;
  flex-direction: column;
  gap: 24px;
}

.ct-panel {
  background: var(--gsj-color-bg-muted);
  border: .5px solid var(--gsj-color-border);
  border-radius: var(--gsj-radius-card);
  padding: 20px;
}

.ct-panel__title {
  font-family: var(--gsj-font-heading);
  font-size: 1.0625rem;
  font-weight: 700;
  margin: 0 0 4px;
  color: var(--gsj-color-text);
}

.ct-panel__lead {
  font-size: .9375rem;
  color: var(--gsj-color-text-secondary);
  margin: 0 0 16px;
  line-height: 1.5;
}

.ct-canales {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* Los dos `style=""` del panel en el kit. */
.ct-panel .ct-nota { margin-top: 14px; }
.ct-panel .gsj-social-row { margin-top: 8px; }

.ct-verlink {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--gsj-font-heading);
  font-weight: 600;
  font-size: .9375rem;
  color: var(--gsj-color-text-link);
  text-decoration: none;
  margin-top: 12px;
}

.ct-verlink:hover { text-decoration: underline; }

/* ────────────────────────────────────────────────────────────────────────────
   FICHA DE EVENTO  (`ev-*`)  — AGENDA
   `/agenda/{alias}`: la ficha de un evento de DPCalendar. Fuente de verdad:
   `ui_kits/sitio/agenda-evento.html`, donde estas reglas viven inline en el
   <style> de la pantalla.

   Por qué el kit no alcanza como fuente y hubo que agregar clases: el kit retrata
   UN estado —evento recurrente, con foto, con tema y con tres salidas próximas— y
   el catálogo real tiene además evento de fecha única, evento vencido y evento sin
   ubicación geocodificada. Las clases nuevas (`--vencido`, `--sin-coords`,
   `--foto`, `ev-tarjeta-salida`) son esos estados, no decoración.
   ──────────────────────────────────────────────────────────────────────────── */

.ev-main { padding-bottom: 56px; }

.ev-grid { display: grid; grid-template-columns: 1fr; gap: 40px; align-items: start; }

/* `min-width: 0` en las celdas: sin esto el ítem de grilla no puede achicarse por
   debajo del min-content de su contenido y la hero a sangre desborda el viewport.
   Es la misma nota que trae el kit. */
.ev-grid > * { min-width: 0; }

.ev-col { display: flex; flex-direction: column; }

/* 🔴 PROPORCIÓN FIJA, NO ALTO FIJO (fila 141, 2026-09-22). Con `height: 180px` a todo el ancho la
   relación cambiaba con el viewport: 2,17:1 a 390 y **5:1 a 899**, donde una placa 16:9 pierde el
   64 % del alto (medido en `scratchpad/placas/RECOMENDACION.md`). Ninguna zona segura aguanta eso.
   Con `aspect-ratio` el recorte es constante, y el tope de **325px** hace que el peor caso (899px de
   ancho, el último antes de la grilla de dos columnas) dé 2,77:1 — exactamente el mismo recorte que
   el hero de escritorio. Medido con `scratchpad/medir_hero.js` en 9 anchos de 320 a 1920. */
.ev-hero {
  aspect-ratio: 16 / 9;
  height: auto;
  max-height: 325px;
  border-radius: 0;
  margin: 0 calc(var(--gsj-space-6) * -1) 18px;
  background: linear-gradient(135deg, oklch(72% 0.12 55deg), oklch(83% 0.15 88deg));
}

/* `overflow:hidden` va en el modificador CON foto y no en la base: el kit dibuja el hero
   como degradado sin hijos, así que declararlo arriba hacía diverger `.ev-hero` sin que
   nada lo necesitara. Recortar sólo hace falta cuando hay una imagen que redondear. */
.ev-hero--foto { background: var(--gsj-color-bg-muted); overflow: hidden; }
.ev-hero img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* ═══ «EN CARTEL» — lo que está abierto varios días ═══════════════════════════════════════
   Banda por encima de las jornadas de `/agenda`. Existe porque una VENTANA no pertenece a un
   día: la muestra abierta del 7 al 26 se veía una sola vez y el contador de cada jornada
   subcontaba. Ver la nota larga en `com_dpcalendar/list/default.php`.

   🔸 Se lee como un ESTANTE y no como una tarjeta más: fondo tonal, sin foto y en una línea
   por ítem. Si se pareciera a las tarjetas de la lista competiría con ellas, y lo que tiene
   que hacer es lo contrario — decir «esto no es de un día, está todo el tiempo».
   ⚠️ No usa `gsj-event-card`: esa card promete fecha y hora, que es justo lo que una ventana
   no tiene. */
.ag-cartel {
  margin: 0 0 var(--gsj-space-6);
  padding: var(--gsj-space-5) var(--gsj-space-6);
  /* 🔴 `--gsj-color-primary-light`, el MISMO token que usa `.ev-proximas` para el bloque
     tonal de «Próximas fechas» — que es el mismo rol visual. La primera versión inventó un
     `--gsj-color-surface-accent` que NO EXISTE en el DS y quedaba sirviendo el fallback
     `#fff3e0`, o sea un hex crudo en un componente. Es la trampa que la memoria del proyecto
     ya tenía escrita: el DS base hardcodea los colores, así que un token inventado no falla,
     simplemente no existe y nadie se entera. */
  background-color: var(--gsj-color-primary-light);
  border: 1px solid var(--gsj-color-border);
  border-radius: var(--gsj-radius-card);
}

.ag-cartel__h {
  font-family: var(--gsj-font-heading);
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  /* El aire hasta la primera tarjeta lo pone el rótulo: al retirarse la nota, un margen de
     2px dejaba el encabezado pegado a la lista. */
  margin: 0 0 var(--gsj-space-3);
}


/* Sin `gap`: el separador entre tarjetas lo pone la línea de 0.5px del componente base,
   igual que en la lista de jornadas. Un `gap` acá sumaría una segunda forma de separar. */
.ag-cartel__lista { display: block; }

/* 🔴 LA TARJETA ES LA MISMA QUE LA DE LAS JORNADAS (`SjturCards::evento()`); acá sólo cambia
   la CAJA, porque va sobre el fondo tonal de la banda y no sobre el blanco de la lista.
   La versión anterior tenía un ítem propio con su markup y su CSS, y medido lado a lado era
   otro componente: meta en Lora 14px contra Ubuntu 13px y título peso 600 contra 700.
   Mantener dos componentes sincronizados a mano es justo lo que este proyecto ya pagó caro
   con la tarjeta de evento antes de subirla a `SjturCards`. */
/* 🔴 SIN CAJA PROPIA: la tarjeta se comporta exactamente igual que dentro de `.ag-lista`.
   La versión anterior le puso fondo blanco, borde y radio, y [U] lo cazó de una: «¿card
   dentro de card?». Era cierto —una caja con borde y radio adentro de otra caja con borde y
   radio— y además incoherente, porque las tarjetas de las jornadas NO tienen caja: se separan
   con la línea de 0.5px del componente base.
   Lo que distingue a la banda es su fondo tonal y su rótulo, no una caja por fila. El
   modificador queda casi vacío, y eso es la señal de que la consistencia es real y no
   maquillada: si hiciera falta redefinir tipografías o espaciados, serían dos componentes. */
.ag-card--cartel {
  padding-left: 0;
  padding-right: 0;
}

/* Y el chip de fecha se oculta, igual que en `.ag-card--jornada`. Ahí se oculta porque la
   fecha ya está en el encabezado del día; acá porque **una ventana no tiene UN día**: el chip
   mostraba «Hoy» para algo que dura veinte, y el dato temporal correcto —«Hasta el 26 de
   agosto»— ya está en la línea de meta. */
.ag-card--cartel .gsj-event-card__date { display: none; }

/* 🔴 `--gsj-color-primary-text` y NO `--gsj-color-primary`: el segundo es el naranja de MARCA,
   para rellenos, y medido sobre el render da 3.01:1 en texto chico — debajo del 4.5:1 de WCAG.
   El primero es el mismo color oscurecido para texto y da 6.64:1; es el que ya usa
   `.ag-card__tema` en esta misma pantalla. Leyendo el CSS los dos parecen «el rojo del sitio».
   Va por CLASE y no por posición: el orden de la meta cambia según qué datos tenga el evento. */
.ag-card__hasta {
  font-weight: 600;
  color: var(--gsj-color-primary-text);
}

/* ---- `--afiche` en el hero de la ficha de evento ----------------------------------------
   🔴 MISMO PROBLEMA QUE EN LA TARJETA, EN UN LUGAR MÁS AGRESIVO: acá el `cover` recorta a
   180/300 px de alto a todo el ancho, así que un afiche 4:5 pierde ~70 % de su alto —y lo
   que se pierde es el título—. Medido sobre los 10 afiches de la Agenda Cultural: 7 con
   relación menor que 1.2. La condición la decide `SjturCards::esAfiche()`, la MISMA que usa
   la tarjeta: si cada pantalla tuviera su propia regla, se contradirían.
   El fondo es una copia desenfocada del propio afiche, como un segundo `<img>` y no como un
   `background-image` inline (ver el override). */
.ev-hero--afiche { position: relative; }
.ev-hero--afiche img { object-fit: contain; position: relative; z-index: 1; }
.ev-hero__fondo {
  object-fit: cover !important;
  position: absolute !important;
  inset: 0;
  z-index: 0 !important;
  /* ⚠️ El `scale` no es cosmético: `blur()` samplea fuera del borde y sin agrandar deja un
     halo translúcido en los cuatro lados. */
  filter: blur(24px) saturate(1.35);
  transform: scale(1.15);
}

/* Scopeado al contenedor (0,2,0) para ganarle al reset `p:last-child{margin-bottom:0}`
   del DS base (0,1,1): `.ev-lugar` es el último hijo de `.ev-encabezado`, así que el
   margen inferior que pide acá se perdía y la línea de lugar quedaba pegada a la foto. */
.ev-encabezado .ev-lugar {
  font-family: var(--gsj-font-heading);
  font-size: 0.875rem;
  color: var(--gsj-color-text-muted);
  margin: 0 0 14px;
  display: flex;
  align-items: center;
  gap: 6px;
}

.ev-tema { margin-bottom: 10px; }

.ev-desc { font-size: 0.9375rem; line-height: 1.65; margin: 0 0 20px; color: var(--gsj-color-text-secondary); }

.ev-proximas {
  background: var(--gsj-color-primary-light);
  border-radius: var(--gsj-radius-card);
  padding: 20px;
  margin-bottom: 20px;
}

/* Estado «ya pasó»: el mismo bloque, en gris, para que no se lea como una invitación
   a algo que no va a ocurrir. */
.ev-proximas--vencido { background: var(--gsj-color-bg-muted); }
.ev-proximas__volver { margin-top: 14px; }

.ev-proximas__h { font-family: var(--gsj-font-heading); font-size: 1.125rem; font-weight: 700; margin: 0 0 4px; }
.ev-proximas__cadencia { margin: 0 0 16px; font-size: 0.875rem; color: var(--gsj-color-brand-text); }
.ev-salidas { display: flex; flex-direction: column; gap: 10px; }

.ev-salida {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding-bottom: 10px;
  border-bottom: 0.5px solid rgba(0, 0, 0, 0.08);
}

.ev-salida__cuando { font-family: var(--gsj-font-heading); font-weight: 500; font-size: 0.9375rem; color: var(--gsj-color-text); }
.ev-salida__horas { font-size: 0.875rem; color: var(--gsj-color-text-secondary); text-align: right; }

.ev-h3 { font-family: var(--gsj-font-heading); font-size: 0.9375rem; margin: 0 0 4px; }
.ev-sub { font-size: 0.8125rem; margin: 0 0 12px; color: var(--gsj-color-text-muted); }

/* 🔴 LOS DOS CTA DE LA TARJETA COMPARTEN REGLA, no una cada uno. `.ev-cta-ics` ya tenía
   `width: 100%` y al sumar «Comprar entradas» quedaron de anchos distintos —257 y 314 px—
   apilados, con el borde derecho dentado. Lo vio [U] pidiendo comparar uno con otro.
   Van juntos en el selector a propósito: si mañana alguien cambia el ancho de uno, cambia los
   dos, que es la única forma de que dos botones hermanos no se separen con el tiempo. */
.ev-cta-ics,
.ev-cta-entradas { width: 100%; gap: 8px; margin-top: 16px; }

/* 🔴 CUANDO HAY DOS CTA, EL SECUNDARIO NECESITA CONTORNO. Medido sobre el render: el botón
   tonal contra el bloque tonal de mobile daba **1.01:1** —son casi el mismo color, así que el
   botón no tenía ningún límite visual y sólo se veía su texto— y **1.11:1** contra la tarjeta
   blanca del aside. Lo preguntó [U]: «¿y en mobile? ¿qué onda el contraste con el fondo de
   ese bloque?».
   Ninguna de las cuatro variantes del DS lo arregla: las cuatro resuelven al mismo relleno.
   Un primario sólido + un secundario con contorno es además el emparejamiento estándar.
   ⚠️ El selector es `~` y no una clase nueva: el contorno aparece SÓLO cuando el botón de
   entradas está delante, o sea cuando este botón es de verdad secundario. Sin venta sigue
   siendo el primario y no le corresponde contorno. */
.ev-cta-entradas ~ .ev-cta-ics {
  /* Gris neutro y NO `--gsj-color-primary-text`: en rojo, el contorno competía con el botón
     primario sólido y quedaban «dos cosas rojas» (lo objetó [U]). Éste da **5.28:1 sobre el
     bloque tonal y 5.62:1 sobre la tarjeta blanca**, o sea que sobra sobre el mínimo de 3:1.
     ⚠️ NO se usa `--gsj-color-border`, que sería lo natural: medido componiéndolo sobre el
     fondo real da **1.36:1** — es justamente por eso que el botón no tenía límite visible.
     Un `rgba()` leído sobre lienzo vacío informa 9.84:1 y engaña. */
  border: 1px solid var(--gsj-color-text-muted);
}

/* La tarjeta «Próxima salida» del aside. En el kit es un `style=""` inline sobre un
   div suelto; acá es una clase porque la reusa el estado 3 de `agenda-estados`. */
.ev-tarjeta-salida {
  background: var(--gsj-color-surface);
  border: 0.5px solid var(--gsj-color-border);
  border-radius: var(--gsj-radius-card);
  padding: 22px;
}

.ev-tarjeta-salida__rotulo {
  font-family: var(--gsj-font-heading);
  font-size: 0.8125rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--gsj-color-text-muted);
  margin: 0 0 4px;
}

.ev-tarjeta-salida__cuando { font-family: var(--gsj-font-heading); font-size: 1.375rem; font-weight: 700; margin: 0 0 2px; }
.ev-tarjeta-salida__hora { font-size: 0.875rem; color: var(--gsj-color-text-secondary); margin: 0 0 18px; }

.ev-bloque-tema { border-top: 0.5px solid var(--gsj-color-border); padding-top: 18px; }

/* Mapa. El kit lo retrata en fallback («todavía no geocodificado»); en el catálogo
   real la ubicación de DPCalendar trae lat/long, así que el estado normal es el
   iframe y el fallback queda para los que no la tengan. */
.ev-mapa {
  border: 1px solid var(--gsj-color-border);
  border-radius: 12px;
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  background: var(--gsj-color-bg-subtle);
}

/* `height` explícito y `width:100%`: un <iframe> sin dimensiones cae al 300×150 por
   defecto del navegador. Ya pasó una vez en la ficha de prestador. */
.ev-mapa iframe { width: 100%; height: 280px; border: 0; border-radius: 8px; display: block; }

.ev-mapa__dir { margin: 0; font-family: var(--gsj-font-heading); font-weight: 500; display: flex; align-items: flex-start; gap: 8px; }
.ev-mapa__nota { margin: 0; font-size: 0.8125rem; color: var(--gsj-color-text-muted); }

.ev-aside { display: none; }
.ev-solo-desktop { display: none; }
/* 🔴 `u-solo-mobile` HACE LO MISMO QUE `ev-solo-mobile` Y SE LLAMA DISTINTO A PROPÓSITO.
   `auditar_fidelidad.js` indexa por prefijo de diseño y `ev-` está en su lista: sumarla a
   `.ev-proximas` cambiaría su clave y el bloque saldría de la comparación **sin bajar el
   puntaje**. Con `u-` la clave no cambia y se sigue auditando. */
.ev-solo-mobile,
.u-solo-mobile { display: block; }

@media (min-width: 900px) {
  .ev-grid { grid-template-columns: 1fr 360px; }
  /* ≥900 el hero vive en la columna de contenido (832px): 300px de alto = 2,77:1. */
  .ev-hero { aspect-ratio: auto; height: 300px; max-height: none; border-radius: var(--gsj-radius-card); margin: 0 0 24px; order: 2; }
  .ev-encabezado { order: 1; }
  .ev-desc { order: 3; font-size: 1.0625rem; line-height: 1.7; margin-bottom: 28px; max-width: 620px; }
  .ev-proximas { order: 4; padding: 24px; margin-bottom: 28px; max-width: 620px; }
  .ev-proximas__h { font-size: 1.25rem; }
  .ev-proximas__cadencia { font-size: 0.9375rem; margin-bottom: 18px; }
  .ev-salida { gap: 16px; padding-bottom: 12px; }
  .ev-salida__cuando { font-size: 1rem; }
  .ev-salida__horas { font-size: 0.9375rem; }
  .ev-bloque-programa { order: 5; max-width: 620px; }
  .ev-bloque-lugar { order: 6; }
  .ev-bloque-mapa { order: 7; }
  .ev-encabezado .ev-lugar { font-size: 0.9375rem; margin-bottom: 20px; }
  .ev-h3 { font-size: 1.125rem; margin-bottom: 16px; }
  .ev-aside { display: flex; flex-direction: column; gap: 24px; }
  .ev-solo-desktop { display: block; }
  .ev-solo-mobile,
  .u-solo-mobile { display: none; }
  .ev-mapa { max-width: 620px; }
}

/* El bloque «Programa» es markup de DPCalendar y necesita su clase contenedora para que
   apliquen sus reglas `dp-schedule-*`, que son descendientes. Pero esa misma clase trae
   `display:grid; grid-template-columns:1fr 1fr 1fr`, que acá no corresponde: el bloque es
   una lista dentro de nuestra columna. Se neutraliza sólo el rol de maquetación. */
/* `display:block` NO alcanza: `.com-dpcalendar-event` de DPCalendar declara además
   `grid-template-columns:1fr 1fr 1fr` y sus `grid-template-rows`, que quedan especificados
   aunque el elemento ya no sea grid — y el auditor los compara. Se neutralizan los tres. */
.ev-bloque-programa.com-dpcalendar-event { display: block; grid-template-columns: none; grid-template-rows: none; }
/* El encabezado del bloque. Sin esto hereda el h2 de PÁGINA y sale a 48px: es el mismo
   caso de «propiedad no declarada» que obligó a declarar color y tipografía en la EventCard. */
.ev-bloque-programa .dp-heading { font-family: var(--gsj-font-heading); font-size: 1.125rem; font-weight: 700; margin: 0 0 16px; line-height: 1.28; letter-spacing: -0.01em; }

/* JERARQUÍA DEL TRAMO. El markup es de DPCalendar y no declara ninguna: los tres renglones
   salían idénticos —18px, peso 400, mismo color— así que la HORA, que es el eje por el que
   alguien decide a qué acto ir, pesaba lo mismo que la duración y que la aclaración.
   El tratamiento no se inventa: es el que el DS ya usa para la metadata de sus tarjetas
   (`gsj-event-card__meta`, `gsj-prestador-card__location`) — dato principal en tipografía de
   título, secundario en footnote atenuado. El orden hora → duración lo arregla el override
   `com_dpcalendar/event/default_schedule.php`, porque mover sólo lo visible con `order`
   dejaría el orden de LECTURA al revés. */
/* 🔴 EL SANGRADO IZQUIERDO NO ES DECORATIVO: DPCalendar dibuja un TIMELINE —`border-left`
   de 2px más un punto `::after` en `left:-7px`— y su `padding: .9em 1.2em` es lo único que
   mantiene el texto fuera de esa línea. La primera versión de este bloque puso
   `padding: … 0` y el contenido quedó ENCIMADO sobre el timeline; lo vio [U] en pantalla.
   Se conserva la geometría de DP (que para un cronograma es el patrón correcto) y se
   recolorean línea y punto con los tokens del DS, en vez de su `silver`. Y NO se agrega
   `border-bottom`: el timeline ya separa los tramos, dos separadores compiten. */
.ev-bloque-programa .dp-schedule-list__item {
  padding: var(--gsj-space-4) 0 var(--gsj-space-4) var(--gsj-space-6);
  border-left: 2px solid var(--gsj-color-border);
  color: inherit;
}
/* 🔴 EL PUNTO SE DECLARA ENTERO —`content`, `position`, tamaño— y no sólo su color. De
   fábrica lo dibuja el CSS de DPCalendar (`media/com_dpcalendar/css/.../event/default.min.css`),
   que el SITIO carga pero el KIT no: recolorearlo nada más dejaba el kit sin timeline y al
   sitio con uno, o sea las dos pantallas distintas y el DS dependiendo de una hoja de
   terceros para verse bien. Con la declaración completa, kit y sitio dibujan lo mismo aunque
   mañana DP cambie o quite su CSS. La geometría es la de DP —el punto centrado sobre la
   línea de 2px— para no mover lo que ya estaba bien. */
.ev-bloque-programa .dp-schedule-list__item::after {
  content: "";
  display: block;
  position: absolute;
  top: var(--gsj-space-5);
  left: -7px;
  width: 10px;
  height: 10px;
  border: 2px solid var(--gsj-color-primary);
  border-radius: 50%;
  background: var(--gsj-color-surface);
}
.ev-bloque-programa .dp-schedule__title {
  font-family: var(--gsj-font-heading);
  font-size: var(--gsj-font-size-headline);
  font-weight: 700;
  line-height: 1.28;
  color: var(--gsj-color-text);
}
.ev-bloque-programa .dp-schedule__duration {
  font-family: var(--gsj-font-heading);
  font-size: var(--gsj-font-size-footnote);
  color: var(--gsj-color-text-muted);
  margin-top: 2px;
  /* Declarada, no heredada de DPCalendar: su hoja pone `font-style:italic` en
     `.dp-schedule__duration` y el kit no la carga. Sin esto, kit y sitio diferían. */
  font-style: italic;
}
/* La aclaración sí va en el cuerpo del sitio: es prosa, no metadata. */
.ev-bloque-programa .dp-schedule__description { font-size: var(--gsj-font-size-footnote); color: var(--gsj-color-text-muted); margin-top: 4px; }
.ev-bloque-programa .dp-schedule__description:empty { display: none; }

/* El kit trae este margen como `style=""` en el h1; acá se declara, porque es aire de la
   página y no una decisión de la instancia. */
.ev-encabezado .gsj-section-header__title { margin: 0 0 6px; }

/* En mobile el bloque «Organiza» va en el flujo principal y necesita separarse del que
   sigue; en desktop vive en el aside, que ya tiene su propio `gap`. El kit lo trae como
   `style="margin-bottom:20px"` sobre el div. */
.ev-bloque-lugar.ev-solo-mobile { margin-bottom: 20px; }

/* ────────────────────────────────────────────────────────────────────────────
   LISTADO DE LA AGENDA  (`ag-*`)
   `/agenda`: lista cronológica con recurrencia resuelta + rail de facetas, y una
   vista mensual secundaria al pie en desktop. Fuente de verdad:
   `ui_kits/sitio/agenda.html`, donde estas reglas viven inline.

   Las facetas del kit son `<label>` con checkbox porque su mock era estático; acá
   son enlaces (`ag-faceta`), que es lo que corresponde a un filtro que cambia la
   URL y tiene que funcionar sin JavaScript y ser navegable por teclado.
   ──────────────────────────────────────────────────────────────────────────── */

.ag-main { padding-bottom: 56px; }

/* CANON DE CABECERA (fila 11, decidido 2026-08-06). Las tres magnitudes del h1 y su
   bajada son las mismas en toda pantalla de listado, y viven acá donde significan lo
   mismo en el kit y en el sitio — que NO es `.ag-main`: en el sitio `.ag-main` es el
   contenedor de página (`gsj-page-main ag-main`) y en el kit es la columna de
   resultados dentro de `.ag-layout`. Poner el aire ahí habría movido cosas distintas.
     · margin-top 20px  → h1 a 20px del breadcrumb (169px de tope en las 4 con miga)
     · margin-bottom 12px → gap h1→bajada
     · bajada 1rem / 1.125rem en desktop (era 0.9375/1.0625: la agenda era la única
       pantalla un escalón por debajo de las otras cuatro) */
.ag-h1 { margin: 20px 0 12px; }
.ag-h1-extra { display: none; }
.ag-bajada { color: var(--gsj-color-text-secondary); margin: 0 0 18px; font-size: 1rem; }

/* El cuerpo del listado va sobre `bg-subtle`, como el directorio (`.sj-directorio-cuerpo`)
   y la búsqueda (`.sj-busqueda-cuerpo`). Antes era blanco sobre blanco: la tarjeta de
   `.ag-lista` quedaba separada del fondo sólo por 1px al 18% de alfa, y el rail no se leía
   como panel. Era la única de las tres pantallas con rail que no tenía la banda.

   🔴 A SANGRE COMPLETA CON `::before`, no con la banda como caja propia. Es el mismo patrón
   —y el mismo motivo— que `.pr-main::before`: `.gsj-page-main` está acotado a 1280px, así
   que un fondo puesto en la caja se leería como una banda recortada en pantallas anchas.
   `inset-inline: calc(50% - 50vw)` lo estira al viewport sin tocar la maquetación.
   ⚠️ Y no se reestructuró el DOM a propósito: `sjtur-agenda.js` busca `.gsj-sheet`,
   `[data-ag-panel]` y `[data-ag-facetas]` DENTRO de `.ag-main`, y `.ag-js` (que esconde el
   rail) también cuelga de ahí. Sacar `.ag-layout` a una `<section>` hermana —que es como lo
   arma el directorio— habría matado el bottom-sheet entero. */
.ag-layout { display: flex; flex-direction: column; gap: 20px; position: relative;
             padding-top: 32px; padding-bottom: 56px; }
.ag-layout::before { content: ""; position: absolute; z-index: 0; inset-block: 0;
                     inset-inline: calc(50% - 50vw); background: var(--gsj-color-bg-subtle); }
/* `z-index` a secas, SIN `position: relative`: los hijos son ítems flex y respetan
   `z-index` sin posicionarse. Ponerles `position:relative` —como hace `.pr-main > *`, que
   no tiene hijos sticky— le sacaría el `position: sticky` al rail en desktop. */
.ag-layout > * { z-index: 1; }

/* 🔴 EL RAIL LLEGA VISIBLE A TODO ANCHO Y LO ESCONDE `ag-js`, no un breakpoint a
   secas. La regla anterior era `.ag-rail{display:none}` y el reemplazo en mobile era una
   tira de chips; ahora el reemplazo es el bottom-sheet, que **existe sólo si el JS corre**.
   Esconder el rail por ancho dejaría la página sin ninguna forma de filtrar en el navegador
   que no ejecutó el script — que es exactamente lo que se midió en `/busqueda-avanzada` a
   390px: rail oculto, sheet sin implementación, 0 facetas. */
.ag-rail { display: block; }
.ag-js .ag-rail { display: none; }

/* Componentes que declaran su `display` (`.gsj-sheet`, `.gsj-button`) le ganan al `[hidden]`
   del user-agent. Sin esta guardia el scrim del sheet «cerrado» tapa la página entera y se
   come todos los clicks — medido en las pantallas del buscador, misma regla que `.at-main`
   y `.com-finder`. */
.ag-main [hidden] { display: none !important; }
.ag-principal { min-width: 0; }

.ag-rail__titulo { font-size: 0.9375rem; font-weight: 700; margin: 0 0 16px; }

/* La faceta es un enlace: hay que devolverle la caja del `gsj-facets__option` del kit
   y sacarle la decoración de enlace.
   🔴 SIN `color`. Acá decía `color: inherit`, puesto para matar el azul de enlace, y de
   paso pisaba el `--gsj-color-text-secondary` que declara el propio `.gsj-facets__option`
   (misma especificidad 0,1,0, y este archivo carga después). Resultado: las facetas de la
   agenda se veían en texto pleno y las de servicios y búsqueda en secundario — el mismo
   componente del DS con dos colores. La auditoría de fidelidad NO puede detectarlo: en el
   sitio el elemento es `a.ag-faceta.gsj-facets__option` y en el kit `label.gsj-facets__option`,
   distinta firma ⇒ nunca entran a la comparación, y la agenda daba 58/58 igual.
   Quitar la declaración —en vez de repetir el token— deja que gobierne el componente.
   `.ag-faceta` se emite siempre junto a `.gsj-facets__option` (un solo uso en el override). */
.ag-faceta { text-decoration: none; cursor: pointer; }
.ag-faceta:hover { text-decoration: underline; }
.ag-faceta.is-selected { font-weight: 700; color: var(--gsj-color-primary-text); }

/* La lista vive en una tarjeta: el separador de `gsj-event-card` necesita un marco
   para leerse. Es la misma nota que trae el kit. */
.ag-lista {
  background: var(--gsj-color-surface);
  border: 0.5px solid var(--gsj-color-border);
  border-radius: var(--gsj-radius-card);
  padding: 0 18px;
}

.ag-card { text-decoration: none; }
.ag-card__hoy { font-size: 1rem; }
.ag-card__tema { color: var(--gsj-color-primary-text); }

/* C5 (2026-09-22): chip «Entradas a la venta» de la EventCard. Peso 600 para que se lea como
   DATO, y NO el rojo de `.ag-card__tema`/`.ag-card__hasta`: tres cosas en rojo en una línea
   de meta ya no destacan ninguna. Es información, no un botón: la tarjeta entera es el enlace. */
.ag-card__entradas { font-weight: 600; color: var(--gsj-color-text-secondary); }

/* «Entrada libre y gratuita» en la ficha de evento: reemplaza al botón de compra cuando el campo
   «Entrada» dice gratuita y no hay link. Mismo ícono y peso que el chip del listado; no es botón. */
.ev-entrada-gratis {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 12px;
  font-family: var(--gsj-font-heading);
  font-weight: 600;
  color: var(--gsj-color-text);
}
.ev-entrada-gratis svg { width: 20px; height: 20px; flex: none; }

.ag-resumen { margin-bottom: 14px; }
.ag-resultados { font-family: var(--gsj-font-heading); font-size: 0.9375rem; color: var(--gsj-color-text-secondary); }
.ag-chips { margin-bottom: 18px; }

/* Barra de filtros de mobile. El kit la define como una fila con el botón «Filtros» y
   una tira de chips desplazable; acá los chips son los que filtran. */
.ag-mobile-bar { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
.ag-mobile-bar > div { flex: 1; min-width: 0; }

/* El botón que abre el sheet. `flex:0 0 auto` y `gap:8px` son los del kit; el `justify`
   está declarado porque `.gsj-button` no lo trae y en una fila flex el icono y el texto
   quedan a merced del ancho sobrante. */
.ag-filtros-btn { flex: 0 0 auto; justify-content: center; gap: 8px; }

/* El pie del sheet: «Limpiar» al ancho de su texto y «Ver eventos» ocupando el resto,
   como en el kit (`flex:0 0 auto` / `flex:1`). Van con clase propia y no con `style=`
   inline, que es lo que hace el mock. */
.ag-sheet__limpiar { flex: 0 0 auto; }
.ag-sheet__aplicar { flex: 1; }

.ag-nota {
  font-size: var(--gsj-font-size-caption-1);
  color: var(--gsj-color-text-muted);
  line-height: 1.5;
  margin: 16px 0 0;
}

/* Estado vacío. El kit lo resuelve dentro de un marco en `agenda-estados`; acá es el
   contenido de la columna, centrado. */
.ag-vacio { text-align: center; padding: 8px 8px 22px; }
.ag-vacio__icono {
  width: 76px; height: 76px; margin: 0 auto 16px;
  border-radius: 50%;
  background: var(--gsj-color-bg-muted);
  display: flex; align-items: center; justify-content: center;
  color: var(--gsj-color-text-muted);
}
.ag-vacio__titulo { font-size: 1.25rem; margin: 0 0 8px; text-wrap: balance; }
.ag-vacio__texto { font-size: 0.9375rem; margin: 0 0 18px; line-height: 1.55; color: var(--gsj-color-text-secondary); }
.ag-vacio__acciones { display: flex; flex-direction: column; gap: 10px; }

/* «Mientras tanto, en …» — el consuelo del estado vacío (`agenda-estados`, caso 1).
   Hermano de `.ag-vacio` y no hijo: aquél está centrado y éste va alineado a la izquierda,
   como las dos mitades del marco del kit.

   ⚠️ EL TÍTULO Y LA BAJADA DECLARAN TODO, incluida la `line-height`. En el kit son un `h3`
   y un `p` PELADOS que heredan del DS; el sitio además carga nucleus y bootstrap, que le
   dan otra base a los mismos dos elementos. Es exactamente el defecto que el kit no puede
   revelar —van 15 apariciones—, y acá evitarlo cuesta cuatro declaraciones. */
.ag-mientras {
  border-top: 0.5px solid var(--gsj-color-border);
  padding-top: 20px;
  margin: 0;
  /* `start` y no `left`: es el valor que computa el kit —donde nadie declara nada— y el
     que hay que declarar acá, porque el hermano de arriba (`.ag-vacio`) está centrado y
     un futuro reacomodo del markup se lo llevaría puesto. */
  text-align: start;
}
.ag-mientras__titulo {
  font-family: var(--gsj-font-heading);
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.28;
  color: var(--gsj-color-text);
  margin: 0 0 4px;
}
.ag-mientras__nota {
  font-family: var(--gsj-font-body);
  font-size: 0.8125rem;
  font-weight: 400;
  line-height: 1.625;
  color: var(--gsj-color-text-muted);
  margin: 0 0 14px;
}
.ag-mientras__lista { display: flex; flex-direction: column; gap: 12px; }

/* Navegación de rango. La vista de fábrica la traía y sin ella no hay forma de mirar
   más allá del mes en curso: es función, no adorno. */
.ag-rango { display: flex; justify-content: space-between; gap: 12px; margin-top: 20px; }

/* ── Vista mensual (complemento de desktop) ──────────────────────────────── */
.ag-mes { margin-top: 48px; }
.ag-mes__head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; }
.ag-mes__titulo { font-size: 1.5rem; margin: 0; }
/* El margen va en la BASE y se anula en la grilla de días, que es como lo trae el kit:
   allá la primera grilla (los nombres de día) lleva `style="margin-bottom:6px"` y la
   segunda no lleva nada. Tenerlo al revés no cambiaba nada en pantalla, pero hacía que
   el auditor comparara dos grillas distintas y marcara una divergencia falsa. */
.ag-mes__grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; margin-bottom: 6px; }
.ag-mes__grid--dias { margin-bottom: 0; }

.ag-mes__wd {
  text-align: center;
  font-family: var(--gsj-font-heading);
  font-size: 12px; font-weight: 700;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--gsj-color-text-muted);
  padding: 4px 0;
}

.ag-mes__day {
  min-height: 76px;
  border-radius: var(--gsj-radius-sm);
  padding: 6px;
  background: var(--gsj-color-surface);
  border: 0.5px solid var(--gsj-color-border);
}

.ag-mes__day--empty { background: transparent; border-color: transparent; }

.ag-mes__n {
  font-family: var(--gsj-font-heading);
  font-size: 13px; font-weight: 500;
  color: var(--gsj-color-text);
  display: flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; border-radius: 50%;
}

.ag-mes__mark {
  display: inline-block; margin-top: 6px;
  font-size: 10.5px; line-height: 1.2; font-weight: 600;
  padding: 2px 6px; border-radius: 9999px;
}

.ag-mes__mark--primary { background: var(--gsj-color-primary-fill); color: #fff; }

/* ── El día del calendario, ahora clickeable (PENDIENTES filas 13b/14) ──────────
   El número que cada día dibuja es la promesa de una información y hasta el
   2026-08-07 no llevaba a ningún lado (medido: 0 elementos clicables). Ahora es un
   `<a>` real —anda sin JavaScript y se puede compartir— así que necesita área de
   click, foco visible y estado elegido.
   🔴 El enlace ocupa la celda ENTERA (`inset: 0` sobre el `.ag-mes__day` relativo) y
   no sólo el número: un blanco de 24px en una celda de 76 es la clase de objetivo
   táctil que el Bloque 2 de a11y ya corrigió en el resto del sitio. */
.ag-mes__day { position: relative; }

/* ⚠️ SIN `display:flex`, y no es indiferente. La primera versión lo puso en columna y eso
   convirtió a `.ag-mes__mark` en ítem flex: pasó de `inline-block` a `block`, que es una
   divergencia REAL contra el kit y no cosmética. El enlace se queda como bloque normal para
   que sus hijos rindan exactamente igual que cuando colgaban del `.ag-mes__day`. */
.ag-mes__link {
  position: absolute; inset: 0;
  padding: 6px;
  text-decoration: none; color: inherit;
  border-radius: var(--gsj-radius-sm);
}

.ag-mes__link:hover { background: var(--gsj-color-bg-subtle); }

.ag-mes__link:focus-visible {
  outline: 2px solid var(--gsj-color-primary-fill);
  outline-offset: 2px;
}

/* El día elegido se marca en el CONTENEDOR y no en el enlace: así el estado sigue
   ahí aunque el foco se mueva. */
.ag-mes__day--sel {
  border-color: var(--gsj-color-primary-fill);
  box-shadow: inset 0 0 0 1px var(--gsj-color-primary-fill);
}

/* ── La jornada, cuando la lista se agrupa por día (PENDIENTES fila 19, corrección de [U])
   El kit no dibuja este encabezado: su mock de agenda es una lista plana. Es divergencia
   declarada, del mismo tipo que el día clicable del calendario. */
.ag-jornada + .ag-jornada { margin-top: 20px; }

/* ── EL ENCABEZADO DE JORNADA ───────────────────────────────────────────────────
   Rediseñado el 2026-08-07 a pedido de [U], y MIDIENDO la pantalla antes de decidir.
   Tres cosas salieron de la medición y ninguna se veía leyendo el CSS:

   🔴 1. LA JERARQUÍA ESTABA INVERTIDA. El encabezado era 15px/700 y los títulos de las
      tarjetas que agrupa son **18px/700**: la sección quedaba por debajo de sus propios
      ítems. Ahora es 20px, un escalón por encima.
   🔴 2. EL `sticky` NUNCA FUNCIONÓ. `#g-page-surround` de Gantry tiene `overflow:hidden`,
      que anula `position:sticky` en todos sus descendientes. Medido: al desplazar, el
      encabezado se iba con la sección (y=−181 los dos). El comentario que decía «pegajoso al
      desplazar» era falso. Se destraba abajo, ACOTADO a esta pantalla.
   🔴 3. EL PILL «HOY» REPROBABA CONTRASTE: 3.54:1 con texto de 11px, y AA pide 4.5. Usaba
      `on-primary-container` —que es el par del container CLARO— sobre `primary-fill`.
      Con `on-primary` (blanco) da **4.97**. Medido, no estimado.

   La lista mide 5.958px de alto a 1280 y **10.287px a 390**: el encabezado es lo único que
   dice dónde estás parado, así que tiene que sostener el scroll. */
.ag-jornada__titulo {
  font-family: var(--gsj-font-heading);
  /* 20px: un escalón POR ENCIMA de los 18px del título de tarjeta. */
  font-size: 20px; font-weight: 700;
  letter-spacing: 0;
  color: var(--gsj-color-text);
  display: flex; align-items: baseline; gap: 10px;
  margin: 0 0 8px;
  padding: 12px 0 10px;
  border-bottom: 0.5px solid var(--gsj-color-border);
  /* Pegajoso al desplazar: en «Este mes» son ~25 jornadas y sin esto, a mitad de una
     jornada larga, se pierde de vista de qué día se está mirando — que es justo lo que
     este agrupado vino a resolver. */
  position: sticky; top: 0; z-index: 1;
  background: var(--gsj-color-surface);
}

/* En jornada el bloque de fecha de la tarjeta es redundante: el día ya lo dice el
   encabezado. Se conserva el espacio de la hora, que es lo que se escanea. */
.ag-card--jornada .gsj-event-card__date { display: none; }

/* «Hoy» como acento y no como prefijo del texto: el día de la semana se sigue leyendo. */
.ag-jornada__hoy {
  font-size: 11px; font-weight: 700;
  letter-spacing: 0.06em; text-transform: uppercase;
  /* `on-primary` y NO `on-primary-container`: el segundo es el par del container claro y
     sobre el fill daba 3.54:1 con texto de 11px. Con éste, 4.97:1. */
  color: var(--gsj-color-on-primary);
  background: var(--gsj-color-primary-fill);
  border-radius: 9999px;
  padding: 2px 8px;
  flex: none;
  /* 🔴 El encabezado alinea por `baseline`, que es lo correcto para TEXTO —la fecha y el
     contador comparten línea de base aunque midan 20 y 13px—. Pero este chip es una CAJA con
     fondo y padding: alinearlo por su baseline lo empuja **3,3px** abajo del centro de la
     fecha y se lee torcido. Lo vio [U]. Una caja se alinea por su centro óptico. */
  align-self: center;
}

/* 🔴 LA FECHA ADOPTA EL REGISTRO DE RÓTULO DEL DS (caja alta + tracking), y no crece.
   Lo pidió [U]: «entre título de jornada y título de evento debería notarse mejor la
   diferencia». El problema no era que 20px fuera poco: **20 y 18 difieren en un solo canal y
   apenas un 11%**, con familia, peso (700) y color idénticos. Dos razones:
     · la escala modular no tiene ese escalón — el paso mínimo perceptible es ~1.2 y 20/18 es
       1.11; el vecino de 18 hacia arriba es 24;
     · y sobre todo, **encabezado y título nunca entran en la misma fijación ocular**: una
       jornada mide 900-2000px, así que la comparación se hace de memoria, y la memoria no
       resuelve un 11% de tamaño. Hace falta un canal que se decodifique SIN referencia.
   Subir el tamaño era la palanca equivocada: el encabezado es **wayfinding**, no contenido;
   si crece, le compite a los 10 enlaces que introduce.
   🔸 Es el registro que el DS ya usa para rótulos —7 precedentes en este mismo archivo, y el
   propio rail de esta pantalla («FILTRAR», «ZONA»)—, así que no estrena nada. De paso unifica
   el encabezado consigo mismo: el pill «HOY» ya era caja alta con tracking y la fecha no.
   🔸 Va en `__fecha` y NO en `__titulo`: el `text-transform` heredaría al contador
   («9 actividades»), que tiene que seguir en caja baja.
   🔸 Se descartó la palanca de COLOR midiendo: `.ag-card__tema` ya usa el rojo de marca en
   **70 instancias** de esta página, así que pintar la fecha de ese tono le daría al
   encabezado el color que acá ya significa «tema».
   🔸 Contraste sin cambios: 18.42:1, porque no toca ningún color. */
.ag-jornada__fecha {
  color: inherit;
  text-transform: uppercase;
  /* ⚠️ SIN `letter-spacing`, a pedido de [U]: el tracking que acompaña a la caja alta en los
     rótulos chicos del DS (11-13px) no le sienta a 20px. A ese tamaño la caja alta ya
     distingue el registro por sí sola, y el tracking la vuelve un titular de afiche. */
}

/* El contador de la jornada: empuja a la derecha y se lee en secundario. */
.ag-jornada__n {
  margin-left: auto;
  font-family: var(--gsj-font-body);
  font-size: 13px; font-weight: 400;
  color: var(--gsj-color-text-secondary);
  flex: none;
}

/* 🔴 DESTRABA EL `sticky`, Y SÓLO EN ESTA PANTALLA. `#g-page-surround` lleva
   `overflow:hidden` —de Gantry, en todo el sitio— y eso anula `position:sticky` en cualquier
   descendiente. `clip` recorta igual pero NO crea contenedor de desplazamiento, así que el
   sticky vuelve a funcionar. Va con `:has()` para no tocar ninguna otra página: medido, con
   `clip` el encabezado se pega (y=0 con la sección en −72) y **no aparece scroll horizontal**,
   que es lo que ese `hidden` estaba evitando. */
#g-page-surround:has(.ag-main) { overflow: clip; }

@media (max-width: 640px) {
  /* ⚠️ El tamaño NO baja a 18px en mobile aunque sobre menos ancho: el título de tarjeta
     mide 18px también a 390, así que bajarlo empata la jerarquía y vuelve el problema que
     este rediseño vino a corregir. Lo que cede es el layout, no el peso. */
  .ag-jornada__titulo { flex-wrap: wrap; row-gap: 2px; }
  .ag-jornada__n { margin-left: 0; width: 100%; }
}



/* ── Paginación dentro del rango (PENDIENTES fila 19 · pedido de [U]) ───────────
   Distinta de `.ag-rango`, que cambia el MES. Ésta recorre lo que hay adentro. */
.ag-pag {
  display: flex; align-items: center; justify-content: center;
  gap: 12px; flex-wrap: wrap;
  margin-top: 20px;
}

.ag-pag__estado {
  font-size: 13px;
  color: var(--gsj-color-text-muted);
}

/* Los chips de tema, cuando el evento tiene más de uno (PENDIENTES · fila 19, hilo de tags).
   ⚠️ El separador NO puede quedar librado al espacio en blanco del HTML: `gsj-badge` es
   `inline-flex` y un `foreach` que emita los elementos pegados los deja soldados. Medido: el
   gap de 4,2px que se veía era whitespace colapsado, no una regla. */
.ev-tema + .ev-tema { margin-left: 6px; }

.ev-bloque-tema__chips { display: flex; flex-wrap: wrap; gap: 6px; }





.ag-solo-desktop { display: none; }
.ag-solo-mobile { display: block; }

@media (min-width: 900px) {
  .ag-layout { flex-direction: row; gap: 40px; align-items: flex-start; }
  /* 🔴 El par con `.ag-js` es OBLIGATORIO: sin él, `.ag-js .ag-rail
     {display:none}` —dos clases, (0,2,0)— le gana a `.ag-rail` de acá, que vale (0,1,0),
     y el rail desaparecería en DESKTOP con el JS puesto. Es el mismo defecto que ya se
     pagó una vez en el rail del buscador. */
  /* La card del rail: los mismos 4 valores que `.dir-rail` y `.bus-rail` declaran en su
     bloque de 900px. Sobre la banda `bg-subtle` es lo que hace que el rail se lea como
     panel de filtros y no como texto suelto al costado. */
  .ag-js .ag-rail,
  .ag-rail { display: block; flex: 0 0 260px; position: sticky; top: 20px;
             background: var(--gsj-color-surface); border: 1px solid var(--gsj-color-border);
             border-radius: 20px; padding: 20px; }
  .ag-mobile-bar { display: none; }
  .ag-principal { flex: 1; min-width: 0; }
  .ag-solo-desktop { display: block; }
  .ag-solo-mobile { display: none; }
  .ag-h1-extra { display: inline; }
  .ag-lista { padding: 4px 24px; }
  /* 1.125rem, no 1.0625: canon de la bajada (fila 11). Ver la nota en `.ag-h1`. */
  .ag-bajada { margin-bottom: 24px; font-size: 1.125rem; }
}

/* ── Cabecera de ficha de PROMOCIÓN — sin recorte ────────────────────────────────
   Pedido de [U] el 2026-08-12 mirando «San Juan Todo el Año»: la horizontal en desktop.
   La caja genérica `.art-media` es 16:6 con `object-fit:cover`, y ninguna de las dos
   piezas de una promo entra sin perder algo — medido: la de mobile (4:5) deja ver el
   30 % del alto y la de desktop (4:1) el 67 % del ancho.
   🔴 Acá manda la IMAGEN, igual que en el banner del home: se ve entera. Es la regla que
   `Promo-Imagenes-Spec.md` ya declaraba («las dos se muestran enteras, sin recortar») y
   que en esta pantalla era el último lugar donde no se cumplía. */
.art-media--promo {
  aspect-ratio: auto;
  min-height: 0;
}
.art-media--promo picture,
.art-media--promo img {
  display: block;
  width: 100%;
  height: auto;
  object-fit: fill;
}

/* ── FICHA DE PROMOCIÓN ──────────────────────────────────────────────────────────
   Layout copiado de `ui_kits/sitio/promociones-ficha-externa.html`, donde vivía en el
   `<style>` local de la pantalla. Va acá porque es maquetación de PÁGINA, no un
   componente del DS. 2026-08-12. */
.promo-main { padding-bottom: 8px; }

/* 🔴 `contain` y no `cover`: una promo es una gráfica COMPUESTA (título, CTA, logos) y
   recortarla le come alguna de las tres. El kit lo dice: «Badges y título van DEBAJO». */
.promo-hero__frame {
  position: relative;
  margin-top: var(--gsj-space-5);
  border-radius: var(--gsj-radius-card);
  overflow: hidden;
  background: var(--gsj-color-bg-muted);
  /* 🔴 6:1 EN DESKTOP PORQUE ES LA MEDIDA ESTÁNDAR QUE SE LE PIDE AL CLIENTE
     (2400 × 400, `DEV-docs/Promo-Imagenes-Spec.md`). El kit traía 5/2, pero su mock usa un
     placeholder «Fotografía pendiente» — ese marco se diseñó SIN una pieza real adentro.
     Medido con arte real: un 6:1 dentro de un 2,5:1 con `contain` dejaba **191 px de banda
     vacía, el 58 % del marco**, o sea que cuanto MÁS cumplía la pieza, PEOR se veía.
     [U] 2026-08-12: «la idea es tener banners estándar que le pueda pedir al cliente» — si el
     marco se adapta a lo que llegue, no hay estándar que pedir. */
  aspect-ratio: 6/1;
}
.promo-hero__frame picture,
.promo-hero__frame img { display: block; width: 100%; height: 100%; object-fit: contain; }
@media (max-width: 575px) { .promo-hero__frame { aspect-ratio: 16/9 } }

.promo-badges { display: flex; gap: 8px; flex-wrap: wrap; margin: 16px 0 12px; }
.promo-titulo {
  font-family: var(--gsj-font-heading); font-weight: 700;
  font-size: var(--gsj-font-size-title-1); color: var(--gsj-color-text);
  margin: 0; line-height: 1.1;
}
.promo-encabezado {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--gsj-space-5); margin: var(--gsj-space-6) 0 var(--gsj-space-8);
}
.promo-bajada { flex: 1; min-width: 260px; font-size: 1.125rem; line-height: 1.5; color: var(--gsj-color-text); }
.promo-bajada p { margin: 0; }
.promo-vigencia { align-self: flex-start; font-size: var(--gsj-font-size-footnote); }

.ficha-grid {
  display: grid; grid-template-columns: minmax(0, 1fr) 320px;
  gap: var(--gsj-space-8); align-items: start;
}
@media (max-width: 768px) { .ficha-grid { grid-template-columns: 1fr } }

.promo-prose {
  font-family: var(--gsj-font-body); color: var(--gsj-color-text-secondary);
  line-height: var(--gsj-line-height-relaxed, 1.65); font-size: 1rem;
}
.promo-prose h2 {
  font-family: var(--gsj-font-heading); font-weight: 700; color: var(--gsj-color-text);
  font-size: var(--gsj-font-size-title-3); margin: var(--gsj-space-8) 0 var(--gsj-space-4);
}
.promo-prose h2:first-child { margin-top: 0; }
.promo-prose h3 {
  font-family: var(--gsj-font-heading); font-weight: 500; color: var(--gsj-color-text);
  font-size: var(--gsj-font-size-headline); margin: var(--gsj-space-6) 0 var(--gsj-space-2);
}
.promo-prose p { margin: 0 0 var(--gsj-space-4); }
.promo-prose ol, .promo-prose ul { margin: 0 0 var(--gsj-space-4); padding-left: 1.35em; }
.promo-prose li { margin-bottom: var(--gsj-space-3); padding-left: 4px; }
.promo-prose li::marker { color: var(--gsj-color-primary-text); font-family: var(--gsj-font-heading); font-weight: 700; }
.promo-prose strong { color: var(--gsj-color-text); font-weight: 600; }

.promo-aside { position: sticky; top: 24px; display: flex; flex-direction: column; gap: var(--gsj-space-6); }
.promo-aside__caja {
  border: 1px solid var(--gsj-color-border); border-radius: var(--gsj-radius-card);
  padding: var(--gsj-space-6); background: var(--gsj-color-surface);
}
.promo-aside__titulo {
  font-family: var(--gsj-font-heading); font-weight: 600;
  font-size: var(--gsj-font-size-headline); margin: 0 0 6px;
}
.promo-aside__texto {
  margin: 0 0 var(--gsj-space-5); font-size: var(--gsj-font-size-footnote);
  color: var(--gsj-color-text-muted); line-height: 1.5;
}
.promo-aside__cta { width: 100%; justify-content: center; gap: 8px; }
.promo-aside__nota {
  margin: 10px 0 0; font-size: var(--gsj-font-size-caption-1);
  color: var(--gsj-color-text-muted); line-height: 1.45;
}
.promo-aside__rotulo {
  margin: 0 0 8px; font-size: var(--gsj-font-size-footnote);
  color: var(--gsj-color-text-muted); font-family: var(--gsj-font-heading);
}

