/* style.css — home page specific styles (hero, product sections, captured plans, loop, etc.) */

/* ════════════════════════════════════════════════════════════════════════════
   CINEMATIC GLOBALS — semibold display, mono metadata, grain + gradient
   ════════════════════════════════════════════════════════════════════════════ */

/* --font-mono and --font-sans are declared in common.css :root and inherited here. */

/* Mono for editorial metadata: timestamps, photographer credits, scroll hint, footer.
   Section titles, kickers, badges, prices, ratings and lang switch stay Public Sans. */
/* `.hero-scroll-hint span` ahora vive en common.css como parte del
   componente compartido — quitado de aquí 2026-05. */
.loopD-num,
.plan-case-meta,
.photo-credit,
.footer-bottom {
  font-family: var(--font-mono);
  font-weight: 400;
  letter-spacing: 0.04em;
  font-feature-settings: 'ss01' off;
}

.plan-case-meta,
.photo-credit,
.footer-bottom {
  font-size: var(--text-mono-sm);
  letter-spacing: 0.02em;
}

/* The Loop accordion numbers — mono rhythm, clapperboard feel */
.loopD-num { font-size: var(--text-body-sm); letter-spacing: 0.06em; }

/* App + Premium pair — both share `--gradient-strong` (deep base).
   Their distinctive character comes from the `.has-vignette--strong`
   overlay positioned ad-hoc (right for App, left for Premium) behind
   the device mockup of each section. Position is set here as a
   page-specific override — it's NOT a documented modifier in the DS,
   each section places the vignette where its key visual element sits. */
.product-section--app {
  background: var(--gradient-strong);
  --vignette-x: 70%;   /* behind the iPhone mockup on the right */
}

/* ─── Mobile reorder · The App ────────────────────────────────────────
   En ≤1024px los phones (.app-showcase) van ENTRE el body del producto
   y los CTAs. Lo conseguimos extrayendo los CTAs a un sibling
   .product-copy--actions (ver HTML) · DOM order ya es copy → showcase
   → actions, así que en mobile (1 col stack) sale como queremos.

   En DESKTOP (>1024px), el grid 2-col coloca:
     · copy + actions juntos en columna 1 (rows 1 y 2)
     · showcase en columna 2 spanning ambos rows · centrado vertical
   El resultado visual es idéntico a antes en desktop. */
@media (min-width: 1025px) {
  /* `1fr auto auto 1fr` · las dos filas 1fr (arriba/abajo) centran el
     bloque copy+actions verticalmente contra el mockup Y absorben el
     exceso de altura del showcase — sin esto el exceso se repartía entre
     copy (row) y actions (row), separándolos. `row-gap: 0` quita el gap
     del grid entre copy y actions (que era 48-96px); el spacing estipulado
     copy→CTA (32px / 2rem) lo pone el margin-top de las actions. El
     column-gap del grid se conserva. */
  .product-section--app .product-grid {
    grid-template-rows: 1fr auto auto 1fr;
    row-gap: 0;
  }
  .product-section--app .product-copy {
    grid-column: 1;
    grid-row: 2;
  }
  .product-section--app .product-copy--actions {
    grid-column: 1;
    grid-row: 3;
    margin-top: 2rem; /* 32px · gap estipulado texto→botones */
  }
  .product-section--app .app-showcase {
    grid-column: 2;
    grid-row: 1 / 5;
    align-self: center;
  }
}

/* En mobile, .product-copy--actions hereda las mismas reglas de
   centrado que .product-copy tiene en mobile (text-align: center,
   centrar el pitch-cta). */
@media (max-width: 1024px) {
  .product-section--app .product-copy--actions {
    text-align: center;
  }
  .product-section--app .product-copy--actions .pitch-cta {
    justify-content: center;
  }

  /* Safety margin · el parallax (factor 0.1) puede mover los teléfonos
     hasta ~40px hacia abajo durante el scroll. Añadimos margin-bottom
     para que NUNCA lleguen a tocar los CTAs · el gap del grid (3rem)
     no es suficiente con parallax activo. 64px da margen holgado. */
  .product-section--app .app-showcase {
    margin-bottom: clamp(32px, 6vw, 64px);
  }
}


/* ─── Mismo patrón para Premium (laptop) ─────────────────────────────
   DOM order: copy → laptop → actions. En desktop el grid los
   re-posiciona: laptop a la izquierda (col 1, spanning rows), copy
   arriba derecha (col 2 row 1), actions abajo derecha (col 2 row 2).
   .product-grid--reverse mantiene su grid-template-columns 3fr/2fr.

   En mobile el grid es 1 columna y el DOM order vale: 1) copy, 2)
   laptop, 3) actions. Hace falta order: 3 en actions porque
   common.css fija order: 1 en .product-copy y order: 2 en
   .laptop-showcase dentro de .product-grid--reverse — sin esto las
   actions caerían arriba del todo (default order 0). */
@media (min-width: 1025px) {
  /* Mismo patrón que The App · ver nota allí. `1fr auto auto 1fr` centra
     el bloque copy+actions y absorbe el exceso del laptop; `row-gap: 0`
     + `margin-top: 2rem` (32px) restauran el spacing estipulado copy→CTA. */
  .product-section--premium .product-grid {
    grid-template-rows: 1fr auto auto 1fr;
    row-gap: 0;
  }
  .product-section--premium .product-copy {
    grid-column: 2;
    grid-row: 2;
  }
  .product-section--premium .product-copy--actions {
    grid-column: 2;
    grid-row: 3;
    margin-top: 2rem; /* 32px · gap estipulado texto→botones */
  }
  .product-section--premium .laptop-showcase {
    grid-column: 1;
    grid-row: 1 / 5;
    align-self: center;
  }

  /* El último .pitch-body del bloque de texto lleva margin-bottom: 2rem
     (32px). Como .product-copy es grid item (crea su propio BFC), ese
     margen NO colapsa y queda atrapado DENTRO del box, inflando el gap
     visual texto→botones a 32+32 = 64px. Lo anulamos en desktop para que
     el único espacio sea el margin-top: 2rem (32px) de las actions.
     (En mobile el margen sí hace falta para separar texto del mockup.) */
  .product-section--app .product-copy:not(.product-copy--actions) > .pitch-body:last-child,
  .product-section--premium .product-copy:not(.product-copy--actions) > .pitch-body:last-child {
    margin-bottom: 0;
  }
}

@media (max-width: 1024px) {
  .product-grid--reverse .product-copy--actions {
    order: 3;
  }
  .product-section--premium .product-copy--actions {
    text-align: center;
  }
  .product-section--premium .product-copy--actions .pitch-cta {
    justify-content: center;
  }

  /* Mismo safety margin que el App section · el laptop con parallax
     factor 0.1 puede desplazarse y "tocar" los CTAs sin este buffer. */
  .product-section--premium .laptop-showcase {
    margin-bottom: clamp(32px, 6vw, 64px);
  }
}

.product-section--premium {
  background: var(--gradient-strong);
  --vignette-x: 30%;   /* behind the laptop mockup on the left */
}
/* Móvil (≤1024 · grid apilado a 1 col) · el laptop deja de estar a la
   izquierda y pasa a media altura del stack (copy → laptop → actions) ·
   centramos el vignette (x 50%) para que quede detrás del laptop en vez
   de arriba-izquierda. */
@media (max-width: 1024px) {
  /* Centrado horizontal + bajado (y 60%) para que caiga justo detrás del
     laptop en el stack apilado, no por encima. */
  .product-section--premium { --vignette-x: 50%; --vignette-y: 60%; }
}


/* ────────────────────────────────────────────────────────────────────────
   Movement at scroll
   1. Mask-reveal headlines (clip from below + slight rise)
   2. Stagger on grouped reveal items
   3. Parallax: see script.js — extended to plan tiles + product showcases
   ──────────────────────────────────────────────────────────────────────── */

/* Headlines inside .reveal start hidden behind clip-path. When .reveal becomes
   .visible, they slide-in from below with a soft cinematic curve. */
.reveal :where(.section-title, .hero-tagline, h2:not(.section-title)) {
  clip-path: inset(0 0 102% 0);
  transform: translateY(18px);
  transition:
    clip-path 1.05s var(--ease-soft) 0.05s,
    transform 1.05s var(--ease-soft) 0.05s;
  will-change: clip-path, transform;
}
.reveal.visible :where(.section-title, .hero-tagline, h2:not(.section-title)) {
  clip-path: inset(0 0 0 0);
  transform: translateY(0);
}

/* Subtitle / lead body: same idea but smaller distance + later */
.reveal :where(.section-subtitle, .pitch-body) {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity var(--dur-glide) var(--ease-soft) 0.25s,
              transform var(--dur-glide) var(--ease-soft) 0.25s;
}
.reveal.visible :where(.section-subtitle, .pitch-body) {
  opacity: 1; transform: translateY(0);
}

/* Stagger in plan cases (case studies grid) */
.plan-case { transition-delay: var(--stagger, 0ms) !important; }
.plan-cases > .plan-case:nth-child(1) { --stagger: 80ms; }
.plan-cases > .plan-case:nth-child(2) { --stagger: var(--dur-instant); }
.plan-cases > .plan-case:nth-child(3) { --stagger: 320ms; }

@media (prefers-reduced-motion: reduce) {
  .reveal :where(.section-title, .hero-tagline, h2, .section-subtitle, .pitch-body) {
    clip-path: none !important;
    transform: none !important;
    opacity: 1 !important;
    transition: none !important;
  }
}

/* ────────────────────────────────────────────────────────────────────────
   Density & breathing — .section / .section-lg paddings ahora viven
   en common.css (valores 160-280 / 200-320, simétricos). No duplicar aquí.
   ──────────────────────────────────────────────────────────────────────── */

/* Moderate the seam between The App and Premium: enough breathing room for
   each section to feel composed, but tighter than the default so the two
   vignettes can fuse instead of being separated by a flat band. Placed
   after .section to win the cascade. */
.product-section--app,
.product-section--premium {
  padding-top: var(--section-pad-y-md);
  padding-bottom: var(--section-pad-y-md);
}

/* Captured Plans — flat black with a very subtle vertical fade so the
   carousel of photos lands on its own ground. Tighter top padding so the
   section reveals quickly after Premium. */
/* Captured Plans — sits on a slightly elevated dark grey so the section
   reads as its own block against Premium (very dark) above and the
   statement slide below. A soft radial highlight behind the carousel
   lifts the photo slider off the page. */
.captured-plans {
  /* Photographic content band — shared with Plan Every Shot. */
  background: var(--gradient-soft);
  padding: var(--section-pad-y-md) 0;
}

/* Tighter rhythm in Captured Plans — the section-header sits closer
   to the carousel so the divider connects visually to the cases. */
.captured-plans .section-header {
  margin-bottom: clamp(24px, 3vw, 40px);
}

.section-subtitle {
  line-height: 1.2;
  margin-bottom: clamp(48px, 6vw, 80px);
}

/* Section header: more space between subtitle and content below */
.section-header { margin-bottom: clamp(56px, 7vw, 96px); }

/* The Loop section: maintain its own min-height but breathe inside copy column */
.loopD-copy { padding: clamp(80px, 9vw, 140px) clamp(40px, 6vw, 96px); }

/* ────────────────────────────────────────────────────────────────────────
   Borders & radii — generous on cards, pill on chips/CTA
   ──────────────────────────────────────────────────────────────────────── */

/* Cards: prep tiles, plan cases, captured plans → roomy modern radius */
.prep-tile,
.plan-case,
.plan-case-image,
.captured-plan-card,
.case-card,
.plan-tile {
  border-radius: clamp(16px, 1.6vw, 24px);
}

/* Phone screens / laptop screens — already tight to device frame, leave them.
   Loop photo block: gentle radius on its container at desktop */
@media (min-width: 1024px) {
  .loopD { border-radius: 0; }
  .loopD-grid { border-radius: 0; overflow: hidden; }
}

/* Chips: pill always */
.prep-chip { border-radius: var(--radius-full); }


/* Headlines: semibold + tighter tracking for cinematic weight */
.hero-tagline,
/* `.section-title` is 600 globally now (common.css). This rule keeps the
   home-specific h2 selectors aligned with the same weight + tracking. */
.statement-headline,
.product-copy h2,
.loopD-copy > h2,
.final-cta h2 {
  font-weight: 600;
  letter-spacing: -0.03em;
}

/* Paragraphs inside The Loop use text-wrap: balance so the body copy
   and callouts distribute lines evenly — no orphans, no jagged
   ragged-right edges. Scoped to .loop so other sections keep
   default wrapping. */
.loop p,
.loop .loop-callout {
  text-wrap: balance;
}

/* Subtle film grain — fixed overlay, never blocks pointer events */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: var(--z-grain);
  pointer-events: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0.55 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
  background-size: 240px 240px;
  mix-blend-mode: overlay;
  opacity: 0.08;
}

@media (prefers-reduced-motion: reduce) {
  body::after { opacity: 0.05; }
}

/* PRUEBA (iOS) · el grano es una capa fixed full-screen con mix-blend-mode
   por encima de todo (z-9999). En iOS ese tipo de capa puede hacer que el
   compositor recomponga mal las capas de debajo y pinte la nav fija POR
   DETRÁS del contenido (el hero se ve sobre la barra, aunque lógicamente la
   nav esté encima). Lo desactivamos en móvil para comprobar si es el culpable
   — en móvil el grano es prácticamente imperceptible. */
@media (max-width: 720px) {
  body::after { display: none; }
}

/* Atmospheric vignettes are handled by the `.has-vignette` utility in
   common.css. Sections opt in by adding the class to their markup,
   with optional modifiers --strong (intensity) and --right/--left/
   --top/--bottom (position). */


/* ════════════════════════════════════════════════════════════════════════════
   HERO
   ════════════════════════════════════════════════════════════════════════════ */
.home-hero-media {
  position: absolute;
  inset: -10% 0;
  z-index: 1;
  will-change: transform;
}

.home-hero-media video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.home-hero-media::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--scrim-hero);
  z-index: 2;
}

.home-hero-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center center;
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity var(--dur-cinema) var(--ease-cinematic);
}


.home-hero-media img.active {
  opacity: 1;
  animation: slowZoom 20s var(--ease-out) forwards;
}

@media (prefers-reduced-motion: reduce) {
  .home-hero-media img.active { animation: none; }
}

/* (Visuals come from .cta-row in common.css; keep this selector empty
   so future hero-specific tweaks have a hook.) */


.home-hero .hero-eyebrow {
  display: inline-block;
  font-size: var(--text-body-md);
  font-weight: 600;
  letter-spacing: 2.5px;
  text-transform: uppercase;
  color: var(--gray-white) !important;
  margin-bottom: 2rem;
  opacity: 1;
}

/* Home hero tagline inherits .hero-tagline from common.css.
   Only page-specific overrides go here. */

.home-hero {
  position: relative;
  min-height: 100svh;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  /* Asimetría justificada: hero 100svh con contenido flex-centered. El
     padding-top usa el token --section-pad-y-xl (120-220) para reservar
     espacio bajo la nav fixed; el bottom queda más ajustado para que el
     centro óptico del bloque caiga en el tercio superior, no en el
     geométrico. Única excepción a la regla de simetría (regla 8). */
  padding-top: var(--section-pad-y-xl);
  padding-bottom: clamp(80px, 14vh, 160px);
}

.home-hero-content {
  position: relative;
  z-index: 3;
  /* Padding horizontal canónico (= .container · var(--gutter)) para
     mantener consistencia con el resto de secciones en todos los
     viewports. */
  padding: 0 var(--gutter);
  max-width: 1024px;
  /* `backwards` (no `both`): aplica el estado inicial durante el delay
     (sin flash) pero NO conserva el transform al terminar. Con `both`, el
     `transform: translateY(0)` residual de fadeUp dejaba a este contenedor
     como backdrop-root permanente, anulando el `backdrop-filter` del
     `.btn-tertiary` glass del hero (no se veía el blur). Al revertir a
     "sin transform" tras la entrada, el blur del botón vuelve a funcionar. */
  animation: fadeUp var(--dur-glide) var(--ease-out) var(--dur-soft) backwards;
  margin-left: auto;
  margin-right: auto;
}


/* ════════════════════════════════════════════════════════════════════════════
   PLAN EVERY SHOT
   ════════════════════════════════════════════════════════════════════════════ */

.prep-scroller-wrap {
  position: relative;
  width: 100%;
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 6%, #000 94%, transparent 100%);
  mask-image: linear-gradient(90deg, transparent 0, #000 6%, #000 94%, transparent 100%);
}

.prep-scroller {
  display: flex;
  align-items: center;
  gap: 16px;
  overflow-x: auto;
  overflow-y: visible;
  scroll-snap-type: none;
  scroll-behavior: smooth;
  scrollbar-width: none;
  /* Asymmetric vertical padding: tighter on top AND bottom so the
     chips above and the prev/next controls below sit closer to the
     carousel. The 70px bottom is still enough for the active tile's
     scale + drop shadow without clipping. */
  padding: 60px clamp(10vw, 22vw, 24vw) 70px;
  -webkit-overflow-scrolling: touch;
}

.prep-scroller::-webkit-scrollbar {
  display: none;
}

.prep-tile.is-active {
  transform: scale(1.14);
  filter: brightness(1) saturate(1.05) opacity(1);
  /* Subtle white stroke + photographic vignette inside + drop shadow.
     The atmospheric halo is now painted on the section background so it
     extends behind the chips and paginator, not just under the tile. */
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.12),
    inset 0 0 100px 12px rgba(0, 0, 0, 0.55),
    0 18px 44px rgba(0, 0, 0, 0.45);
  margin: 0 1.75rem;
  z-index: 2;
  opacity: 1;
}

/* Non-active tiles fade back slightly so the focused one carries the
   attention without flattening the rest of the gallery. */
.prep-tile:not(.is-active) {
  opacity: 0.78;
  transition: opacity var(--dur-glide) var(--ease-soft),
              transform var(--dur-glide) var(--ease-soft),
              box-shadow var(--dur-glide) var(--ease-soft),
              filter var(--dur-glide) ease;
}

.prep-tile:hover:not(.is-active) {
  transform: scale(1.02);
  filter: brightness(0.94) saturate(1);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.06),
    0 14px 36px rgba(0, 0, 0, 0.32);
}

.prep-tile.is-active:hover {
  transform: scale(1.04);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.14),
    inset 0 0 110px 12px rgba(0, 0, 0, 0.55),
    0 28px 64px rgba(0, 0, 0, 0.6),
    0 0 0 1px rgba(0, 0, 0, 0.4);
}

.prep-tile img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform var(--dur-glide) var(--ease-soft);
}

.prep-tile-video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform var(--dur-glide) var(--ease-soft);
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.prep-tile.is-active img {
  transform: scale(1.03);
}

.prep-tile figcaption {
  position: absolute;
  left: -1px;
  right: -1px;
  /* Overshoot below by 2px so the gradient covers the very bottom edge
     without leaving a thin seam between the figcaption and the inset
     stroke when the tile is scaled. */
  bottom: -2px;
  padding: 4rem 1.4rem 1.6rem;
  color: var(--gray-white);
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  /* Gradiente · termina al 90% en la base (no 100%) para que la foto
     asome un poco bajo el texto. */
  background: linear-gradient(
    to top,
    rgba(0, 0, 0, 0.9)  0%,
    rgba(0, 0, 0, 0.82) 25%,
    rgba(0, 0, 0, 0.6)  55%,
    rgba(0, 0, 0, 0)    100%
  );
}

.prep-tile-title {
  font-weight: 600;
  font-size: var(--text-body-lg);
  letter-spacing: -0.01em;
  line-height: 1.2;
}

.prep-tile-author {
  /* Mono caption — same editorial credit style used elsewhere on
     the page (.plan-attribution, .map-cite). Slightly smaller than
     the title, lighter colour. */
  font-family: var(--font-mono);
  font-size: var(--text-body-sm);
  font-weight: 400;
  letter-spacing: 0.04em;
  color: rgba(255, 255, 255, 0.7);
}

.prep-section {
  padding: var(--section-pad-y-md) 0;
  /* Photographic band gradient. The seam against neighbouring sections
     is carried by the gradient itself, not a hairline — keeps the dark
     cinematic continuity uninterrupted. */
  background: var(--gradient-soft);
}

/* Tighter rhythm in Plan Every Shot — shrink the gap from rule to chips
   and from chips to the carousel so the title block doesn't feel
   abandoned above the photos. */
.prep-section .section-header {
  margin-bottom: clamp(24px, 3vw, 40px);
}
.prep-section .section-header > .section-rule {
  margin: 1.5rem auto 0;
}
.prep-chips {
  margin-bottom: clamp(8px, 1.5vw, 20px);
}

.prep-scroller-wrap { position: relative; }

/* Bottom-centred carousel controls: prev arrow · counter · next arrow.
   Same circular glass language as Captured Plans, paired with a mono
   "01 / 17" counter so the user knows how many subjects are left. */
/* Position-only override — visuals come from .pager / .pager__* in
   common.css. */
.prep-pager {
  margin-top: clamp(8px, 1.2vw, 16px);
}

.prep-tile {
  position: relative;
  flex: 0 0 auto;
  width: clamp(280px, 28vw, 380px);
  aspect-ratio: 4 / 5;
  border-radius: var(--radius-s);
  overflow: hidden;
  margin: 0;
  background: var(--gray-11);
  box-shadow: var(--shadow-soft);
  scroll-snap-align: center;
  scroll-snap-stop: always;
  cursor: pointer;
  transform: scale(1);
  transform-origin: center center;
  transition: transform var(--dur-glide) var(--ease-soft),
    box-shadow var(--dur-glide) var(--ease-soft),
    filter var(--dur-glide) ease;
  filter: brightness(0.82) saturate(0.92);
  will-change: transform;
}

@media (prefers-reduced-motion: reduce) {
  .prep-tile-video {
    animation-play-state: paused;
  }
}

@media (max-width: 720px) {
  /* Chips en UNA fila con scroll horizontal (en vez de envolver en varias
     filas) · así las imágenes ganan alto. El JS centra el chip activo a
     medida que cambia la foto (ver setActiveBySubject). */
  .prep-chips {
    gap: 8px;
    /* A SANGRE · escapa el gutter del .container para que el scroll vaya de
       borde a borde · lead-in dentro (= gutter) para que el primer/último
       chip respiren. */
    margin: 1.5rem calc(-1 * var(--gutter)) 2rem;
    padding-inline: var(--gutter);
    flex-wrap: nowrap;
    justify-content: flex-start;
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    overscroll-behavior-x: contain;
  }
  .prep-chips::-webkit-scrollbar { display: none; }
  /* Fuera los degradados (mask) de los lados de la galería en móvil. */
  .prep-scroller-wrap { -webkit-mask-image: none; mask-image: none; }
  .prep-chip  { flex: 0 0 auto; padding: 8px 13px; font-size: var(--text-body-sm); }
  .prep-scroller {
    gap: 12px;
    /* Generous vertical padding so the active scaled tile (1.14x) and
       its drop shadow don't get clipped at the top, and there's enough
       breath before the paginator below. */
    padding: 36px clamp(5vw, 12vw, 18vw) 48px;
  }
  /* Imágenes más grandes (ganan protagonismo) al liberar el espacio que
     antes ocupaban las filas de chips. */
  .prep-tile { width: clamp(220px, 68vw, 300px); }

  /* More margin between the carousel and the paginator on mobile. */
  .prep-pager {
    margin-top: 1.25rem;
  }

  /* (Sin override de fondo en mobile · usa el MISMO --gradient-soft que
     desktop — la banda azulada es lo que la diferencia bien de los vecinos.
     El intento previo de poner un plano #0A0A0A la dejaba menos
     diferenciada que en desktop. El seam con Experiences (gradient-strong,
     top #14161e) se mantiene porque gradient-soft baja a #0c1018, más
     oscuro. Ya no hace falta box-shadow.) */
}

@media (prefers-reduced-motion: reduce) {
  .prep-scroller { scroll-behavior: auto; }
  .prep-tile,
  .prep-tile img { transition: none; transform: none !important; }
}

/* ════════════════════════════════════════════════════════════════════════════
   FINAL CTA
   ════════════════════════════════════════════════════════════════════════════ */

.final-cta-logo {
  /* Block-level + auto margins so the SVG always centres horizontally,
     regardless of inline-flow quirks (an `<a>` is inline by default
     and was being centred via text-align, which made the SVG sit a
     hair off-axis). */
  display: block;
  width: fit-content;
  margin: 0 auto 1rem;
}

.final-cta-logo svg {
  display: block;
}

.final-cta {
  /* Soft cinematic band — sits between the elevated content above and
     the deeper footer below, so both seams read clearly via the gradient
     fade rather than borders. */
  background: var(--gradient-soft);
  /* No more 85svh — section sized by its own content (logo + headline
     + buttons) plus a healthy padding. */
  min-height: 0;
  padding: var(--section-pad-y-md) 0;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  position: relative;
  isolation: isolate;
}

/* Film-grain overlay — very subtle, layered on top of the gradient
   to add tactile texture without compromising legibility. The SVG
   feTurbulence keeps it crisp at any DPR. */
.final-cta::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='220' height='220'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0.55 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
  background-size: 220px 220px;
  mix-blend-mode: overlay;
  opacity: 0.18;
}
@media (prefers-reduced-motion: reduce) {
  .final-cta::after { opacity: 0.10; }
}

.final-cta > .container {
  width: 100%;
}

.final-cta > * {
  width: 100%;
}

.final-cta h2 {
  font-family: var(--font-sans);
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1.05;
  font-feature-settings: 'ss01' on;
  font-size: clamp(var(--text-heading-md), 4.5vw, var(--text-heading-xl));
  color: var(--gray-white);
  max-width: 760px;
  /* Tighter top — 1rem from logo above; looser bottom — 3rem so the
     CTAs feel like a deliberate pause after the headline. */
  margin: 0 auto 3rem;
  text-align: center;
}

/* Final-cta variant of statement-headline — keeps the per-word reveal
   animation but with the bigger final-cta type ramp + centred lines. */
.statement-headline--final .statement-line { display: block; }
.statement-headline--final .statement-line-2 { margin-top: 0.2em; }

/* The h2 reveal is now driven by the per-word .statement-slide stagger
   (see .statement-headline .word). The old whole-headline blur/scale
   animation has been removed so they don't compete. */

/* Estado inicial OCULTO (fix flash) · el logo, el wordmark y los botones
   se animan con `finalCtaFade` (opacity 0→1) + delay + fill `both`. Sin
   este opacity:0 de base nacían VISIBLES y, al añadirse `.is-visible`, el
   relleno backwards del delay los escondía para reaparecer → el usuario
   veía el logo, luego desaparecer, luego entrar con la animación. Naciendo
   ocultos, solo aparecen con la animación. El observer de .final-cta
   siempre añade `.is-visible` (con fallback sin IO), así que no hay riesgo
   de quedar ocultos; reduced-motion los fuerza visibles abajo. */
.final-cta-logo,
.final-cta .wordmark,
.final-cta-buttons > * {
  opacity: 0;
}

.final-cta.is-visible .final-cta-logo {
  animation: finalCtaFade var(--dur-glide) var(--ease-soft) var(--dur-soft) both;
}

.final-cta.is-visible .wordmark {
  animation: finalCtaFade var(--dur-glide) var(--ease-soft) var(--dur-soft) both;
}

.final-cta.is-visible .final-cta-buttons > *:nth-child(1) {
  animation: finalCtaFade var(--dur-glide) var(--ease-soft) var(--dur-glide) both;
}

.final-cta.is-visible .final-cta-buttons > *:nth-child(2) {
  animation: finalCtaFade var(--dur-glide) var(--ease-soft) 0.72s both;
}

.final-cta.is-visible .final-cta-buttons > *:nth-child(3) {
  animation: finalCtaFade var(--dur-glide) var(--ease-soft) 0.84s both;
}

.final-cta-primary {
  height: 60px;
  padding: 0 28px;
  font-size: var(--text-body-md);
}

@media (prefers-reduced-motion: reduce) {
  .final-cta.is-visible h2,
  .final-cta.is-visible .final-cta-logo,
  .final-cta.is-visible .wordmark,
  .final-cta.is-visible .final-cta-buttons > * {
    animation: none !important;
    /* Sin animación pero visibles · si no, el opacity:0 de base los
       dejaría ocultos para siempre en reduced-motion. */
    opacity: 1;
  }
}

/* ════════════════════════════════════════════════════════════════════════════
   GET-APP PICKER
   ════════════════════════════════════════════════════════════════════════════ */

.get-app-picker {
  position: relative;
  display: inline-block;
}

.get-app-trigger {
  display: inline-flex;
  align-items: center;
  gap: 10px;
}

.get-app-caret {
  width: 12px;
  height: 12px;
  transition: transform var(--dur-soft) var(--ease-out);
}

.get-app-picker[data-open="true"] .get-app-caret {
  transform: rotate(180deg);
}

.get-app-menu {
  position: absolute;
  top: calc(100% + 12px);
  left: 50%;
  width: 320px;
  padding: 20px 22px;
  background: var(--bg-neutral-default);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: var(--radius-m);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  opacity: 0;
  pointer-events: none;
  transform: translateX(-50%) translateY(-4px);
  transition: opacity var(--dur-instant) var(--ease-out), transform var(--dur-instant) var(--ease-out);
  z-index: var(--z-chip);
}

.get-app-menu::before {
  content: '';
  position: absolute;
  top: -6px;
  left: 50%;
  width: 12px;
  height: 12px;
  background: var(--bg-neutral-default);
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  border-left: 1px solid rgba(255, 255, 255, 0.08);
  transform: translateX(-50%) rotate(45deg);
  pointer-events: none;
}

.get-app-picker[data-open="true"] .get-app-menu {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
  pointer-events: auto;
}

.get-app-options-row {
  display: contents;
}

.get-app-menu-header {
  display: none;
}

.get-app-option {
  display: block;
  line-height: 0;
  transition: opacity var(--dur-instant) var(--ease-out);
}

.get-app-option:hover {
  opacity: 0.85;
}

.get-app-option:focus-visible {
  outline: 2px solid var(--content-link-default);
  outline-offset: 3px;
  border-radius: var(--radius-s);
}

.get-app-option img {
  height: 48px;
  width: auto;
  display: block;
}

/* (Visuals come from .cta-row in common.css.) */

.product-section .reveal {
  opacity: 1;
  transform: none;
  transition: none;
}

.prep-section .reveal {
  opacity: 1;
  transform: none;
  transition: none;
}

@media (prefers-reduced-motion: reduce) {
  .get-app-menu,
  .get-app-option { transition: none !important; }
}

@media (prefers-reduced-motion: reduce) {
  .get-app-menu,
  .get-app-caret,
  .get-app-option { transition: none !important; }
}

@media (max-width: 1024px) {
  .verbs {
    grid-template-columns: 1fr;
    gap: 2.5rem;
  }

  .verb {
    grid-template-columns: 140px 1fr;
  }

  .plan-case {
    grid-template-columns: 1fr !important;
  }

  .plan-case.reverse .plan-visuals {
    order: initial;
  }

}

@media (max-width: 720px) {
  /* Note: .nav-links + .nav-lang rules are handled by the mobile nav
     block above (≤960px / ≤480px). Don't re-hide nav-links here or the
     mobile panel won't open. */
  /* En mobile el hero ocupa el viewport completo (mismo lenguaje que
     el hero de pricing / premium · 100svh excluye el chrome del browser
     para que no haya jump cuando la barra se oculta al hacer scroll). */
  .home-hero {
    min-height: 100svh;
  }

  .home-hero-cta {
    flex-direction: column;
    align-items: center;
    width: 100%;
    max-width: 320px;
    margin: 0 auto;
  }

  .home-hero-cta .btn {
    width: 100%;
  }

  /* CTAs un escalón más bajos en móvil · btn-l (62px) → medidas de btn-m
     (52px). El btn-l a ancho completo pesaba demasiado y le restaba
     protagonismo a los títulos. Solo home (este style.css es exclusivo). */
  .btn-l {
    height: 52px;
    padding: 14px 22px;
  }

  .section {
    padding: 4rem 0;
  }

  /* Móvil (feedback responsive 2026-07): tras probarlo, la subida de fuentes
     se PASÓ — el único escalón del DS llevaba subtítulo/body al tamaño de
     DESKTOP (grande en un teléfono). Volvemos a la escala responsive original
     (título 40, subtítulo 24, body 18: encogen en móvil a propósito). Se
     conserva el AIRE entre secciones (md 64→80, lg 96→120), que sí gustó. */
  .section-title {
    font-size: var(--text-heading-lg);
    line-height: 1.1;
  }
  :root {
    /* Solo el aire de sección se mantiene subido en móvil · las fuentes
       editoriales vuelven a su valor responsive (tokens sin override → su
       clamp: subtítulo 24, body 18 en móvil). */
    --section-pad-y-md: 80px;
    --section-pad-y-lg: 120px;
  }

  .verb {
    grid-template-columns: 1fr;
    gap: 0.5rem;
  }

  .plan-visuals {
    grid-template-columns: 1fr;
  }

}

@media (max-width: 480px) {
  /* Gutter lateral · gobernado por el token `--gutter` (16px) vía `.container`
     y `.home-hero-content`. NOTA: revierte la decisión previa de "32px en
     todos los viewports" — auditoría 2026-08 unificó el sitio a 16px. */

  .home-hero h1 {
    font-size: var(--text-heading-xl);
  }

  .final-cta {
    padding: 6rem 0;
  }
}

/* ════════════════════════════════════════════════════════════════════════════
   EXPERIENCES
   ════════════════════════════════════════════════════════════════════════════ */

.experiences-media {
  position: absolute;
  inset: 0;
  z-index: -2;
}

.experiences-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  filter: brightness(0.5) saturate(1.1) contrast(1.05);
}

.experiences-scrim {
  position: absolute;
  inset: 0;
  z-index: -1;
  background: radial-gradient(ellipse at center,
      rgba(0, 0, 0, 0.35) 0%,
      rgba(0, 0, 0, 0.65) 70%,
      rgba(0, 0, 0, 0.85) 100%),
    linear-gradient(180deg,
      rgba(0, 0, 0, 0.55) 0%,
      rgba(0, 0, 0, 0.45) 50%,
      rgba(0, 0, 0, 0.80) 100%);
}

.experiences-inner {
  width: 100%;
  max-width: 780px;
  text-align: center;
  display: flex;
  flex-direction: column;
  gap: clamp(24px, 3vw, 40px);
}

.experiences-header {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.experiences-title {
  font-size: clamp(var(--text-heading-lg), 6.5vw, var(--text-display-lg));
  font-weight: 400;
  letter-spacing: -0.03em;
  line-height: 1.05;
  margin: 0;
  color: var(--gray-white);
}

.experiences-body {
  max-width: 620px;
  margin: 1.25rem auto 0;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.experiences-body p {
  margin: 0;
  font-size: clamp(var(--text-body-md), 1.4vw, var(--text-body-lg));
  line-height: 1.55;
  color: var(--gray-1);
}

.experiences-body strong {
  font-weight: 700;
  color: var(--gray-white);
}

.experiences-stats {
  list-style: none;
  padding: clamp(20px, 2.5vw, 32px) 0;
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: clamp(20px, 3vw, 48px);
  border-top: 1px solid rgba(255, 255, 255, 0.22);
  border-bottom: 1px solid rgba(255, 255, 255, 0.22);
}

.experiences-stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.25rem;
  position: relative;
  min-width: 110px;
}

.experiences-stat + .experiences-stat::before {
  content: '';
  position: absolute;
  left: calc(-1 * clamp(10px, 1.5vw, 24px));
  top: 15%;
  bottom: 15%;
  width: 1px;
  background: rgba(255, 255, 255, 0.12);
}

.experiences-stat-value {
  font-size: clamp(var(--text-heading-md), 3.5vw, var(--text-heading-lg));
  font-weight: 300;
  letter-spacing: -0.02em;
  line-height: 1;
  color: var(--gray-white);
  font-variant-numeric: tabular-nums;
}

.experiences-stat-label {
  font-size: var(--text-body-xs);
  font-weight: 600;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--content-text-subtitle);
}

.experiences-testimonial {
  margin: 0;
  max-width: 720px;
  align-self: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.25rem;
}

.experiences-quote-mark {
  width: 32px;
  height: 32px;
  color: var(--bg-primary-default);
  opacity: 0.9;
}

.experiences-quote {
  font-size: clamp(var(--text-body-lg), 2.2vw, var(--text-lead));
  font-weight: 400;
  line-height: 1.4;
  letter-spacing: -0.01em;
  color: var(--gray-white);
  margin: 0;
  padding: 0;
  border: 0;
  text-align: center;
}

.experiences-cite {
  display: inline-flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 0.5rem;
  font-size: var(--text-body-xs);
  color: var(--content-text-subtitle);
  letter-spacing: 0.01em;
}

.experiences-cite-author {
  font-weight: 600;
  color: var(--gray-white);
}

.experiences-cite-sep {
  opacity: 0.5;
}

.experiences-cite-trip {
  width: 100%;
  font-size: var(--text-body-xs);
  font-weight: 600;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--bg-primary-default);
  margin-top: 0.25rem;
}

.experiences-cta {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 1.25rem 2rem;
}

.experiences-stat-plus {
  font-size: 0.65em;
  font-weight: 400;
  color: var(--yellow-5);
  margin-left: 1px;
}

.experiences-subtitle {
  margin: 0.75rem 0 0;
  font-size: clamp(var(--text-body-lg), 2.2vw, var(--text-lead));
  font-weight: 400;
  line-height: 1.3;
  color: var(--gray-white);
  letter-spacing: -0.01em;
}

.experiences {
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--gray-white);
  isolation: isolate;
  padding: clamp(56px, 6vw, 88px) 1.5rem;
  min-height: 80svh;
}

@media (max-width: 720px) {
  .experiences-stats {
    flex-wrap: wrap;
    gap: 1.5rem 2rem;
  }
  .experiences-stat {
    min-width: 90px;
  }
  .experiences-stat + .experiences-stat::before {
    /* Dividers get messy when wrapped — hide them on small screens */
    display: none;
  }
}

@media (max-width: 480px) {
  .experiences {
    min-height: 95svh;
  }
  .experiences-cta {
    flex-direction: column;
    gap: 1rem;
  }
}

/* ════════════════════════════════════════════════════════════════════════════
   REDUCED MOTION / ACCESSIBILITY
   ════════════════════════════════════════════════════════════════════════════ */



@media (prefers-reduced-motion: reduce) {
  /* Disable all infinite or ambient animations */
  .laptop-glow,
  .hero-scroll-hint {
    animation: none !important;
  }

  /* Ba-slider hint bounce */
  .ba-slider.hint .ba-handle {
    animation: none !important;
  }

  /* Scroll reveals — show everything immediately */
  .reveal {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }

  /* Hero photo crossfade */
  .home-hero-media img {
    transition: opacity var(--dur-instant) linear !important;
  }
}

/* ════════════════════════════════════════════════════════════════════════════
   THE LOOP — Split 50/50 accordion
   ════════════════════════════════════════════════════════════════════════════ */
.loopD { background: var(--gray-black); color: var(--gray-white); }
.loopD-grid {
  display: grid; grid-template-columns: 1fr 1fr;
  min-height: 680px;
}
.loopD-photo { position: relative; overflow: hidden; }
.loopD-img {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover;
  opacity: 0; transition: opacity var(--dur-glide) var(--ease-soft);
}
.loopD-img.is-active { opacity: 1; }
.loopD-copy {
  padding: clamp(60px, 7vw, 100px) clamp(32px, 5vw, 72px);
  display: flex; flex-direction: column; justify-content: center;
  background: var(--gray-9);
}
.loopD-kicker {
  font-size: var(--text-mono-sm); letter-spacing: 3px; text-transform: uppercase;
  color: var(--yellow-5); margin: 0 0 18px; font-weight: 600;
}
.loopD-copy > h2 {
  font-family: var(--font-sans);
  font-weight: 300; font-size: clamp(var(--text-heading-md), 4vw, var(--text-heading-xl));
  letter-spacing: -0.02em; line-height: 1.08; margin: 0 0 40px;
}
.loopD-items { display: flex; flex-direction: column; gap: 4px; }
.loopD-item {
  background: transparent; border: none; padding: 20px 0;
  border-top: 1px solid rgba(255,255,255,0.12);
  text-align: left; cursor: pointer; color: inherit;
  display: grid; grid-template-columns: auto 1fr; column-gap: 20px; row-gap: 0;
  align-items: baseline;
  transition: padding var(--dur-soft);
}
.loopD-item:last-child { border-bottom: 1px solid rgba(255,255,255,0.12); }
.loopD-num {
  font-family: var(--font-mono);
  font-weight: 400; font-size: var(--text-body-sm);
  color: rgba(255,255,255,0.5);
  grid-row: 1;
}
.loopD-title {
  font-family: var(--font-sans);
  font-weight: 400; font-size: clamp(var(--text-body-lg), 2.4vw, var(--text-heading-md));
  letter-spacing: -0.01em; color: rgba(255,255,255,0.55);
  grid-row: 1; transition: color var(--dur-soft);
}
.loopD-body {
  grid-column: 2; grid-row: 2;
  font-size: var(--text-body-md); font-weight: 300; line-height: 1.55;
  color: rgba(255,255,255,0.78);
  max-height: 0; overflow: hidden; opacity: 0;
  margin: 0;
  transition: max-height 0.5s, opacity 0.5s, margin var(--dur-soft);
}
.loopD-item.is-active .loopD-title { color: var(--yellow-5); }
.loopD-item.is-active .loopD-num { color: var(--yellow-5); }
.loopD-item.is-active .loopD-body {
  max-height: 200px; opacity: 1; margin-top: 12px;
}
@media (max-width: 1024px) {
  .loopD-grid { grid-template-columns: 1fr; }
  .loopD-photo { aspect-ratio: 4 / 3; }
}


/* ────────────────────────────────────────────────────────────────────────
   The Loop — V2 circle + V3 slide (exploration variants)
   Texts use project tokens: Public Sans for headlines/kickers/words,
   mono only for editorial metadata (none here). Kicker colour stays in
   the blue accent visible in the wireframe references.
   ──────────────────────────────────────────────────────────────────────── */

.loop {
  /* Deep gradient — differentiates against Statement Cinema (bg-bold)
     above and Plan Every Shot (gradient-soft) below. Vignette glow
     applied via .loop::before in this file's atmosphere block. */
  background: var(--gradient-strong);
  padding: var(--section-pad-y-lg) 0;
  position: relative;
  overflow: hidden;
}

/* Title / subtitle / pitch-body inside .loop use the same shared classes
   (.section-title, .section-subtitle, .pitch-body) as The App / Premium /
   Captured Plans. Only layout-specific tweaks live here. */
.loop--circle .loop-copy .section-title {
  text-align: left;
  margin-bottom: 1.25rem;
}

.loop--circle .loop-copy .section-subtitle {
  text-align: left;
  font-size: var(--text-editorial-subtitle);
  line-height: 1.125;
  font-weight: 300;
  max-width: none;
  margin: 0 0 2rem;
}

.loop--circle .loop-copy .section-rule {
  margin: 0 0 2rem;
}

.loop--circle .loop-copy .pitch-body {
  text-align: left;
  font-size: var(--text-editorial-body);
  line-height: 1.4;
  font-weight: 300;
  color: var(--content-text-subtitle);
  max-width: 42ch;
  margin: 0 0 2rem;
}

/* (Visuals come from .cta-row.cta-row--start in common.css.) */

.loop--slide .loop-slide-intro .section-rule { margin: 0 auto 1.75rem; }

/* ── V2: animated circle ─────────────────────────────────────────────── */

.loop--circle .loop-stage {
  max-width: var(--max-wide);
  margin: 0 auto;
  /* Padding horizontal canónico (= .container · var(--gutter)). */
  padding: 0 var(--gutter);
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
  gap: clamp(40px, 6vw, 96px);
  align-items: center;
}

.loop-diagram {
  position: relative;
  aspect-ratio: 1 / 1;
  width: 100%;
  max-width: 720px;
  margin: 0 auto;
}

/* The Loop V2 — infinite "comet" loop on 3 arcs.
   Each arc spans 120° (Imagine→Plan, Plan→Shoot, Shoot→Imagine) and lives a
   12s cycle in 3 phases of 4s:
     • Phase active (its 4s window): dashoffset 1000 → 0, opacity 1 — the
       arc draws from its origin dot to the next.
     • Trailing fade (next ~1.5s): opacity 1 → 0 while the next arc draws.
     • Quiet: opacity 0, ready to snap-reset and start again.
   The active word + callout track the arc that is currently drawing.
*/

.loop-ring {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  /* Allow the pulse rings to bleed past the viewBox edges (the top dot
     sits right at the SVG boundary, so the pulse would be clipped). */
  overflow: visible;
}

.loop-ring .loop-ring-track {
  /* Track + glows en --yellow-5 vía color-mix — antes usaban el ámbar
     legacy #F8AC19 (paleta Meteor, fuera del sistema) y convivían dos
     amarillos distintos en el mismo diagrama. */
  stroke: color-mix(in srgb, var(--yellow-5) 18%, transparent);
}

/* Arcs are now JS-controlled (script.js drives stroke-dashoffset + opacity
   so the line can be redirected on hover or restarted on viewport entry).
   Transitions defined here so JS-set values animate smoothly. */
.loop-arc {
  fill: none;
  stroke: var(--yellow-5);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-dasharray: 1000;
  stroke-dashoffset: 1000;
  filter: drop-shadow(0 0 6px color-mix(in srgb, var(--yellow-5) 35%, transparent));
  opacity: 0;
  /* Smooth ease-in-out so the line eases into motion at the start,
     glides through the middle, and settles into the destination dot
     at the end — pairs with the matching word + callout fades. */
  transition: stroke-dashoffset var(--dur-cinema) var(--ease-cinematic),
              opacity var(--dur-glide) var(--ease-out);
}

/* Station dots — always full size, always full yellow. They simply gain a
   stronger glow when "active" (i.e. when the line is parked there). */
.loop-stop {
  fill: var(--yellow-5);
  cursor: pointer;
  pointer-events: auto;
  transition: filter var(--dur-instant) var(--ease-out);
  filter: drop-shadow(0 0 4px color-mix(in srgb, var(--yellow-5) 45%, transparent));
}

.loop-stop.is-active,
.loop-stop:hover {
  filter: drop-shadow(0 0 12px color-mix(in srgb, var(--yellow-5) 85%, transparent));
}

/* GPS-style pulse rings — a single one-shot animation triggered by JS via
   .is-pulsing the moment the line lands on a dot. */
.loop-pulse {
  fill: none;
  stroke: var(--yellow-5);
  stroke-width: 1;
  opacity: 0;
  transform-origin: center;
  transform-box: fill-box;
  pointer-events: none;
}

.loop-pulse.is-pulsing {
  animation: loopPulse var(--dur-glide) var(--ease-soft) 1;
}

@keyframes loopPulse {
  0%   { opacity: 0.45; transform: scale(1); }
  100% { opacity: 0;    transform: scale(2.4); }
}

.loop-stack {
  position: absolute;
  inset: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: clamp(var(--text-heading-lg), 5.4vw, var(--text-display-lg));
  line-height: 1;
  letter-spacing: -0.03em;
  color: color-mix(in srgb, var(--yellow-5) 22%, transparent);
  text-align: center;
  gap: 0.15em;
  pointer-events: none;
}

/* The word colour fades over the FULL line transit (1100ms) with the
   same ease-in-out so the highlight glides cleanly between stations. */
.loop-stack-line {
  transition: color var(--dur-cinema) var(--ease-cinematic);
}

.loop-stack-line.is-active {
  color: var(--yellow-5);
}

/* Callouts — appear under each dot, with a translucent backdrop so the text
   stays readable when it overlaps the dashed circle. */
.loop-callout {
  position: absolute;
  width: max-content;
  max-width: 24ch;
  font-family: var(--font-mono);
  font-size: var(--text-body-md);
  font-weight: 400;
  letter-spacing: 0.01em;
  line-height: 1.5;
  color: var(--gray-white);
  text-align: center;
  pointer-events: none;
  padding: 10px 14px;
  border-radius: var(--radius-s);
  background: rgba(8, 10, 16, 0.82);
  backdrop-filter: var(--glass-filter-strong);
  -webkit-backdrop-filter: var(--glass-filter-strong);
  border: 1px solid rgba(255, 255, 255, 0.05);
  opacity: 0;
  transform: translate(-50%, 8px);
  /* Same 1100ms ease-in-out as the arc + word — the source callout
     fades out and the destination fades in over the whole line transit. */
  transition: opacity var(--dur-cinema) var(--ease-cinematic),
              transform var(--dur-cinema) var(--ease-cinematic);
}

.loop-callout.is-active {
  opacity: 1;
  transform: translate(-50%, 0);
}

/* Anchor each callout below its station dot. Plan bottom-right, Shoot
   bottom-left so the loop traverses clockwise. */
.loop-callout--imagine { left: 50%; top: 11%; }
.loop-callout--plan    { left: 89%; top: 79%; }
.loop-callout--shoot   { left: 11%; top: 79%; }

@media (max-width: 1024px) {
  .loop--circle .loop-stage { grid-template-columns: 1fr; }
  .loop-diagram { max-width: 420px; margin: 0 auto; }

  /* Centred header block on mobile: title, subtitle, rule, body all
     align to the optical centre. The CTAs sit centred beneath. */
  .loop--circle .loop-copy {
    text-align: center;
  }
  .loop--circle .loop-copy .section-title,
  .loop--circle .loop-copy .section-subtitle,
  .loop--circle .loop-copy .pitch-body {
    text-align: center;
  }
  .loop--circle .loop-copy .pitch-body {
    margin-left: auto;
    margin-right: auto;
  }
  .loop--circle .loop-copy .section-rule {
    margin-left: auto;
    margin-right: auto;
  }
  .loop--circle .loop-copy .loop-cta {
    justify-content: center;
  }

  /* Tooltips (callouts) · en el diagrama pequeño de mobile las posiciones de
     desktop se salían del marco o pisaban el stack central (Imagine/Plan/
     Shoot). Reposicionamos:
       · imagine → abre hacia ARRIBA de su punto (no tapa el stack).
       · plan / shoot → anclados al borde derecho / izquierdo del diagrama
         para que el texto quepa entero (antes iban centrados en 89%/11% y
         la mitad se salía). */
  .loop-callout { max-width: 20ch; font-size: var(--text-body-sm); }

  .loop-callout--imagine {
    left: 50%; top: auto; bottom: 95%;
    transform: translate(-50%, -8px);
  }
  .loop-callout--imagine.is-active { transform: translate(-50%, 0); }

  .loop-callout--plan {
    left: auto; right: 1%; top: 80%;
    transform: translate(0, 8px);
  }
  .loop-callout--plan.is-active { transform: translate(0, 0); }

  .loop-callout--shoot {
    left: 1%; right: auto; top: 80%;
    transform: translate(0, 8px);
  }
  .loop-callout--shoot.is-active { transform: translate(0, 0); }
}

/* (Hairline dividers removed — seam differentiation comes from the
   adjacent sections having distinct base tones and vignettes.) */

/* ────────────────────────────────────────────────────────────────────────
   STATEMENT variants (V1 diptych, V2 frame, V3 trio)
   Shared frame style for all photo elements.
   ──────────────────────────────────────────────────────────────────────── */
.statement-frame {
  position: relative;
  margin: 0;
  overflow: hidden;
  border-radius: var(--radius-s);
  border: 1px solid rgba(255, 255, 255, 0.10);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.06),
    inset 0 0 100px 10px rgba(0, 0, 0, 0.55),
    0 30px 60px -20px rgba(0, 0, 0, 0.7);
  background: var(--gray-11);
}
.statement-frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  filter: brightness(0.9) contrast(1.05);
}

/* ── Epic cinematic quote — two portrait frames flanking the statement ─── */
/* Solid black surface. Atmospheric halo via `.has-vignette` utility
   (added in the markup). Renamed mayo 2026 from `.statement-slide--diptych`
   for clarity — it's not a generic statement, it's the cinematic quote
   block with two flanking portraits. */
.epic-cinematic-quote {
  background: var(--bg-bold);
  padding: var(--section-pad-y-md) 0;
}
.epic-cinematic-quote__layout {
  max-width: var(--max-wide);
  margin: 0 auto;
  /* Padding horizontal canónico (= .container · var(--gutter)). */
  padding: 0 var(--gutter);
  display: grid;
  grid-template-columns: 1fr clamp(260px, 30vw, 420px) 1fr;
  gap: clamp(32px, 5vw, 80px);
  align-items: center;
}
.statement-frame--left,
.statement-frame--right {
  aspect-ratio: 3 / 4;
  width: 100%;
}
.statement-headline--center {
  text-align: center;
  font-size: clamp(var(--text-heading-md), 3.6vw, var(--text-heading-xl));
  line-height: 1.1;
  margin: 0;
}
.statement-headline--center .statement-line {
  display: block;
}

@media (max-width: 1024px) {
  .epic-cinematic-quote__layout { grid-template-columns: 1fr; }
  .statement-frame--left, .statement-frame--right { max-width: 320px; margin: 0 auto; }
}

/* ── V2: Single portrait frame + caption beside ──────────────────────── */
.statement-slide--frame {
  background: var(--gradient-strong);
  padding: var(--section-pad-y-lg) 0;
}
.statement-frame-stage {
  max-width: 1180px;
  margin: 0 auto;
  /* Padding horizontal canónico (= .container · var(--gutter)). */
  padding: 0 var(--gutter);
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1fr);
  gap: clamp(40px, 6vw, 96px);
  align-items: center;
}
.statement-frame--portrait {
  aspect-ratio: 3 / 4;
  width: 100%;
  max-width: 480px;
  margin: 0 auto;
}
.statement-caption {
  max-width: 30ch;
}
.statement-caption-eyebrow {
  font-family: var(--font-mono);
  font-size: var(--text-body-sm);
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--content-text-subtitle);
  margin: 0 0 1.5rem;
}
.statement-headline--side {
  font-size: clamp(var(--text-heading-md), 3.4vw, var(--text-heading-xl));
  line-height: 1.1;
  text-align: left;
  margin: 0;
}
.statement-headline--side .statement-line { display: block; }

@media (max-width: 1024px) {
  .statement-frame-stage { grid-template-columns: 1fr; text-align: center; }
  .statement-caption { margin: 0 auto; }
  .statement-headline--side { text-align: center; }
}

/* `.statement-slide--trio` y descendientes retirados 2026-05-13 — no
   se usan en HTML (la variante V3 con trío de thumbnails fue una
   propuesta descartada en favor de --diptych y --frame). */

/* ────────────────────────────────────────────────────────────────────────
   STATEMENT — Cinematic letterbox variant (V4)
   Pure black field, 2.39:1 cinemascope frame with thin warm edge,
   slow Ken Burns zoom, claqueta-style kicker + mono film credits.
   ──────────────────────────────────────────────────────────────────────── */
.statement-slide--cinema {
  background: var(--gray-black);
  padding: var(--section-pad-y-lg) 0;
  position: relative;
  /* Isolate stacking context so the body::after grain overlay does not
     blend on top of the brand logo and tint its flat fills. */
  isolation: isolate;
}

.cinema-logo,
.nav-logo,
.statement-logo,
.footer-logo {
  /* Logos must always render in their canonical flat colours. The global
     body::after grain overlay sits at --z-grain (9999) with mix-blend-mode:
     overlay, so logos lift one step above it to keep their fills pristine. */
  position: relative;
  z-index: calc(var(--z-grain) + 1);
  isolation: isolate;
  mix-blend-mode: normal;
}

/* Letterbox bars top + bottom for that wide-screen cinema feel */
.statement-slide--cinema::before,
.statement-slide--cinema::after {
  content: "";
  position: absolute;
  left: 0; right: 0;
  height: 28px;
  background: var(--gray-black);
  z-index: 2;
  pointer-events: none;
}
.statement-slide--cinema::before { top: 0; box-shadow: 0 1px 0 rgba(255,255,255,0.05); }
.statement-slide--cinema::after  { bottom: 0; box-shadow: 0 -1px 0 rgba(255,255,255,0.05); }

.cinema-stage {
  max-width: var(--max-wide);
  margin: 0 auto;
  /* Padding horizontal canónico (= .container · var(--gutter)). */
  padding: 0 var(--gutter);
  display: flex;
  flex-direction: column;
  align-items: center;
  /* Default gap = frame → logo (larger) */
  gap: clamp(64px, 8vw, 112px);
}

/* Tighter gap between the headline and the logo directly below */
.statement-headline--cinema + .cinema-logo {
  margin-top: clamp(-3.25rem, -4vw, -2.25rem);
}

/* ── Staggered fade-in: frame → headline → logo ─────────────────────── */
.statement-slide--cinema .cinema-frame,
.statement-slide--cinema .cinema-logo,
.statement-slide--cinema .statement-headline--cinema {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity var(--dur-glide) var(--ease-soft),
              transform var(--dur-glide) var(--ease-soft);
}
.statement-slide--cinema.is-visible .cinema-frame {
  opacity: 1; transform: none;
  transition-delay: 0ms;
}
.statement-slide--cinema.is-visible .statement-headline--cinema {
  opacity: 1; transform: none;
  transition-delay: 380ms;
}
.statement-slide--cinema.is-visible .cinema-logo {
  opacity: 1; transform: none;
  transition-delay: 580ms;
}
@media (prefers-reduced-motion: reduce) {
  .statement-slide--cinema .cinema-frame,
  .statement-slide--cinema .cinema-logo,
  .statement-slide--cinema .statement-headline--cinema {
    opacity: 1 !important; transform: none !important; transition: none !important;
  }
}

/* Logo sits above the headline as a "studio mark" before the title card */
.cinema-logo {
  display: inline-flex;
}
.cinema-logo svg { display: block; }

/* Timecode overlay — top-right corner of the cinema frame, no chip
   background so it reads like a discreet film burn-in. */
.cinema-timecode {
  position: absolute;
  top: clamp(14px, 1.6vw, 22px);
  right: clamp(14px, 1.6vw, 22px);
  font-family: var(--font-mono);
  font-size: var(--text-body-sm);
  letter-spacing: 0.12em;
  color: rgba(255, 255, 255, 0.75);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.65);
  z-index: 3;
  pointer-events: none;
}

.cinema-frame {
  position: relative;
  width: 100%;
  aspect-ratio: 2.39 / 1;
  margin: 0;
  overflow: hidden;
  /* Match the rest of the design system (Captured Plans slider uses the
     same scale of radius). */
  border-radius: var(--radius-m);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.10),
    inset 0 0 120px 20px rgba(0, 0, 0, 0.55),
    0 30px 80px -20px rgba(0, 0, 0, 0.85);
  /* Imagen de fondo COVER (misma que el póster) · llena el frame siempre,
     incluso antes de que el vídeo cargue/reproduzca. Sustituye al póster
     nativo del <video> (retirado), que en móvil se letterboxeaba dejando
     franjas negras arriba/abajo. */
  background: var(--gray-11) url('assets/hero-wide.webp') center / cover no-repeat;
}

.cinema-video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  filter: brightness(0.85) contrast(1.06) saturate(0.95);
}

.statement-headline--cinema {
  text-align: center;
  /* Bigger for more cinematic weight — matches the display-lg ramp used by
     other statement-slide variants. */
  font-size: clamp(var(--text-heading-lg), 5vw, var(--text-display-lg));
  line-height: 0.95;
  letter-spacing: -0.03em;
  margin: 0;
  max-width: 22ch;
}
.statement-headline--cinema .statement-line { display: block; }
.statement-headline--cinema .statement-line + .statement-line { margin-top: 0.3rem; }

/* ── Mobile/tablet (≤1024) · vídeo a FULL-BLEED con overlay ────────────────
   Reescrito BLINDADO tras franjas persistentes en iOS Y Android:
   · `.statement-slide.statement-slide--cinema` (0,2,0) vence a `.statement-slide`
     (flex+center) sin depender del orden de cascada → display:block.
   · El STAGE pasa a `position: static` → el contenedor del frame (absolute)
     deja de ser el stage (que se encogía) y pasa a ser la SECCIÓN. El frame
     llena la sección entera vía inset:0.
   · `min-height: 100dvh` (viewport real con barra del navegador) con
     fallbacks 100svh/100vh.
   · Vídeo `inset:0 + object-fit:cover` (sin height:% que rompía en iOS).
   · Frame excluido del reveal (opacity/transform) que dejaba 14px.
   · SOLO móvil (≤720): en TABLET el <video> de iOS no se estira a pantalla
     completa con NINGUNA técnica (inset:0 / height:% / height:dvh / min-height
     — el emulador sí, el iPad real no; deja franjas). Decisión de Irene 2026-08:
     en tablet usar el DISEÑO DE DESKTOP (vídeo enmarcado como composición
     cinema), no el full-bleed. Por eso este bloque baja de ≤1024 a ≤720. */
@media (max-width: 720px) {
  .statement-slide.statement-slide--cinema {
    display: block;
    position: relative;
    padding: 0;
    min-height: 100vh;
    min-height: 100svh;
    min-height: 100dvh;
    overflow: hidden;
  }
  .statement-slide--cinema::before,
  .statement-slide--cinema::after { display: none; }
  .cinema-timecode { display: none; }

  /* Stage STATIC · solo centra frase + logo · no es el contenedor del frame. */
  .statement-slide--cinema .cinema-stage {
    position: static;
    max-width: none;
    width: 100%;
    min-height: 100vh;
    min-height: 100svh;
    min-height: 100dvh;
    padding: clamp(80px, 14vh, 140px) 24px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: clamp(20px, 4vh, 36px);
  }

  /* Frame = fondo del vídeo · llena la SECCIÓN (inset:0) · sin reveal ·
     overflow hidden para recortar el vídeo escalado (cover manual). */
  .statement-slide--cinema .cinema-frame {
    position: absolute;
    inset: 0;
    aspect-ratio: auto;
    border-radius: 0;
    box-shadow: none;
    overflow: hidden;
    z-index: 0;
    opacity: 1;
    transform: none;
    transition: none;
  }
  /* COVER · caja fija 100%×100% + object-fit:cover (estándar iOS 12+).
     OJO: la técnica anterior (width/height:auto + min-width/min-height:100%
     + translate) fallaba en TABLET cuando el vídeo debía ESCALAR HACIA ARRIBA
     (iPad vertical 1024×1366: la caja crecía a 1366 pero el contenido se
     quedaba en 1080 → letterbox negro dentro de la caja). Con caja fija y
     object-fit:cover el contenido se recorta para llenar, sin franjas. El
     background del frame (cover) sigue como fallback antes de cargar el vídeo. */
  .statement-slide--cinema .cinema-video {
    /* iOS NO estira un <video> (elemento reemplazado) con inset:0 ni height:%
       → se quedaba a su alto intrínseco (1080) y dejaba franjas negras arriba/
       abajo (el emulador SÍ lo estira, por eso no se reproducía). Alto explícito
       en dvh (unidad de viewport que iOS SÍ resuelve) + width:auto → el elemento
       es 16:9, el contenido lo llena SIN letterbox y desborda a los lados
       (el frame overflow:hidden lo recorta). No depende de object-fit. */
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    height: 100vh;
    height: 100svh;
    height: 100dvh;
    width: auto;
    max-width: none;
  }
  .statement-slide--cinema .cinema-frame::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg,
      rgba(0, 0, 0, 0.45) 0%,
      rgba(0, 0, 0, 0.55) 55%,
      rgba(0, 0, 0, 0.78) 100%);
    z-index: 1;
    pointer-events: none;
  }
  .cinema-stage .statement-headline--cinema,
  .cinema-stage .cinema-logo {
    position: relative;
    z-index: 2;
  }
  .statement-headline--cinema + .cinema-logo { margin-top: 0; }
}



/* ────────────────────────────────────────────────────────────────────────
   EXPERIENCES — community diary
   1) Header in two columns (copy left · animated stats right)
   2) Social-proof variant A: photo (left) + quote card (right) with dots
   3) Social-proof variant B: full-bleed photo with quote overlaid (gradient
      ensures legibility)
   ──────────────────────────────────────────────────────────────────────── */
.exp-section {
  position: relative;
  /* Negro pleno (--bg-bold) en desktop y móvil · decisión 2026-07. */
  background: var(--bg-bold);
  padding: var(--section-pad-y-md) 0;
  overflow: hidden;
}

.exp-stage {
  max-width: var(--max-wide);
  margin: 0 auto;
  /* Padding horizontal canónico (= .container · var(--gutter)). */
  padding: 0 var(--gutter);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(56px, 7vw, 96px);
}

/* ── Header: 2 columns (copy · stats) ────────────────────────────────── */
.exp-header {
  width: 100%;
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  gap: clamp(40px, 5vw, 80px);
  align-items: center;
}

.exp-header-copy .section-title {
  text-align: left;
  margin-bottom: 1.25rem;
}
.exp-header-copy .section-subtitle {
  text-align: left;
  font-size: var(--text-editorial-subtitle);
  line-height: 1.125;
  font-weight: 300;
  max-width: none;
  margin: 0 0 2rem;
}
.exp-header-copy .section-rule { margin: 0 0 2rem; }
.exp-header-copy .pitch-body {
  text-align: left;
  font-size: var(--text-editorial-body);
  line-height: 1.4;
  font-weight: 300;
  color: var(--content-text-subtitle);
  max-width: 46ch;
  margin: 0;
}

.exp-stats {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(20px, 3vw, 40px) clamp(16px, 3vw, 32px);
}
.exp-stat {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.4rem;
}
.exp-stat-value {
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: clamp(var(--text-heading-lg), 4.5vw, var(--text-display-lg));
  line-height: 1;
  letter-spacing: -0.04em;
  color: var(--gray-white);
  font-variant-numeric: tabular-nums;
}
.exp-stat-label {
  font-family: var(--font-mono);
  font-size: var(--text-body-sm);
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--yellow-5);
}

@media (max-width: 1024px) {
  .exp-header { grid-template-columns: 1fr; }

  /* Centred header block on mobile: title, subtitle, rule, body all
     align to the optical centre. Stats also re-centre as a 2-col grid. */
  .exp-header-copy {
    text-align: center;
  }
  .exp-header-copy .section-title,
  .exp-header-copy .section-subtitle,
  .exp-header-copy .pitch-body {
    text-align: center;
  }
  .exp-header-copy .pitch-body {
    margin-left: auto;
    margin-right: auto;
  }
  .exp-header-copy .section-rule {
    margin-left: auto;
    margin-right: auto;
  }
  .exp-stats {
    justify-items: center;
    text-align: center;
  }
  .exp-stat { align-items: center; }
}


/* ── CTAs ─ (visuals from shared .cta-row in common.css.) ────────────── */

/* ── OPTION 1: magazine diptych with 2-level navigation ──────────────────
   Container holds multiple stories; only one is visible at a time.
   Photo column on the left has a crossfade stack + dot pagination;
   text column on the right is always fully readable on solid dark. */
.exp-stories {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: clamp(20px, 2.5vw, 36px);
}
.exp-stories-track {
  position: relative;
  display: grid;
}
.exp-story {
  grid-column: 1;
  grid-row: 1;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity var(--dur-glide) var(--ease-out),
              visibility 0s linear var(--dur-glide);
}
.exp-story.is-active {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity var(--dur-glide) var(--ease-out),
              visibility 0s linear 0s;
}

.exp-proof--diptych {
  width: 100%;
  margin: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  border-radius: var(--radius-m);
  overflow: hidden;
  /* Shadow projects upward (negative Y) toward the avatar nav above. */
  box-shadow: var(--shadow-stage-up);
}
.exp-dip-photo {
  position: relative;
  overflow: hidden;
  /* Fixed aspect drives the diptych row height — the right column
     (quote) matches via the grid, so the container does NOT grow
     across breakpoints regardless of quote length.
     3:2 matches the dominant landscape photos in the gallery
     (4 of the 6 carousel images sit at ~1.4–1.6). Portrait photos
     unavoidably crop in any landscape-oriented frame. */
  aspect-ratio: 3 / 2;
}
.exp-dip-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Photo stack: multiple photos crossfade in the same frame. */
.exp-photo-stack {
  position: absolute;
  inset: 0;
}
.exp-photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity var(--dur-glide) var(--ease-out);
}
.exp-photo.is-active { opacity: 1; }

/* (Scrim inferior retirado · existía solo para dar legibilidad al pager
   sobre la foto · ahora el pager vive debajo del componente, fuera de la
   imagen, así que ya no hace falta.) */
/* (Photo credit shares the .photo-credit component with the hero —
   see common.css. The .photo-credit--top modifier anchors it
   top-right inside the Experiences gallery.) */

/* Pager · FUERA de la imagen · centrado DEBAJO del componente (desktop +
   mobile). Visuales del componente .pager (--md) en common.css. */
.exp-photo-pager {
  justify-content: center;
  margin-top: clamp(12px, 2vw, 20px);
  pointer-events: auto;
}
.exp-dip-text {
  /* Lighter than the deep bg of .exp-section so the diptych reads as
     a card sitting on top of the section, with the same blue-tinted
     cinematic family as the surrounding bands. */
  background: var(--gradient-subtle);
  /* Padding tuned so the quote + author credit fit inside the
     photo-driven 3:2 row height — keeps the diptych as tall as the
     images themselves and prevents the empty band below the photo. */
  padding: clamp(28px, 4vw, 56px);
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 1.25rem;
  margin: 0;
  border-left: 1px solid rgba(255, 255, 255, 0.06);
}
.exp-dip-quote {
  margin: 0;
  font-family: var(--font-sans);
  font-weight: 300;
  font-style: normal;  /* override del <blockquote> default (regla 4) */
  /* Sized so the quote + author credit always fit inside the photo's
     3:2 row height across viewports (1200 → 1920+). Capping at fs-h2
     prevents wide-viewport overflow that would leave a black gap below
     the photo column. */
  font-size: clamp(var(--text-heading-sm), 1.8vw, var(--text-heading-lg));
  line-height: 1.2;
  letter-spacing: -0.02em;
  color: var(--gray-white);
}
/* (.exp-dip-cite / .exp-dip-avatar / .exp-dip-author absorbed into
   .author-credit / .author-credit__avatar / .author-credit__name in
   common.css. Nothing else needed here for Experiences cite.) */

/* ── Outer nav: prev arrow + centred avatar strip + next arrow,
   placed ABOVE the diptych in normal flow (outside the carousel).
   Active chip expands inline to reveal the author name. 10+ entries
   scroll horizontally inside the strip without breaking the row. */
/* (Outer testimonial nav removed — navigation now lives inside the
   photo gallery via .exp-photo-nav. The author + avatar live under
   the quote on the right column.) */

/* Stack the diptych to a single column at tablet too — at 2-column
   widths between 721 and ~1023, the photo's fixed aspect was
   leaving empty black space under the photo whenever the quote text
   was taller than that ratio allowed. Single-column avoids that. */
/* La diptych mantiene las 2 columnas (foto | texto) en tablet vertical (768),
   igual que desktop (petición Irene). Solo apila en móvil (≤720). */
@media (max-width: 720px) {
  .exp-proof--diptych {
    grid-template-columns: 1fr;
  }
  /* Shorter, wider photo when stacked — 16:10 reads as a "scene
     strip" rather than a portrait-style 4:5 column, and the user
     reaches the quote without a long scroll. */
  .exp-dip-photo { aspect-ratio: 16 / 10; }
}

@media (max-width: 720px) {
  /* Quote is much smaller on mobile — clamp would otherwise floor at
     fs-h3 (32px) which is overwhelming inside a narrow column. */
  .exp-dip-quote {
    font-size: var(--text-heading-sm);
    line-height: 1.25;
  }
  .exp-dip-text {
    padding: clamp(28px, 6vw, 40px);
    gap: 1.5rem;
  }
}
