/* common.css — design system tokens, shared components (buttons, chips, sections, helpers) */

/* Public Sans se carga desde el <head> de cada página junto a JetBrains
   Mono (link combinado + preconnect, QA #56). El @import que vivía aquí
   era una cadena en serie (HTML → common.css → CSS de Google → fuente)
   que retrasaba el primer render ~300-500ms en 4G. */

:root {

  /* ──────────────────────────────────────────────────────────────────
     PRIMITIVES — full color names (2026-04 DS-Web rename)
     · Each ramp is 9 steps. Step 5 is the brand canonical for that color.
     · Short aliases (--g-1, --y-5, etc.) live below for transitional
       compatibility — same value, shorter handle.
     ────────────────────────────────────────────────────────────────── */

  /* Gray — photographic neutral · 13 steps (white + 11 + black) */
  --gray-white: #FFFFFF;
  --gray-1:     #F2F2F2;
  --gray-2:     #CCCCCC;
  --gray-3:     #B3B3B3;
  --gray-4:     #999999;
  --gray-5:     #808080;
  --gray-6:     #666666;
  --gray-7:     #3A3A3A;
  --gray-8:     #282828;
  --gray-9:     #1F1F1F;
  --gray-10:    #141414;
  --gray-11:    #0A0A0A;
  --gray-black: #000000;

  /* Yellow — brand + action · step 5 is the logo yellow #FED925 */
  --yellow-1: #FFF7D3;
  --yellow-2: #FFF0A8;
  --yellow-3: #FEE87C;
  --yellow-4: #FEDD3B;
  --yellow-5: #FED925;
  --yellow-6: #CBAE1E;
  --yellow-7: #988216;
  --yellow-8: #66570F;
  --yellow-9: #332B07;

  /* Red — alert · step 5 is the logo orange #FF4D00 */
  --red-1: #FFDBCC;
  --red-2: #FFB899;
  --red-3: #FF9466;
  --red-4: #FF7133;
  --red-5: #FF4D00;
  --red-6: #CC3E00;
  --red-7: #992E00;
  --red-8: #661F00;
  --red-9: #330F00;

  /* Lightblue — text links + interactive accents · step 6 is canonical */
  --lightblue-1: #DBF3F9;
  --lightblue-2: #B7E6F3;
  --lightblue-3: #92DAEC;
  --lightblue-4: #6ECDE6;
  --lightblue-5: #4AC1E0;
  --lightblue-6: #3B9AB3;
  --lightblue-7: #2C7486;
  --lightblue-8: #1E4D5A;
  --lightblue-9: #0F272D;

  /* Blue — logo only · step 5 is the logo blue #2689F8 (never used in UI) */
  --blue-1: #D4E7FE;
  --blue-2: #A8D0FC;
  --blue-3: #7DB8FB;
  --blue-4: #51A1F9;
  --blue-5: #2689F8;
  --blue-6: #1E6EC6;
  --blue-7: #175295;
  --blue-8: #0F3763;
  --blue-9: #081B32;

  /* Orange — warm accent · reserved, rarely surfaced */
  --orange-1: #FFE4D0;
  --orange-2: #FFC9A1;
  --orange-3: #FFAD73;
  --orange-4: #FF9244;
  --orange-5: #FF7715;
  --orange-6: #CC5F11;
  --orange-7: #99470D;
  --orange-8: #663008;
  --orange-9: #331804;

  /* Green — success · reserved for form/checkout flows */
  --green-1: #CDF3E1;
  --green-2: #9BE6C2;
  --green-3: #6ADAA4;
  --green-4: #38CD85;
  --green-5: #06C167;
  --green-6: #059A52;
  --green-7: #04743E;
  --green-8: #024D29;
  --green-9: #012715;

  /* Short aliases (--g-/--y-/--r-/--lb-/--b-/--o-/--gr-) RETIRED 2026-05.
     Cada consumer migrado al nombre completo (--gray-/--yellow-/--red-/
     --lightblue-/--blue-/--orange-/--green-). Si algo todavía referencia
     un alias corto, fallará en silencio — re-añadir solo si hay razón. */

  /* ── Semantic — Backgrounds ──
     Trimmed 2026-05 to only the slots with active consumers. Retired:
     --bg-neutral-subtle/-soft/-strong, --bg-primary-weak, --bg-tertiary-soft.
     Re-add a slot when a real component needs it (don't preempt). */
  --bg-neutral-default:   var(--gray-10);   /* .section-dark · cards · containers */
  --bg-neutral-bold:      var(--gray-11);   /* page canvas (body) */
  --bg-primary-default:   var(--yellow-5);    /* brand fill — yellow */
  --bg-primary-strong:    var(--yellow-6);    /* .btn-primary:active */
  --bg-tertiary-default:  var(--gray-8);    /* tertiary surface (used in 1 component) */
  --bg-tertiary-strong:   var(--gray-8);
  --bg-tertiary-bold:     var(--gray-9);

  /* ── Semantic — Text ──
     Note: `--content-text-accent` (cyan) was retired 2026-04. Cyan is for
     LINKS only — not for highlighting text. To emphasise a word inside a
     paragraph use yellow (--yellow-5) or white (--gray-white). */
  --content-text-default:          var(--gray-white);
  /* Bumped from g-4 (#999) to g-3 (#B3B3B3) on 2026-05 — same role,
     better contrast on dark surfaces (~10:1 vs ~7.4:1). */
  --content-text-default-weak:     var(--gray-3);
  --content-text-default-inverted: var(--gray-9);
  --content-text-label:            var(--gray-3);
  --content-text-label-weak:       var(--gray-4);
  --content-text-subtitle:         var(--gray-2);
  --content-text-highlight:        var(--yellow-5);    /* yellow highlight inside body copy */
  --content-text-brandbook-label:  var(--gray-3);
  --content-hint:                  var(--gray-3);

  /* ── Semantic — Links ── */
  /* Links — yellow + underlined (2026-05). Cyan retired as link colour;
     yellow now owns both Action and Interactive text. */
  --content-link-default:  var(--yellow-5);
  --content-link-hover:    var(--yellow-4);
  --content-link-pressed:  var(--yellow-6);
  --content-link-disabled: var(--yellow-8);

  /* ── Semantic — Borders ── */
  /* `--border-neutral-default` (opaque --g-6) retired 2026-04 — only had
     1 usage. The 50%-transparent --border-neutral-soft below is the
     canonical hairline used across the system. */
  /* White-on-dark hairline at 16% opacity. Bumped from 12% — the lower
     value rendered visibly thinner at rounded corners on some browsers
     because alpha-blending compounds at the antialiased edge. 16% reads
     as a clean, even 1px line all the way around. */
  --border-neutral-soft:     color-mix(in srgb, var(--gray-white) 16%, transparent);
  --border-secondary-accent: var(--yellow-5);
  /* `--border-primary-accent` (cyan) retired 2026-04 — never used in
     any real component. Yellow (--border-secondary-accent) is the only
     accent border the system needs. */
  /* `--border-tertiary-accent` retired 2026-04 — its single usage
     (.info-tip border) migrated to --border-neutral-soft. */

  /* ── Semantic — Brand ── */
  --brand-yellow: var(--yellow-5);
  --brand-red:    var(--red-5);
  --brand-blue:   var(--blue-5);
  --brand-black:  var(--gray-9);
  --brand-white:  var(--gray-white);

  /* ── Semantic — Aliases (signal/success/warning/error/info) ── */
  --signal-default:  var(--red-5);
  --signal-hover:    var(--red-4);
  --signal-pressed:  var(--red-6);
  --signal-on:       var(--gray-white);
  --success-default: var(--green-5);
  --warning-default: var(--yellow-5);
  --error-default:   var(--red-5);
  --info-default:    var(--blue-5);

  /* ── Semantic — Magic hours (fases de luz) ──
     Colores de marca de PhotoPills para las fases de luz del día. NO son
     roles de UI (acción/alerta/etc.): son una PALETA DE DATO. Cualquier
     visualización o pieza que represente Day / Golden hour / Blue hour /
     Night DEBE usar estos tokens — no re-elegir a ojo. Mapean 1:1 a
     primitivas existentes. (Decisión de Irene · 2026-07-22.) */
  --lightphase-day:    var(--lightblue-3);  /* Day light   · #92DAEC */
  --lightphase-golden: var(--red-5);        /* Golden hour · #FF4D00 */
  --lightphase-blue:   var(--blue-5);       /* Blue hour   · #2689F8 */
  --lightphase-night:  var(--gray-black);   /* Night       · #000000 */

  /* ──────────────────────────────────────────────────────────────────
     DESIGNER ALIASES (2026-04 · DS-Web rename)
     A friendlier vocabulary for design-time thinking. These are pure
     aliases — they layer on top of the primitives + semantic tokens
     above. Devs can use either; designers should reach for these.
     ──────────────────────────────────────────────────────────────────

     Naming rules:
     · `--color-<role>-<intensity>` for accents (action, link, alert)
     · Intensity scale: subtle → soft → default → strong → bold
     · `--bg-<surface>` for the tonal cascade of section backgrounds
     ────────────────────────────────────────────────────────────────── */

  /* Action — yellow ramp · covers BOTH primary CTAs and inline text links
     (unified 2026-05: yellow owns Action + Identity + Interactive text). */
  --color-action-subtle:  var(--yellow-2);
  --color-action-soft:    var(--yellow-3);
  --color-action-default: var(--yellow-5);   /* brand yellow ★ */
  --color-action-strong:  var(--yellow-6);
  --color-action-bold:    var(--yellow-7);

  /* `--color-link-*` retired 2026-05 — use `--color-action-*` instead.
     Links and CTAs share the same hue family in this system. */

  /* Alert — red ramp · errors, validation, attention */
  --color-alert-subtle:  var(--red-2);
  --color-alert-soft:    var(--red-3);
  --color-alert-default: var(--red-5);   /* brand alert ★ */
  --color-alert-strong:  var(--red-6);
  --color-alert-bold:    var(--red-7);

  /* ─────────────────────────────────────────────────────────────────
     SURFACE FAMILIES (2026-04 DS-Web rename)

     Three orthogonal layers compose any section's atmosphere:

     1. `--bg-*`        Solid backgrounds (no gradient).
     2. `--gradient-*`  Directional vertical fades (light top → dark
                        bottom). Each one creates a clear seam against
                        the next section.
     3. `--vignette-*`  Atmospheric overlays applied via ::before.
                        Don't change the base tone — only add character
                        (warm-right, cool-left, central glow, band…).

     A section = surface + (optional) vignette.
     ───────────────────────────────────────────────────────────────── */

  /* ── Backgrounds — solids ─────────────────────────────────────── */
  --bg-bold: var(--gray-black);   /* Solid #000 — anchor (footer, statements) */

  /* Light surface · off-white con tinte azul-gris sutil. Para sales
     letters largas y secciones de lectura sostenida (Overview, How It
     Works, Itinerary, FAQs). El tilt azul (B>G>R, +5 puntos sobre rojo)
     arma con los gradients dark del DS (blue tilt B>G>R) y evita el
     blanco puro #FFF que genera fatiga. Patrón validado en Linear,
     Figma marketing, Vercel docs. */
  --bg-light-default:                #F5F7FA;
  --content-text-on-light-default:   var(--gray-11);   /* near-black */
  --content-text-on-light-weak:      var(--gray-6);    /* medium gray */
  --border-on-light:                 rgba(10, 10, 10, 0.12);

  /* ── Gradients — directional vertical fades ───────────────────── */
  /* Each gradient ranges from a "light top" to a "dark bottom".
     Stacked sections produce a visible "lift" at every seam.
     All three share a clear blue tilt (B > G > R in every stop). */
  --gradient-subtle: linear-gradient(180deg, #25282e 0%, #16181e 100%);
                     /* range #25 → #16 — card on dark surface */
  --gradient-soft:   linear-gradient(180deg, #181c26 0%, #0c1018 100%);
                     /* range #18 → #0c — content band, blue-tinted, gentle delta */
  --gradient-strong: linear-gradient(180deg, #14161e 0%, #02030a 100%);
                     /* range #14 → #02 — deep band, near-black bottom */

  /* ── Vignettes — atmospheric overlay color (single, blue-gray) ──
     One vignette family with two intensities. Position is set by
     modifier classes (.has-vignette--right/--left/--top/--bottom)
     on the consumer element. See `.has-vignette` utility in common.css. */
  --vignette-soft:   rgba(95, 105, 128, 0.20);  /* atmospheric ambiental */
  --vignette-strong: rgba(95, 105, 128, 0.50);  /* character pronunciado */

  /* ── Scrims — legibility overlays over photography (2026-07 audit) ──
     Distintos de --gradient-* (fondos de sección) y de --vignette-*
     (carácter atmosférico): un scrim oscurece la foto para que el texto
     encima pase contraste AA. Se aplican en el ::after/overlay del media.
     · hero  → oscurece leve arriba (nav) + fuerte abajo (title block).
     · soft  → fade inferior medio, para captions/diptychs sobre foto.
     · strong→ cobertura completa creciente, para heroes con mucho copy. */
  --scrim-hero:         linear-gradient(180deg, rgba(0, 0, 0, 0.10) 0%, rgba(0, 0, 0, 0) 35%, rgba(0, 0, 0, 0.75) 100%);
  --scrim-photo-soft:   linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.25) 45%, rgba(0, 0, 0, 0.65) 100%);
  --scrim-photo-strong: linear-gradient(180deg, rgba(0, 0, 0, 0.30) 0%, rgba(0, 0, 0, 0.55) 55%, rgba(0, 0, 0, 0.82) 100%);

  /* `--gradient-default`, `--bg-subtle/-soft/-default/-strong/-elevated/
     -loop/-deep/-atmospheric/-pre-anchor/-anchor` were aliases retired
     2026-05 (zero consumers). Use `--gradient-subtle/-soft/-strong` and
     `--bg-bold/-neutral-bold/-neutral-default` directly. */

  /* ── Shadows ── */
  --shadow-md:           0 4px 16px color-mix(in srgb, var(--gray-black) 20%, transparent);
  --shadow-device-light: 0 50px 80px -20px color-mix(in srgb, var(--gray-black) 22%, transparent);
  --shadow-device-dark:  0 60px 100px -20px color-mix(in srgb, var(--gray-black) 65%, transparent);
  /* ── Typography ── */
  /* Font families (the only two used across the site) */
  --font-sans: 'Public Sans', -apple-system, BlinkMacSystemFont, 'SF Pro Display', sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, Monaco, monospace;
  /* `--font-brand` · solo para el wordmark "PhotoPills" (logo lockup).
     Gibson es la tipografía oficial del wordmark; cae a Public Sans si
     no está disponible. NO usar fuera del lockup — para todo lo demás,
     `--font-sans`. */
  --font-brand: Gibson, 'Public Sans', -apple-system, BlinkMacSystemFont, sans-serif;

  /* ──────────────────────────────────────────────────────────────────
     TEXT — typography scale (2026-04 DS-Web rename)
     · Prefix `--text-*` for everything readable.
     · Suffix tells the role (display/heading/body/mono) + size (xs–xl).
     · `--fs-*` shortnames RETIRED 2026-05 — every consumer migrated to `--text-*`.
     ────────────────────────────────────────────────────────────────── */

  /* Display — hero / statement */
  --text-display-xl: 96px;   /* hero h1 */
  --text-display-lg: 78px;   /* secondary display */
  --text-display-md: 64px;   /* tertiary display */

  /* Heading — section titles */
  --text-heading-xl: 56px;   /* big section title */
  --text-heading-lg: 40px;   /* default section title */
  --text-heading-md: 32px;   /* subheading */
  --text-heading-sm: 24px;   /* compact subheading */

  /* Body — editorial copy */
  --text-lead:    28px;      /* hero subtitle / lead paragraph */
  --text-body-lg: 22px;      /* large body */
  --text-body-md: 18px;      /* default body (md) — minimum legible for prose */
  --text-body-sm: 16px;      /* small body — still safe for reading */
  --text-body-xs: 14px;      /* legal / smallest body — captions, never paragraphs */

  /* Mono — metadata, technical labels */
  --text-mono-xs: 10px;      /* tiny mono — timer digits */
  --text-mono-sm: 12px;      /* photo credits, footer meta */
  --text-mono-md: 14px;      /* eyebrows */
  --text-mono-lg: 16px;      /* author credit, paginator */
  --text-mono-xl: 18px;      /* author name (avatar+autor) · mono destacado */

  /* Editorial fluid sizes — FUENTE ÚNICA del subtítulo/body editorial
     (section-header / editorial-stack / product-copy · patrón "mirror de la
     home"). Esta receta estaba copiada por todo el repo; ahora vive aquí.
     Cambiar el tamaño editorial = tocar solo estas 2 líneas. */
  --text-editorial-subtitle: clamp(var(--text-heading-sm), 3vw, var(--text-heading-md));
  --text-editorial-body:     clamp(var(--text-body-md), 1.7vw, var(--text-body-lg));

  /* Product hero title — tamaño del H1 "PhotoPills Premium Beta" (Pricing +
     Premium comparten el componente `.pricing-intro__title-v2`). Tokenizado
     (petición Irene 2026-08): tocar el tamaño del hero = estas 2 líneas.
     Desktop: display-md (64) → display-lg (78). Móvil: heading-xl (56) → 78. */
  --text-hero-title:    clamp(var(--text-display-md), 7vw, var(--text-display-lg));
  --text-hero-title-sm: clamp(var(--text-heading-xl), 8vw, var(--text-display-lg));

  /* Line-heights + tracking (shared across the scale) */
  --lh-display:       1.08;
  --lh-heading:       1.18;
  --lh-body:          1.47;
  --tracking-display: -0.022em;
  --tracking-heading: -0.018em;

  /* `--fs-*` aliases retired (mayo 2026). Every consumer migrated to the
     canonical `--text-*` tokens. If something still references --fs-...
     it'll fail loudly — re-add the alias only if there's a real reason. */

  /* ── Motion easings · canonical ramp (4 steps) ──
     `--ease` (legacy default) retired 2026-05; consumers migrated to
     `--ease-out` (UI default). */
  --ease-out:       cubic-bezier(0.4, 0, 0.2, 1);
  --ease-soft:      cubic-bezier(0.2, 0.8, 0.2, 1);
  --ease-cinematic: cubic-bezier(0.83, 0, 0.17, 1);
  --ease-reveal:    cubic-bezier(0.23, 0.98, 0.34, 0.99);
  /* `--dur-reveal` (800ms) was unified into `--dur-cinema` (1100ms) in
     mayo 2026 — both lived in the "long, intentional" bucket and the
     perceptual delta wasn't worth a separate token. Section .reveal entries
     now play at the same tempo as The Loop. */
  /* Legacy duration tokens (--dur-fast/normal/slow/hover) retired in
     2026-04 coherence pass. Use the canonical ramp below
     (--dur-instant/soft/glide/cinema). */

  /* ── DS · Avatar sizes ── */
  --avatar-sm: 32px;
  --avatar-md: 40px;       /* canonical author-credit avatar */
  --avatar-lg: 48px;

  /* ── DS · Section vertical padding ──
     Catálogo cerrado de 4 escalones. Padding SIEMPRE simétrico arriba/abajo;
     la única excepción documentada es el hero (xl) que admite asimetría
     justificada en su comentario CSS.
       sm  → módulos compactos (reservado)
       md  → editorial default — la mayoría de secciones
       lg  → statement / bandas con peso visual
       xl  → heroes (home, pricing), 100vh/svh */
  --section-pad-y-sm: clamp(48px, 6vw, 80px);
  --section-pad-y-md: clamp(64px, 8vw, 112px);
  --section-pad-y-lg: clamp(96px, 12vw, 180px);
  --section-pad-y-xl: clamp(120px, 22vh, 220px);

  /* `--bg-section-photographic/-loop/-deep/-elevated`, `--bg-final-cta`,
     `--bg-footer` — todos retirados 2026-05. Eran 6 gradients radial+linear
     custom para secciones de la homepage; sustituidos por las 3 bandas
     canónicas `--gradient-subtle/-soft/-strong` + viñetas opcionales vía
     `.has-vignette`. Cero consumers actuales. */

  /* ── DS · Breakpoints (4 canonical, mobile-first cascade) ──
     CSS uses literal values (custom properties don't work inside
     @media queries). These tokens are documentation references only. */
  --bp-xs: 480px;    /* compact phone — type micro-adjust */
  --bp-sm: 720px;    /* phone / portrait — full mobile layout */
  --bp-md: 1024px;   /* tablet / landscape — stack diptychs, hamburger nav */
  --bp-lg: 1200px;   /* small desktop max-width gate */

  /* ── DS · Radius extras
     `--radius-pill` retired 2026-04 → use `--radius-full` (same effect). */
  --radius-circle: 50%;     /* avatar, dot, icon button — geometrically distinct from --radius-full */

  /* ── DS · Shadows (3 elevations, 2026-04 simplification)
     `--shadow-card`, `--shadow-mockup`, `--shadow-popover` consolidated
     into 2 downward shadows (soft + strong). The upward `--shadow-stage`
     was renamed to `--shadow-stage-up` for explicitness. */
  --shadow-soft:     0 8px 24px rgba(0, 0, 0, 0.25),
                     inset 0 1px 0 rgba(255, 255, 255, 0.08);
  --shadow-strong:   0 16px 36px -12px rgba(0, 0, 0, 0.55);
  --shadow-stage-up: 0 -40px 90px -20px rgba(0, 0, 0, 0.85);

  /* ── Glow — halo de acción en yellow-5 (2026-07 audit) ──
     Receta compartida entre el Loop de la home y Capabilities de App.
     En HTML se aplica como box-shadow vía estos tokens; en SVG el mismo
     halo va como `filter: drop-shadow(0 0 Npx color-mix(in srgb,
     var(--yellow-5) N%, transparent))` porque drop-shadow no acepta un
     token de box-shadow. Mantener AMBAS recetas con los mismos valores. */
  --glow-action-soft:   0 0 4px color-mix(in srgb, var(--yellow-5) 45%, transparent);
  --glow-action-strong: 0 0 12px color-mix(in srgb, var(--yellow-5) 85%, transparent);

  /* ── Glass — receta backdrop-filter unificada (2026-07 audit) ──
     Dos intensidades cierran el catálogo: la canónica del chrome
     (.btn-ghost / .icon-btn) y la fuerte para paneles, barras de filtros
     y tooltips grandes. El blur del nav (20px/180%) queda como receta
     propia del site chrome, documentada en .nav. */
  --glass-filter:        blur(2.5px) saturate(120%);
  --glass-filter-strong: blur(12px) saturate(140%);

  /* ── Glass surfaces (tint) · 2026-08 ──
     El FILTRO ya está tokenizado arriba; esto tokeniza el FONDO translúcido
     del glass. Tres roles, uno por contexto:
       --glass-bg:        tinte claro sobre superficies OSCURAS (chrome:
                               btn-ghost, icon-btn) · va con --glass-filter.
       --glass-bg-panel:  oscuro casi opaco para paneles de contenido
                               (panel--glass) · va con --glass-filter-strong.
       --glass-bg-dark:   oscuro TRANSLÚCIDO sobre FOTO (deja ver la imagen,
                               p.ej. buscador del 404) · va con --glass-filter-strong. */
  --glass-bg:       rgba(255, 255, 255, 0.16);
  --glass-bg-panel: rgba(10, 13, 18, 0.82);
  --glass-bg-dark:  rgba(10, 13, 18, 0.42);

  /* Aliases — old names kept for transitional compat. */
  --shadow-card:    var(--shadow-soft);
  --shadow-mockup:  var(--shadow-strong);
  --shadow-popover: var(--shadow-strong);
  --shadow-stage:   var(--shadow-stage-up);

  /* ── DS · Z-index stack (canonical) ── */
  --z-base:    0;
  --z-overlay: 5;     /* photo credit, paginator overlay */
  --z-chip:    10;    /* chip strips above scrim */
  --z-modal:   50;
  --z-nav:     100;   /* sticky topbar */
  --z-toast:   1000;
  --z-grain:   9999;  /* film grain overlay (always on top) */

  /* ── DS · Motion durations · canonical ramp (4 steps) ──
     `--dur-snap` (200ms) and `--dur-instant` (100ms) unified 2026-05:
     kept the name "instant" at the snap value (200ms). `--dur-reveal`
     (800ms) absorbed by `--dur-cinema` (1100ms). Legacy `--dur-fast/
     normal/slow/hover` retired 2026-04. */
  --dur-instant: 200ms;   /* hover, focus, micro-interactions */
  --dur-soft:    320ms;   /* opacity / colour transitions */
  --dur-glide:   600ms;   /* per-element reveal */
  --dur-cinema: 1100ms;   /* the loop arc, loop crossfade */

  /* ── Spacing ── */
  --sp-tiny:    1px;
  --sp-2xs:     2px;
  --sp-xs:      4px;
  --sp-s:       8px;
  --sp-ds:      12px;
  --sp-default: 16px;
  --sp-m:       24px;
  --sp-l:       32px;
  --sp-xl:      40px;

  /* ── Radius ──
     `--radius-xs` (4px) retired 2026-04 — usages migrated to --radius-s.
     The system intentionally has 4 radii: small (8) · medium (16) ·
     large (24) · full (9999, capsule). Plus --radius-circle (50%) above
     for true circles regardless of size. */
  --radius-s:    8px;
  --radius-m:    16px;
  --radius-l:    24px;
  --radius-full: 9999px;

  /* ── Layout ── */
  --max-article: 720px;
  --max-content: 980px;
  --max-wide:    1240px;
  --max-full:    1440px;
  --nav-height:  48px;
  --nav-bg:      var(--gray-black);   /* negro sólido (2026-07 · antes glass rgba 0.85 que se transparentaba con el scroll) */

  /* Gutter lateral · ÚNICO margen horizontal de sección para todo el sitio.
     Auditoría 2026-08: convivían 4 valores (12/16/24/32) → unificado a un
     token responsive: 16px en móvil (densidad + foto expansiva + convención
     iOS) que escala a 24px en tablet/desktop (aire editorial donde sobra
     espacio). Todas las secciones y `.container` lo usan; los bleeds full-bleed
     escapan por calc(-1 * var(--gutter)) y escalan solos.
     Curva: 16 hasta ~500px · llega a 24 a ~750px · 24 por encima. */
  --gutter: clamp(16px, 3.2vw, 24px);

}

.container {
  max-width: var(--max-wide);
  margin: 0 auto;
  padding: 0 var(--gutter);
}

.container.narrow {
  max-width: var(--max-content);
}

.section-dark,
.section-darkest,
.section-stars,
.section-glow {
  position: relative;
  isolation: isolate;
}

.section-dark,
.section-darkest {
  color: var(--content-text-default);
}

.section-dark    { background: var(--bg-neutral-default); }
.section-darkest { background: var(--bg-neutral-bold); }

/* Ambient top-glow — very subtle radial spotlight that gives dark sections
   depth without visible texture. Inspired by Apple's product pages: you
   notice the air, not the gradient. */
.section-dark::before,
.section-darkest::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse 80% 55% at 50% 0%,
              rgba(255, 255, 255, 0.045) 0%,
              rgba(255, 255, 255, 0) 60%);
  pointer-events: none;
  z-index: -1;
}

/* ── Buttons ──────────────────────────────────────────────────────────
   Sizes:    .btn-s (40px) · .btn-m (52px) · .btn-l (62px)
   Variants: .btn-primary (yellow) · .btn-tertiary (glass)
   States:   :hover · :active · :focus-visible · :disabled (all variants)
   ─────────────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-xs);
  font-weight: 600;
  border-radius: var(--radius-full);
  transition: background-color var(--dur-instant) var(--ease-out),
              color var(--dur-instant) var(--ease-out),
              transform var(--dur-instant) var(--ease-out),
              box-shadow var(--dur-instant) var(--ease-out);
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
  border: 0;
}
/* Focus ring uses layered box-shadows instead of outline so it follows
   the button's border-radius (pill) consistently across all browsers.
   First ring matches the canvas (the offset); second is the yellow ring. */
.btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--gray-black), 0 0 0 5px var(--yellow-5);
}
.btn:disabled,
.btn[aria-disabled="true"] {
  opacity: 0.4;
  cursor: not-allowed;
  pointer-events: none;
}

/* Sizes — height + horizontal padding + body font size */
.btn-s { height: 40px; padding: 10px 18px; font-size: var(--text-body-sm); }
.btn-m { height: 52px; padding: 14px 22px; font-size: var(--text-body-md); }
.btn-l { height: 62px; padding: 18px 24px; font-size: var(--text-body-md); }

/* `.btn-tertiary` · solid grey (NO glass). Diferenciado de `.btn-ghost`,
   que sí es glass (white 0.16 + blur). El gris opaco simula el efecto
   que el glass deja sobre fondo negro pero sin transparencia — útil
   cuando hay que destacar acción secundaria sobre fondos heterogéneos
   (foto, satélite, gradientes) donde el glass podría no leer bien.
   Diferencia clave entre las tres variantes glass-ish:
   - .btn-ghost    → transparente, blur, alpha (mezcla con el fondo)
   - .btn-tertiary → gris opaco gray-8 (independiente del fondo)
   - .btn-dark     → near-black gray-11 (más sólido, contraste máximo) */
.btn-tertiary {
  background: var(--gray-8);
  color: var(--gray-white);
}
.btn-tertiary:hover  { background: var(--gray-7); color: var(--gray-white); }
.btn-tertiary:active { background: var(--gray-6); }


/* ── Icon button · acción de un solo icono (cerrar, toggle, FAB) ───────
   Sizes: .icon-btn-s (32px) · .icon-btn-m (40px) · .icon-btn-l (44px)

   Apariencia única · glass (white alpha + backdrop blur), mirror exacto
   de `.btn-ghost`. Funciona sobre superficies oscuras del DS y sobre
   fotos por igual (el blur ancla el botón sin necesidad de scrim sólido).

   El catálogo NO incluye variante "primary" porque las acciones
   destacadas usan `.btn-primary` (pill con label). El icon-btn cubre
   solo UI chrome (cerrar, expandir, FAB de menú, scroll-to-top).
   ─────────────────────────────────────────────────────────────────── */
.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-circle);
  border: 0;
  background: rgba(255, 255, 255, 0.16);
  backdrop-filter: var(--glass-filter);
  -webkit-backdrop-filter: var(--glass-filter);
  color: var(--gray-white);
  cursor: pointer;
  padding: 0;
  flex-shrink: 0;
  transition: background-color var(--dur-instant) var(--ease-out),
              color var(--dur-instant) var(--ease-out),
              transform var(--dur-instant) var(--ease-out);
}

.icon-btn:hover {
  background: rgba(255, 255, 255, 0.22);
  color: var(--gray-white);
}

.icon-btn:active {
  background: rgba(255, 255, 255, 0.28);
}

/* Focus ring · misma técnica que .btn (box-shadow capas) para que el
   anillo siga el radius circle en todos los navegadores. */
.icon-btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--gray-black), 0 0 0 4px var(--yellow-5);
}

.icon-btn:disabled,
.icon-btn[aria-disabled="true"] {
  opacity: 0.4;
  cursor: not-allowed;
  pointer-events: none;
}

/* Sizes · cuadrado fijo, icono centrado vía flex. SVG hereda currentColor. */
.icon-btn-s { width: 32px; height: 32px; }
.icon-btn-m { width: 40px; height: 40px; }
.icon-btn-l { width: 44px; height: 44px; }

/* Variant · tertiary: solid gray-8 (no glass), espejo de `.btn-tertiary`.
   Para FABs sobre fotos o superficies heterogéneas donde el glass
   puede leer mal. El sólido ancla el botón independientemente del fondo. */
.icon-btn-tertiary {
  background: var(--gray-8);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
.icon-btn-tertiary:hover  { background: var(--gray-7); color: var(--gray-white); }
.icon-btn-tertiary:active { background: var(--gray-6); }


.photo-credit {
  position: absolute;
  bottom: 1rem;
  right: 1.5rem;
  /* Mono caption — shared component used by the hero and any photo
     gallery on the page (e.g. Experiences). */
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  font-weight: 400;
  letter-spacing: 0.04em;
  color: rgba(255, 255, 255, 0.65);
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.55);
  z-index: var(--z-overlay);
  pointer-events: none;
  margin: 0;
}

/* Top-right variant — used inside the Experiences gallery so the
   credit doesn't compete with the paginator at the bottom. */
.photo-credit--top {
  top: clamp(12px, 1.6vw, 20px);
  right: clamp(14px, 1.8vw, 22px);
  bottom: auto;
}

@keyframes scrollHintFade {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes scrollHintPulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.55; }
}

/* Calm vertical bounce — a 5px wink to invite scrolling without
   distracting. Keeps `translateX(-50%)` from the base centering and
   adds a gentle Y oscillation. ease-in-out + 2.6s feel intentional
   rather than restless. */
@keyframes scrollHintBounce {
  0%, 100% { transform: translateX(-50%) translateY(0); }
  50%      { transform: translateX(-50%) translateY(9px); }
}

.app-rating {
  margin-top: 2.25rem;
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  color: var(--gray-white);
  font-size: var(--text-body-sm);
}

.app-rating-score {
  font-weight: 600;
  font-size: var(--text-heading-sm);
  letter-spacing: -0.02em;
  line-height: 1;
  color: var(--gray-white);
}

.app-rating-stars {
  display: inline-flex;
  gap: 2px;
  color: var(--brand-yellow);
  align-items: center;
}

.app-rating-stars svg {
  width: 16px;
  height: 16px;
  display: block;
}

.app-rating-count {
  font-family: var(--font-mono);
  font-size: var(--text-body-xs);
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--content-text-subtitle);
  padding-left: 0.65rem;
  border-left: 1px solid rgba(255, 255, 255, 0.2);
  line-height: 1.4;
}
/* Reviews · downloads · en DESKTOP van en una línea, separados por el MISMO
   divider (border-left) que separa las estrellas del contenido. */
.app-rating-count__item + .app-rating-count__item {
  margin-left: 0.65rem;
  padding-left: 0.65rem;
  border-left: 1px solid rgba(255, 255, 255, 0.2);
}
@media (max-width: 720px) {
  /* Móvil · los dos datos APILADOS en 2 líneas, sin divider entre ellos
     (se mantiene el divider estrellas│bloque del .app-rating-count). */
  .app-rating-count { display: inline-flex; flex-direction: column; }
  .app-rating-count__item + .app-rating-count__item {
    margin-left: 0;
    padding-left: 0;
    border-left: 0;
  }
}

@keyframes fadeUp {
  from { opacity: 0; transform: translateY(16px); }
  to { opacity: 1; transform: translateY(0); }
}

.section-header {
  text-align: center;
  max-width: var(--max-content);
  margin: 0 auto 2.5rem;
}

/* Match the typographic scale used in product-copy sections (The App,
   Premium) so titles, subtitles and pitch bodies render identically across
   the page — only alignment changes (centered here vs left there). */
.section-header > .section-subtitle {
  font-size: var(--text-editorial-subtitle);
  line-height: 1.125;
  font-weight: 300;
  margin-bottom: 0;
}

.section-header > .section-rule {
  margin: 2rem auto;
}

.section-header > .pitch-body {
  font-size: var(--text-editorial-body);
  line-height: 1.2;
  font-weight: 300;
  max-width: 56ch;
  margin: 0 auto;
}

@keyframes baHint {
  0%, 100% { transform: translateX(0); }
  30%      { transform: translateX(-8px); }
  70%      { transform: translateX(8px); }
}

.plans-dots {
  display: flex;
  gap: 0.5rem;
  justify-content: center;
  margin-top: 2.5rem;
}

/* (Legacy .loop-dots / .loop-dot rules removed — the live Loop uses
   .loop-stop instead.) */

.section-rule {
  display: block;
  width: 64px;
  height: 2px;
  margin: 0;
  padding: 0;
  border: 0;
  background: var(--gray-6);
}


/* ─────────────────────────────────────────────────────────────────────
   Inline text links — yellow + underlined (2026-05)

   Default `a` style is no underline (set in reset.css) so styled
   buttons / nav / icons stay clean. Inline text links inside
   editorial copy get the canonical link treatment automatically;
   anywhere else, opt in with the `.text-link` class.
   ───────────────────────────────────────────────────────────────────── */
.pitch-body a,
.faq__a a,
.includes__group-note a,
p a,
.text-link {
  color: var(--content-link-default);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
}

.pitch-body a:hover,
.faq__a a:hover,
.includes__group-note a:hover,
p a:hover,
.text-link:hover {
  color: var(--content-link-hover);
}


/* ─────────────────────────────────────────────────────────────────────
   .info-tip — small "i" with hover/focus tooltip bubble (2026-05)

   Inline icon-button used to attach contextual help to a label
   (typically inside fineprint, captions, form fields). The bubble is
   a CSS-only popover — opens on hover, focus and focus-within.

   Markup:
     <span class="info-tip" tabindex="0" role="img"
           aria-label="<the help text>">i<span
           class="info-tip__bubble"><the help text></span></span>

   Notes:
     · `tabindex="0"` makes it keyboard-focusable; `role="img"` keeps the
       SR description simple. The bubble's text is duplicated as
       `aria-label` so screen readers always announce it.
     · The bubble uses --shadow-strong + the canonical hairline + radius-s.
     · Opens via `.info-tip:hover/:focus-visible/:focus-within`.
   ───────────────────────────────────────────────────────────────────── */
.info-tip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  margin-left: 4px;
  border: 1px solid var(--border-neutral-soft);
  border-radius: var(--radius-circle);
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs);
  line-height: 1;
  color: var(--content-text-default-weak);
  cursor: help;
  position: relative;
  vertical-align: middle;
  transition: border-color var(--dur-instant) var(--ease-out),
              color var(--dur-instant) var(--ease-out);
}

.info-tip:hover,
.info-tip:focus-visible {
  border-color: var(--border-secondary-accent);
  color: var(--content-text-default);
  outline: none;
}

.info-tip__bubble {
  position: absolute;
  bottom: calc(100% + 10px);
  left: 50%;
  transform: translateX(-50%);
  width: max-content;
  max-width: 260px;
  padding: 10px 14px;
  background: var(--bg-neutral-default);
  border: 1px solid var(--border-neutral-soft);
  border-radius: var(--radius-s);
  box-shadow: var(--shadow-strong);
  font-family: var(--font-sans);
  font-size: var(--text-body-sm);
  letter-spacing: 0;
  font-weight: 400;
  line-height: 1.45;
  color: var(--content-text-default);
  text-align: left;
  text-transform: none;
  cursor: default;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur-soft) var(--ease-out),
              visibility 0s linear var(--dur-soft);
  z-index: var(--z-popover, 50);
  pointer-events: none;
}

.info-tip:hover .info-tip__bubble,
.info-tip:focus-visible .info-tip__bubble,
.info-tip:focus-within .info-tip__bubble {
  opacity: 1;
  visibility: visible;
  transition-delay: 0s;
}


/* ─────────────────────────────────────────────────────────────────────
   .faq — accordion canónico de preguntas frecuentes (2026-07 audit)

   Promocionado desde premium-pricing (.faq-item) y experiences
   (.exp-faq), que mantenían dos copias espejo de la misma receta.
   Consumido por: premium-pricing, premium, app, experiences.

   Markup:
     <details class="faq">
       <summary class="faq__q">Question?</summary>
       <div class="faq__a"><p>Answer.</p></div>
     </details>

   Notas:
     · La summary funciona con o sin la clase `.faq__q` (el selector
       `.faq > summary` cubre ambos casos).
     · La respuesta admite wrapper `.faq__a` (permite varios párrafos,
       listas, links) o `<p>` directos hijos del details.
     · El indicador +/− es amarillo (el toggle es el action signifier).
     · Question default: --text-body-lg. Páginas de lectura densa pueden
       bajarla un peldaño a --text-body-md con un override page-scoped
       (ver experiences).
   ───────────────────────────────────────────────────────────────────── */
.faq {
  border-bottom: 1px solid var(--border-neutral-soft);
  padding: 18px 0;
}

.faq > summary {
  position: relative;
  list-style: none;          /* Hide default disclosure triangle */
  cursor: pointer;
  font-family: var(--font-sans);
  font-size: var(--text-body-lg);
  /* Mismo peso que el cuerpo (400): la jerarquía pregunta↔respuesta ya la
     dan el color (pregunta blanca / respuesta weak) y el tamaño (21 vs 18).
     El 600 sobraba. (Decisión Irene 2026-08 · antes accordion titles = 600.) */
  font-weight: 400;
  color: var(--content-text-default);
  padding-right: 32px;
  line-height: 1.4;
  transition: color var(--dur-instant) var(--ease-out);
}

.faq > summary::-webkit-details-marker { display: none; }

/* Custom + / − indicator — yellow (the toggle is the action signifier). */
.faq > summary::after {
  content: '+';
  position: absolute;
  right: 4px;
  top: 50%;
  transform: translateY(-50%);
  font-family: var(--font-mono);
  font-size: var(--text-body-lg); /* decorative '+' marker */
  font-weight: 400;
  line-height: 1;
  color: var(--content-text-highlight);
  transition: transform var(--dur-instant) var(--ease-out),
              color var(--dur-instant) var(--ease-out);
}

.faq[open] > summary::after {
  content: '−';
  color: var(--content-text-highlight);
}

.faq > summary:hover {
  color: var(--content-text-highlight);
}

.faq__a {
  margin-top: 10px;
  color: var(--content-text-default-weak);
  font-size: var(--text-body-md);
  line-height: 1.6;
}

.faq__a p {
  margin: 0 0 12px;
  line-height: 1.6;
  font-style: normal;        /* blockquote/em nunca italic (regla DS) */
}

.faq__a p:last-child { margin-bottom: 0; }

/* Variante sin wrapper — párrafos directos dentro del details. */
.faq > p {
  margin: 10px 0 12px;
  font-family: var(--font-sans);
  font-size: var(--text-body-md);
  font-style: normal;
  line-height: 1.6;
  color: var(--content-text-default-weak);
}

.faq > p:last-of-type { margin-bottom: 0; }


/* ─────────────────────────────────────────────────────────────────────
   .acc-toggle — pill de toggle para accordions (2026-07)

   Promocionado desde Dolomites v8 (.exp-hero-shot__plan-summary-icon),
   donde vivía sin documentar. Pill mono uppercase con label dinámico
   (data-attributes) + chevron que rota al abrir. Vive DENTRO del
   <summary> de un <details> (aria-hidden: el summary ya es el control).

   Markup:
     <details>
       <summary> …contenido del summary…
         <span class="acc-toggle" data-label-closed="See details"
               data-label-open="Hide details" aria-hidden="true"></span>
       </summary>
       …
     </details>

   Modo de superficie:
     · Default → on-dark (hairline --border-neutral-soft, texto weak).
     · `.acc-toggle--on-light` → superficies claras (--border-on-light).
     · Páginas con secciones que alternan dark/light pueden re-mapear
       las custom props (--acc-toggle-*) a sus tokens semánticos de
       sección (así lo hace Dolomites con --exp-*).
   ───────────────────────────────────────────────────────────────────── */
.acc-toggle {
  --acc-toggle-color:        var(--content-text-default-weak);
  /* Stroke a white 40% (no el hairline 16% decorativo): es el borde
     de un CONTROL interactivo y debe pasar el contraste no-textual
     de WCAG 1.4.11 (≥3:1 sobre el fondo). White 40% sobre las bandas
     oscuras del catálogo ≈ 3.7:1 (2026-07, feedback usuaria). */
  --acc-toggle-border:       color-mix(in srgb, var(--gray-white) 40%, transparent);
  --acc-toggle-color-hover:  var(--content-text-default);
  --acc-toggle-border-hover: color-mix(in srgb, var(--gray-white) 55%, transparent);
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  background: transparent;
  border: 1px solid var(--acc-toggle-border);
  border-radius: var(--radius-full);
  color: var(--acc-toggle-color);
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  white-space: nowrap;
  transition: color var(--dur-instant) var(--ease-out),
              border-color var(--dur-instant) var(--ease-out);
}

/* Label dinámico · lee data-attributes; el details[open] ancestro
   conmuta closed → open sin CSS específico por accordion. */
.acc-toggle::before {
  content: attr(data-label-closed);
}

details[open] > summary .acc-toggle::before {
  content: attr(data-label-open);
}

/* Chevron · rotación animada al abrir. */
.acc-toggle::after {
  content: '';
  width: 7px;
  height: 7px;
  margin-top: -2px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg);
  transition: transform var(--dur-soft) var(--ease-out),
              margin-top var(--dur-soft) var(--ease-out);
}

details[open] > summary .acc-toggle::after {
  margin-top: 2px;
  transform: rotate(225deg);
}

@media (prefers-reduced-motion: reduce) {
  .acc-toggle::after { transition: none; }
}

details > summary:hover .acc-toggle {
  color: var(--acc-toggle-color-hover);
  border-color: var(--acc-toggle-border-hover);
}

/* Superficies claras (light mode del componente). */
.acc-toggle--on-light {
  --acc-toggle-color:        var(--content-text-on-light-weak);
  /* Mismo criterio WCAG 1.4.11: black 45% sobre off-white ≈ 3.4:1. */
  --acc-toggle-border:       rgba(10, 10, 10, 0.45);
  --acc-toggle-color-hover:  var(--content-text-on-light-default);
  --acc-toggle-border-hover: rgba(10, 10, 10, 0.6);
}


/* ─────────────────────────────────────────────────────────────────────
   .has-vignette — atmospheric overlay utility (2026-04 DS-Web)

   Single radial vignette in the canonical blue-gray cinematic tint.
   Add `.has-vignette` to any section that needs atmospheric character.

   Intensity (default = soft):
     .has-vignette--strong

   Position is NOT part of the documented API — it's set ad-hoc per
   section via the CSS custom properties `--vignette-x` and
   `--vignette-y` (default 50% / 50%). Each page positions the vignette
   behind a key visual element of that section (a logo, a hero word,
   a device mockup) by overriding the variables in page-specific CSS.

   Example (in a page's style.css):
     .product-section--app { --vignette-x: 70%; --vignette-y: 50%; }
   ───────────────────────────────────────────────────────────────────── */
.has-vignette {
  position: relative;
  isolation: isolate;
  --vignette-color: var(--vignette-soft);
  --vignette-x: 50%;
  --vignette-y: 50%;
}

.has-vignette::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: radial-gradient(
    ellipse 70% 60% at var(--vignette-x) var(--vignette-y),
    var(--vignette-color),
    transparent 75%
  );
}

/* Direct children stack above the vignette · `.photo-credit` y
   `.hero-scroll-hint` se excluyen porque son `position: absolute`
   canónicos con anclaje propio (bottom-right y bottom-center
   respectivamente). El selector general los forzaba a `relative`
   → perdían su posicionamiento.
   IMPORTANTE: los `:not(...)` van envueltos en `:where()` para que
   no aporten especificidad. Si no, la regla pasaría de (0,1,0) a
   (0,3,0) y machacaría declaraciones page-scoped como `position:
   absolute` en `.exp-hero__media` / `.exp-movement__media`,
   descuadrando los hero full-bleed. */
.has-vignette > *:where(:not(.photo-credit):not(.hero-scroll-hint)) {
  position: relative;
  z-index: 1;
}

/* Intensity (the only documented modifier) */
.has-vignette--strong { --vignette-color: var(--vignette-strong); }

/* ─────────────────────────────────────────────────────────────────
   .badge — unified contextual label (2026-04 DS-Web rename)
   Replaces .eyebrow-tag (mono pill), .plan-tier (sans pill in author
   credits), and .beta-badge (SVG inline with section title).
   ───────────────────────────────────────────────────────────────── */

/* Default badge — yellow outline pill, mono uppercase.
   Used standalone or inline with body text. Mono is the canonical
   typography for badges (firma técnica) — 2026-05. */
.badge {
  display: inline-block;
  padding: 3px 12px;
  background: transparent;
  border: 1px solid var(--yellow-5);
  border-radius: var(--radius-full);
  color: var(--yellow-5);
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  line-height: 1.2;
  white-space: nowrap;
  vertical-align: middle;
}

/* `.badge--mono` retired 2026-05 — mono is now the default.
   Selector kept as a no-op alias so older markup still validates. */
.badge--mono { /* intentionally empty — same as .badge default */ }

/* Inline-with-title — sized RELATIVE to the parent heading so it
   shrinks/grows with the title. Combine with .badge--mono for the
   classic kicker-on-title pattern (e.g. "Captured Plans · BETA"). */
.badge--inline-title {
  font-size: 0.28em;
  padding: 0.35em 0.9em;
  letter-spacing: 2px;
  margin-left: 0.4em;
  position: relative;
  top: -0.4em;
}

/* `.badge--brand` y `.badge--huge` retirados 2026-05 — el SVG-Beta-mark
   se sustituyó por badge de texto mono (`<span class="badge badge--inline-title">Beta</span>`)
   para mantener la coherencia tipográfica. Si en el futuro vuelve a hacer
   falta un badge tipo SVG/imagen, reintroducir el modifier. */

/* ── Legacy aliases — keep until all pages migrate to .badge.
   Both selectors behave identically to .badge for now. */
.eyebrow-tag,
.plan-tier {
  display: inline-block;
  padding: 4px 14px;
  background: transparent;
  border: 1px solid var(--yellow-5);
  border-radius: var(--radius-full);
  color: var(--yellow-5);
  font-family: var(--font-sans);
  font-size: var(--text-body-sm);
  font-weight: 500;
  letter-spacing: 0;
  line-height: 1.2;
  white-space: nowrap;
  vertical-align: middle;
}

/* `.section-title .badge--brand` y `.section-title .beta-badge` retirados
   2026-05 junto con la migración SVG → texto mono (`.badge--inline-title`).
   Si vuelve a hacer falta un badge-imagen, restaurar estas reglas. */

/* ===========================================================================
   CARD · contenedor de contenido canónico (promovido al DS · 2026-08 ·
   refundado sobre auditoría transversal de las 12 hojas · docs/DS-COMPONENT-AUDIT.md)
   Consolida la docena de cards que vivían sueltas por página (.mis-card,
   .review-card, .showcase-card, .award-card, .plan-card, .feature-tile,
   .sr-card…): todas resolvían lo mismo (foto opcional + tipo + título + texto
   en una caja) con recetas ligeramente distintas. Base tomada de `.mis-card`
   (la más completa del sitio); superficie unificada a `--gradient-subtle`
   (decisión Irene 2026-08 · el gradient "card on dark" del catálogo).
   Esta es la única card del sistema; las demás se migran poco a poco.
   Superficie = `--gradient-subtle` + filete `--border-neutral-soft` +
   `--radius-l`. Hover (solo en --link): lift 2px + filete más claro +
   shadow-soft + zoom 1.04 de la foto (patrón .mis-card). Media opcional.
   Reutiliza otros componentes por dentro — NO duplicar: tags → `.badge`,
   autor → `.author-credit`, rating → `.app-rating`.
   Anatomía:
     .card               contenedor (columna: media opcional + body)
     .card--link         toda la card es <a> · lift + zoom de foto + foco al hover
     .card--compact      grids densos (resultados, listados): padding y tipo
                         un paso más pequeños; mismo radius para coherencia
     .card--light        superficie CLARA (blanca) · para bandas on-light
                         (guías, artículo, mapas Dolomites)
     .card__media        franja de imagen/vídeo arriba · ratio vía --card-ratio
     .card__play         afordancia de play (overlay) para media de vídeo
     .card__icon         icono (alternativa al media · feature-tile)
     .card__body         padding + columna + gap
     .card__eyebrow      metadato mono (tipo/categoría) · yellow uppercase
     .card__meta-row     fila eyebrow + meta (space-between)
     .card__meta         píldora mono de dato (duración, tiempo de lectura)
     .card__title        sans 600 (título)
     .card__text         sans weak (descripción)
     .card__footer       meta mono separada por filete (fecha, fuente…)
     .card__actions      fila de botones/CTA al pie (ver regla de interacción)
   Extensiones de dominio (NO en la base) que viven en su página: los datos de
   misión (.card--mission → facts/availability/sold-out) y los de precio
   (chip/amount/per). Ver el documento de auditoría.
   =========================================================================== */
.card {
  display: flex;
  flex-direction: column;
  background: var(--gradient-subtle);
  border: 1px solid var(--border-neutral-soft);
  border-radius: var(--radius-l);
  overflow: hidden;
  color: var(--content-text-default);
}

/* Card enlazada — toda la tarjeta es un <a>. Sin subrayado + el hover
   canónico de .mis-card: lift 2px + filete más claro + shadow-soft. */
a.card,
.card--link {
  text-decoration: none;
  transition: border-color var(--dur-instant) var(--ease-out),
              transform var(--dur-instant) var(--ease-out),
              box-shadow var(--dur-instant) var(--ease-out);
}
a.card:hover,
.card--link:hover {
  border-color: color-mix(in srgb, var(--gray-white) 24%, transparent);
  transform: translateY(-2px);
  box-shadow: var(--shadow-soft);
}
a.card:focus-visible,
.card--link:focus-visible {
  outline: 2px solid var(--yellow-5);
  outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
  a.card:hover,
  .card--link:hover { transform: none; }
}

/* Media — imagen o vídeo arriba. Ratio configurable por instancia con
   --card-ratio (default 16/10 · usa 4/3, 1/1… según el listado). */
.card__media {
  position: relative;
  margin: 0;
  aspect-ratio: var(--card-ratio, 16 / 10);
  overflow: hidden;
  background: var(--gradient-subtle);
}
.card__media img,
.card__media video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform var(--dur-glide) var(--ease-out);
}
/* Zoom sutil de la foto al hover de una card enlazada (patrón .mis-card). */
a.card:hover .card__media img,
a.card:hover .card__media video,
.card--link:hover .card__media img,
.card--link:hover .card__media video { transform: scale(1.04); }
@media (prefers-reduced-motion: reduce) {
  a.card:hover .card__media img,
  a.card:hover .card__media video,
  .card--link:hover .card__media img,
  .card--link:hover .card__media video { transform: none; }
}

/* Afordancia de play — para cards de vídeo (icono SVG dentro, sin literal). */
.card__play {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 48px;
  height: 48px;
  border-radius: var(--radius-circle);
  background: rgba(0, 0, 0, 0.55);
  color: var(--gray-white);
  display: flex;
  align-items: center;
  justify-content: center;
}
.card__play svg { width: 18px; height: 18px; display: block; }

/* Body */
.card__body {
  display: flex;
  flex-direction: column;
  gap: var(--sp-s);
  padding: clamp(18px, 1.8vw, 24px);
}

/* Icono — alternativa al media para cards sin foto (feature-tile: icono +
   nombre + desc). Va arriba del body. Color de acento por defecto. */
.card__icon { width: 32px; height: 32px; color: var(--content-text-highlight); }
.card__icon svg { width: 100%; height: 100%; display: block; }
/* Icono desde un asset SVG vía mask-image, tintado con el acento (reutiliza el
   SVG sin tocarlo · feature-tiles). La URL va por inline `style="--icon:url()"`. */
.card__icon--mask {
  background-color: var(--content-text-highlight);
  -webkit-mask: var(--icon) center / contain no-repeat;
          mask: var(--icon) center / contain no-repeat;
}

/* Eyebrow / tipo — metadato mono pequeño (categoría, tipo de contenido).
   Mono es correcto aquí: es metadato, no acción ni título. */
.card__eyebrow {
  font-family: var(--font-mono);
  /* 14px (2026-08 · decisión de Irene): el eyebrow es lo que ORDENA la card —
     dice de qué tipo es — y a 12 se leía como una nota al pie. Sube un peldaño
     del ramp mono. La píldora `.card__meta` NO le acompaña: se queda en 12
     porque es dato secundario, y esa diferencia de tamaño es jerarquía
     deliberada dentro de `.card__meta-row`, no un descuadre. */
  font-size: var(--text-mono-md);
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--content-text-highlight);
  margin: 0;
}

/* Meta-row — antetítulo + dato mono a la derecha, en la MISMA fila. Es la
   cabecera de metadatos de una card de listado (Videos, Guides, Search). */
.card__meta-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

/* Meta — píldora mono compacta con el dato del item ("28 min", "14 min read").
   Promovida al DS 2026-08 desde `.vid-duration` (Videos) + `.gd-readtime`
   (Guides), que eran idénticas; Search es el tercer uso. Distinta de `.chip`
   (píldora sans, más grande, es etiqueta/filtro clicable): ésta es metadato
   pasivo dentro de una card. */
.card__meta {
  flex: none;
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  color: var(--content-text-default);
  background: color-mix(in srgb, var(--gray-white) 10%, transparent);
  border-radius: var(--radius-full);
  padding: 2px 8px;
  letter-spacing: 0.02em;
  white-space: nowrap;
}
.card--light .card__meta {
  background: color-mix(in srgb, var(--gray-black) 8%, transparent);
  color: var(--content-text-on-light-default);
}

/* Título — sans 600 (regla universal de títulos del DS). */
.card__title {
  font-family: var(--font-sans);
  font-size: var(--text-body-lg);
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -0.01em;
  color: var(--content-text-default);
  margin: 0;
}

/* Texto / descripción */
.card__text {
  font-family: var(--font-sans);
  font-size: var(--text-body-sm);
  font-weight: 300;
  line-height: 1.5;
  color: var(--content-text-default-weak);
  margin: 0;
}

/* Footer — meta mono separada por filete (autor, fecha, fuente, rating…). */
.card__footer {
  margin-top: var(--sp-xs);
  padding-top: var(--sp-default);
  border-top: 1px solid var(--border-neutral-soft);
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  letter-spacing: 0.02em;
  color: var(--content-text-default-weak);
}
.card__footer strong { color: var(--content-text-default); font-weight: 500; }

/* Actions — fila de botones/CTA al pie del body (masters "Conócele", pricing,
   misiones con 2 CTAs). Reutiliza `.btn` / `.cta-row` por dentro.
   ⚠️ REGLA DE INTERACCIÓN: una card con `.card__actions` (botones reales) NO
   puede ser `<a class="card">` / `.card--link` — un <a>/<button> dentro de un
   <a> es HTML inválido. Dos modos:
     · Card-enlace  → `<a class="card card--link">`, sin botones dentro (el CTA
       es una afordancia visual: chevron/texto). Click en toda la card.
     · Card-acciones → `<article class="card">` con `.card__actions`; el título
       puede ser un <a>. Para cards con uno o varios botones. */
.card__actions { display: flex; flex-wrap: wrap; gap: var(--sp-s); margin-top: var(--sp-s); }

/* Compact — grids densos (resultados de búsqueda, listados largos): padding y
   tipografía un peldaño más pequeños. Mismo radius/superficie → coherente. */
.card--compact .card__body { gap: var(--sp-xs); padding: 14px 16px 16px; }
.card--compact .card__title { font-size: var(--text-body-sm); }
.card--compact .card__text  { font-size: var(--text-body-xs); line-height: 1.45; }

/* Row — card HORIZONTAL: miniatura + texto en una sola fila. Para listados y
   resultados (búsqueda). El título se lee siempre (envuelve); el texto de debajo
   se recorta a 2 líneas. Media cuadrada de ancho fijo a la izquierda. */
.card--row { flex-direction: row; align-items: stretch; border-radius: var(--radius-m); }
.card--row .card__media { flex: none; width: clamp(88px, 26vw, 128px); aspect-ratio: 1 / 1; }
.card--row .card__body { flex: 1 1 auto; min-width: 0; justify-content: center; gap: var(--sp-xs); padding: 12px 16px; }
.card--row .card__title { font-size: var(--text-body-sm); }
.card--row .card__text {
  font-size: var(--text-body-xs);
  line-height: 1.45;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Light — superficie CLARA (blanca). Para bandas on-light (guías, artículo,
   popover de mapa en Dolomites). Consolida .exp-wte-card / .exp-map-card /
   .read-next__card. Nota: el eyebrow amarillo no pasa AA sobre blanco → en
   light el metadato va en gris on-light (--content-text-on-light-weak). */
.card--light {
  background: var(--bg-light-default);
  border-color: var(--border-on-light);
  color: var(--content-text-on-light-default);
}
.card--light .card__media { background: var(--gray-1); }
.card--light .card__eyebrow { color: var(--content-text-on-light-weak); }
.card--light .card__title { color: var(--content-text-on-light-default); }
.card--light .card__text { color: var(--content-text-on-light-weak); }
.card--light .card__footer { border-top-color: var(--border-on-light); color: var(--content-text-on-light-weak); }
.card--light .card__footer strong { color: var(--content-text-on-light-default); }
a.card--light:hover,
.card--light.card--link:hover {
  border-color: color-mix(in srgb, var(--gray-black) 22%, transparent);
}

/* Bare — card SIN caja (sin fondo/borde/sombra): solo media + texto. Para
   galerías/sugerencias donde manda la foto y no hay recuadro (read-next del
   artículo, showcase de premium). El media conserva su radius; el hover NO
   eleva (no hay caja) — solo hace zoom de la foto. Combínala con --light en
   superficies claras. Va después de --light para ganar en bg/borde. */
.card--bare {
  background: none;
  border: 0;
  border-radius: 0;
  overflow: visible;
}
.card--bare .card__media { border-radius: var(--radius-m); }
.card--bare .card__body { padding: 0.9rem 0 0; }
a.card--bare:hover,
.card--bare.card--link:hover { transform: none; box-shadow: none; border-color: transparent; }

/* ===========================================================================
   FORM CONTROLS · campo + input (promovidos al DS · 2026-08 · desde login)
   El DS no tenía campo de texto (solo el toggle .cookie-switch); lo reinventaban
   login/search/missions/calculadoras. `.field` es el wrapper (label + input +
   hint/error); `.input` el control. Superficie oscura; los inputs son lo ÚNICO
   cuadrado del sistema (--radius-s) — todo lo demás (botones, chips) es pill.
   =========================================================================== */
.field { display: flex; flex-direction: column; gap: 8px; }
.field__row { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.field label,
.field__label {
  font-family: var(--font-sans);
  font-size: var(--text-body-sm);
  font-weight: 500;
  color: var(--content-text-default);
}
.field__hint {
  font-family: var(--font-sans);
  font-size: var(--text-body-xs);
  color: var(--content-link-default);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.field__hint:hover { color: var(--content-link-hover); }
.field__error { font-family: var(--font-sans); font-size: var(--text-body-xs); color: var(--red-4); }

.input,
textarea.input {
  width: 100%;
  height: 50px;
  padding: 0 15px;
  background: rgba(255, 255, 255, 0.04);
  /* Borde del input más visible que el filete de 16% (decisión Irene 2026-08):
     los campos necesitan más affordance que una card. Blanco al 55%. */
  border: 1px solid color-mix(in srgb, var(--gray-white) 55%, transparent);
  border-radius: var(--radius-s);
  color: var(--content-text-default);
  font-family: var(--font-sans);
  font-size: var(--text-body-sm);
  transition: border-color var(--dur-instant) var(--ease-out),
              background var(--dur-instant) var(--ease-out);
}
textarea.input { height: auto; min-height: 96px; padding: 12px 15px; resize: vertical; }
/* Placeholder blanco 50% → 5.3:1 sobre el input (pasa AA; el 42% previo daba
   4.05, por debajo del 4.5). Sigue más apagado que el texto escrito (blanco). */
.input::placeholder { color: rgba(255, 255, 255, 0.5); }
.input:hover { border-color: color-mix(in srgb, var(--gray-white) 75%, transparent); }
.input:focus-visible {
  outline: 2px solid var(--yellow-5);
  outline-offset: 2px;
  border-color: transparent;
  background: rgba(255, 255, 255, 0.06);
}
.input--error { border-color: var(--red-5); }

/* Input con adornos — icono guía a la izquierda y/o botón de limpiar (×) a la
   derecha. Para buscadores (search-box) y campos con acción. El wrapper posiciona
   los adornos; el input recibe padding para no solaparse. */
.input-wrap { position: relative; display: flex; align-items: center; }
.input-wrap__icon { position: absolute; left: 15px; display: inline-flex; color: var(--content-text-default-weak); pointer-events: none; }
.input-wrap__icon svg { display: block; }
.input-wrap:has(.input-wrap__icon) .input { padding-left: 44px; }
.input-wrap__clear {
  all: unset;
  position: absolute;
  right: 8px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: var(--radius-circle);
  color: var(--content-text-default-weak);
}
.input-wrap__clear:hover { color: var(--content-text-default); }
.input-wrap__clear:focus-visible { outline: 2px solid var(--yellow-5); outline-offset: 2px; }
.input-wrap:has(.input-wrap__clear) .input { padding-right: 44px; }

/* ===========================================================================
   BTN · slot de icono + full-width + variante social (promovidos 2026-08)
   `.btn__icon` es el slot de icono guía (escala con el texto vía em); cuando
   una .btn lo lleva, el gap sube a 8px. `.btn--block` = full-width.
   `.btn-social` = botón de login con proveedor (Google/Apple): superficie
   suave y calmada para APILAR varias opciones sin competir entre sí (distinta
   del ghost/outline, más presentes). Pill como todos los .btn.
   =========================================================================== */
.btn__icon { display: inline-flex; align-items: center; justify-content: center; width: 1.25em; height: 1.25em; flex-shrink: 0; }
.btn__icon svg { width: 100%; height: 100%; display: block; }
.btn:has(.btn__icon) { gap: var(--sp-s); }
.btn--block { width: 100%; }
.btn-social {
  background: rgba(255, 255, 255, 0.03);
  color: var(--gray-white);
  box-shadow: inset 0 0 0 1px var(--border-neutral-soft);
}
.btn-social:hover { background: rgba(255, 255, 255, 0.06); box-shadow: inset 0 0 0 1px var(--gray-5); }

/* ===========================================================================
   CALLOUT · caja de aviso / tips (promovida 2026-08 · desde article .tips)
   Título mono + lista con checks. Variantes de superficie oscura (default) y
   clara. En claro el check va en gris (el amarillo no pasa contraste).
   =========================================================================== */
.callout {
  border-radius: var(--radius-m);
  padding: clamp(20px, 2.5vw, 28px);
  background: color-mix(in srgb, var(--gray-white) 5%, transparent);
  border: 1px solid var(--border-neutral-soft);
}
.callout__title {
  font-family: var(--font-mono);
  font-size: var(--text-mono-md);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--content-text-highlight);
  margin: 0 0 14px;
}
.callout ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.callout li { display: flex; gap: 10px; font-size: var(--text-body-sm); line-height: 1.45; color: var(--content-text-default-weak); }
.callout li::before { content: '✓'; color: var(--yellow-5); font-weight: 600; flex-shrink: 0; }
.callout--light {
  /* Gris de Apple `--bg-light-default` (#F5F7FA) SIN borde (decisión Irene) — el
     MISMO gris que read-next; antes iba 6% más oscuro y desentonaba. */
  background: var(--bg-light-default);
  border-color: transparent;
  color: var(--content-text-on-light-default);
}
.callout--light .callout__title { color: var(--content-text-on-light-weak); }
.callout--light li { color: var(--content-text-on-light-default); }
.callout--light li::before { color: var(--content-text-on-light-weak); }

/* ===========================================================================
   PANEL · superficie de contenido/CTA sin media (promovido 2026-08)
   El hermano "texto" de la card. `.panel--glass` = superficie oscura
   translúcida + blur + shadow-strong (receta de login-card / nav glass).
   =========================================================================== */
.panel {
  padding: clamp(28px, 3.5vw, 44px);
  border-radius: var(--radius-l);
  background: color-mix(in srgb, var(--gray-white) 4%, transparent);
  border: 1px solid var(--border-neutral-soft);
}
.panel--glass {
  background: var(--glass-bg-panel);
  -webkit-backdrop-filter: var(--glass-filter-strong);
  backdrop-filter: var(--glass-filter-strong);
  box-shadow: var(--shadow-strong);
}

/* ===========================================================================
   CHIP · píldora base (etiqueta o enlace). `<a class="chip">` es un chip
   clicable. Variante `--tag` (amarilla · etiquetas de contenido, tipo tags de
   blog/guía · validada 2026-08). `.chip-dismiss` (chip eliminable con ×) cuelga
   de la misma base. Distinto de `.badge` (metadato mono) y `.tablist__item`.
   =========================================================================== */
.chip,
.chip-dismiss {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border-radius: var(--radius-full);
  background: color-mix(in srgb, var(--gray-white) 8%, transparent);
  font-family: var(--font-sans);
  font-size: var(--text-body-sm);
  color: var(--content-text-default);
}
/* Chip-enlace: sin subrayado (es tag/nav, no link inline de prosa) + hover. */
a.chip { text-decoration: none; transition: background var(--dur-instant) var(--ease-out), color var(--dur-instant) var(--ease-out); }
a.chip:hover { background: color-mix(in srgb, var(--gray-white) 15%, transparent); color: var(--content-text-default); }
a.chip:focus-visible { outline: 2px solid var(--yellow-5); outline-offset: 2px; }
/* Tag · píldora amarilla para etiquetas de contenido. El hover ACLARA
   (yellow-2 → yellow-1), nunca oscurece. Texto oscuro (lee sobre el amarillo). */
.chip--tag { background: var(--yellow-2); color: var(--content-text-on-light-default); }
a.chip--tag:hover { background: var(--yellow-1); color: var(--content-text-on-light-default); }
/* El × necesita hueco a la derecha. */
.chip-dismiss { padding: 6px 8px 6px 12px; }
.chip-dismiss__remove {
  all: unset;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: var(--radius-circle);
  color: var(--content-text-default-weak);
  transition: color var(--dur-instant) var(--ease-out), background var(--dur-instant) var(--ease-out);
}
.chip-dismiss__remove:hover { color: var(--content-text-default); background: rgba(255, 255, 255, 0.08); }
.chip-dismiss__remove:focus-visible { outline: 2px solid var(--yellow-5); outline-offset: 2px; }

/* Chip SELECCIONABLE (filtro por tema · sugerencias) — la píldora canónica usada
   como toggle de filtro dentro de un listado de contenido (vídeo, guía, expedición).
   DISTINTO del tab (.tablist): el tab es el filtro fijo/canónico por TIPO de
   contenido (Search); el chip es una SUGERENCIA de tema, más blanda.

   El fondo base del chip (.chip = white 8%) es casi invisible sobre el lienzo
   negro. Esta variante seleccionable usa RELLENO sólido (no stroke): inactivo =
   gris medio (gray-6 · 3.66:1 sobre negro) con texto oscuro; seleccionado =
   relleno NEUTRO gris oscuro (gray-8) con texto blanco — NUNCA amarillo (relleno
   amarillo = acción; decisiones de Irene 2026-08). Va sobre <button>. */
button.chip {
  border: 0;
  cursor: pointer;
  font-family: var(--font-sans);
  font-size: var(--text-body-sm);
  background: var(--gray-8);           /* reposo · gris oscuro, texto blanco */
  color: var(--gray-white);
  transition: background var(--dur-instant) var(--ease-out),
    color var(--dur-instant) var(--ease-out);
}
button.chip:hover { background: var(--gray-7); }
button.chip:focus-visible { outline: 2px solid var(--yellow-5); outline-offset: 2px; }
button.chip.is-active,
button.chip[aria-pressed="true"] {
  background: var(--gray-6);           /* seleccionado · más claro → destaca + aspa */
  color: var(--gray-white);
  font-weight: 600;
}
button.chip.is-active:hover,
button.chip[aria-pressed="true"]:hover { background: var(--gray-5); }
/* Multi-select tipo Missions: al seleccionar aparece un aspa (×) que quita ese
   filtro. El × va en el markup (oculto) y se revela en activo. Como el chip es
   un <button> toggle, el clic en cualquier parte del chip activo lo deselecciona;
   el × es la afordancia visual de "quitar". */
.chip .chip__x { display: none; }
.chip .chip__x svg { display: block; width: 10px; height: 10px; }
.chip.is-active .chip__x,
.chip[aria-pressed="true"] .chip__x { display: inline-flex; opacity: 0.85; }

/* ===========================================================================
   POPOVER + CHECKBOX · menú anclado + checkbox custom (promovidos 2026-08)
   `.popover` es superficie de menú (misma receta de card). `.checkbox` es el
   checkbox custom con tick amarillo, usable dentro del popover o suelto
   (con `.is-checked`).
   =========================================================================== */
.popover {
  background: var(--gradient-subtle);
  border: 1px solid var(--border-neutral-soft);
  box-shadow: var(--shadow-soft);
  border-radius: var(--radius-l);
  padding: 8px;
}
.popover__option {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 12px;
  border-radius: var(--radius-s);
  font-family: var(--font-sans);
  font-size: var(--text-body-sm);
  cursor: pointer;
}
.popover__option:hover { background: rgba(255, 255, 255, 0.05); }
.checkbox {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  border: 1px solid var(--border-neutral-soft);
  border-radius: var(--radius-s);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.checkbox svg { width: 12px; height: 12px; opacity: 0; color: var(--gray-black); }
.checkbox.is-checked,
.popover__option.is-selected .checkbox { background: var(--yellow-5); border-color: var(--yellow-5); }
.checkbox.is-checked svg,
.popover__option.is-selected .checkbox svg { opacity: 1; }

/* ===========================================================================
   SPEC-LIST · lista de pares etiqueta/valor dt/dd (promovido 2026-08)
   Metadatos técnicos (datos de misión, "what to expect", ficha del hero shot).
   =========================================================================== */
.spec-list { display: grid; grid-template-columns: max-content 1fr; gap: 8px 20px; }
/* Etiqueta · mono uppercase weak. Alineada 2026-08 con la convención de pares
   etiqueta/valor que ya usaba Dolomites (`.exp-overview__label`): 14px, weight
   500 y tracking 0.08em — el mismo tracking que `.card__eyebrow`, que es LA
   norma para etiquetas mono en mayúsculas. Al promover el componente se había
   quedado un peldaño por debajo en los tres valores. */
.spec-list dt {
  font-family: var(--font-mono);
  font-size: var(--text-mono-md);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--content-text-default-weak);
}
/* Valor · sans 18px (cuerpo por defecto). NO copiamos el weight 500 del valor
   de Dolomites: allí es una cuadrícula compacta de datos, y aquí el valor puede
   ser una definición de glosario — o sea prosa, que va en regular. */
.spec-list dd { margin: 0; font-family: var(--font-sans); font-size: var(--text-body-md); color: var(--content-text-default); }

/* ===========================================================================
   BREADCRUMB · migas de navegación (promovido 2026-08)
   Chrome de navegación jerárquica (Home / Academy / Videos). Registro SANS
   discreto (no prosa, no acento): enlaces en gris que ACLARAN al hover (nunca
   amarillo/subrayado, que es solo para links de prosa), separador "/" decorativo
   vía ::before, y la página actual sin enlace (aria-current="page").
   Semántica: <nav aria-label="Breadcrumb"> > <ol class="breadcrumb__list">.
   El dato estructurado BreadcrumbList (JSON-LD) va SIEMPRE en la página aunque
   el breadcrumb visible se omita (SEO/GEO · ver nota en el MDS).
   =========================================================================== */
.breadcrumb { font-family: var(--font-sans); font-size: var(--text-body-xs); line-height: 1.4; }
.breadcrumb__list {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 8px;
  margin: 0;
  padding: 0;
}
.breadcrumb__item { display: inline-flex; align-items: center; gap: 4px 8px; color: var(--content-text-default-weak); }
/* Separador decorativo entre migas (no en la primera). */
.breadcrumb__item + .breadcrumb__item::before {
  content: "/";
  color: var(--content-text-default-weak);
  opacity: 0.55;
}
.breadcrumb a {
  color: var(--content-text-default-weak);
  text-decoration: none;
  padding: 2px 0;
  transition: color var(--dur-instant) var(--ease-out);
}
.breadcrumb a:hover { color: var(--content-text-default); }
.breadcrumb a:focus-visible { outline: 2px solid var(--yellow-5); outline-offset: 2px; border-radius: 2px; }
/* Página actual: no es enlace, contraste pleno. */
.breadcrumb__current { color: var(--content-text-default); }

/* ===========================================================================
   PHOTO-TILE · tile de foto protagonista + etiqueta (promovido 2026-08)
   Distinto de la card de contenido: aquí manda la foto. Ratio por instancia
   con --tile-ratio (default 4/5). Scrim del catálogo (--scrim-photo-soft).
   Consolida .prep-tile (home) + .exp-pursue__chip (experiences).
   =========================================================================== */
.photo-tile {
  position: relative;
  display: block;
  aspect-ratio: var(--tile-ratio, 4 / 5);
  border-radius: var(--radius-m);
  overflow: hidden;
  background: var(--gradient-subtle);
  text-decoration: none;
}
.photo-tile img,
.photo-tile video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform var(--dur-glide) var(--ease-out);
}
.photo-tile:hover img,
.photo-tile:hover video { transform: scale(1.04); }
.photo-tile:focus-visible { outline: 2px solid var(--yellow-5); outline-offset: 2px; }
.photo-tile figcaption,
.photo-tile__caption { position: absolute; inset: auto 0 0 0; padding: 18px 16px 16px; background: var(--scrim-photo-soft); }
.photo-tile__title { font-family: var(--font-sans); font-size: var(--text-body-lg); font-weight: 600; color: var(--gray-white); margin: 0; }
.photo-tile__by { font-family: var(--font-mono); font-size: var(--text-mono-sm); color: rgba(255, 255, 255, 0.75); margin: 4px 0 0; }

/* ===========================================================================
   OVERLAY-CARD · retrato con caption dentro de la foto (promovido 2026-08)
   Ratio por instancia con --overlay-ratio (default 3/4). Scrim fuerte del
   catálogo. Consolida .exp-way-card--overlay + .exp-master-card.
   =========================================================================== */
.overlay-card {
  position: relative;
  display: block;
  aspect-ratio: var(--overlay-ratio, 3 / 4);
  border-radius: var(--radius-m);
  overflow: hidden;
  background: var(--gradient-subtle);
  text-decoration: none;
}
.overlay-card img,
.overlay-card video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform var(--dur-glide) var(--ease-out);
}
.overlay-card:hover img,
.overlay-card:hover video { transform: scale(1.04); }
.overlay-card:focus-visible { outline: 2px solid var(--yellow-5); outline-offset: 2px; }
.overlay-card__caption { position: absolute; inset: auto 0 0 0; padding: 18px 16px 16px; background: var(--scrim-photo-strong); }
.overlay-card__name { font-family: var(--font-sans); font-size: var(--text-body-md); font-weight: 500; color: var(--gray-white); margin: 0; }
.overlay-card__meta { font-family: var(--font-mono); font-size: var(--text-mono-sm); color: rgba(255, 255, 255, 0.75); margin: 3px 0 0; }
/* Texto que se revela al hover/focus (bio de masters, copy de way-card--overlay).
   Colapsado por defecto; se expande al interactuar con la card. */
.overlay-card__reveal {
  max-height: 0;
  opacity: 0;
  overflow: hidden;
  transition: max-height var(--dur-glide) var(--ease-soft), opacity var(--dur-glide) var(--ease-soft);
}
.overlay-card:hover .overlay-card__reveal,
.overlay-card:focus-within .overlay-card__reveal { max-height: 12em; opacity: 1; }
.overlay-card__reveal p { font-family: var(--font-sans); font-size: var(--text-body-sm); color: rgba(255, 255, 255, 0.85); line-height: 1.45; margin: 8px 0 0; }

@media (prefers-reduced-motion: reduce) {
  .photo-tile:hover img,
  .photo-tile:hover video,
  .overlay-card:hover img,
  .overlay-card:hover video { transform: none; }
  .overlay-card__reveal { transition: none; }
}

/* ===========================================================================
   LISTING · plantilla de la familia de LISTADOS ESPECÍFICOS (promovida al DS ·
   2026-08 · desde Videos/Guides/Blog). FUENTE ÚNICA del "chrome" de un listado
   de un solo tipo: cabecera (breadcrumb + título + subtítulo + recuento), barra
   sticky (buscador + filtros por TEMA con .chip) con fondo de cristal que
   aparece al pegarse + pliegue suave de los filtros, y grid de .card CON fondo
   en 3 columnas con su píldora `.card__meta`.
   La card es la del DS (misma unidad de resultado en toda la web · ver "Patrón
   de listado" en el MDS). El JS (barra sticky + filtro + paginación) vive en
   script.js. La Search GENÉRICA (tabs + 4col + sin píldora) NO usa este
   componente — vive en search/ (decisión de sistema · dos filtros, una card).
   =========================================================================== */

/* Lienzo del listado (el <main>). El body toma el negro ancla para el overscroll. */
body:has(.listing) { background: var(--bg-bold); }
.listing {
  background: var(--gradient-strong);
  padding-top: calc(var(--nav-height) + clamp(32px, 5vw, 56px));
  padding-bottom: clamp(56px, 8vw, 100px);
  min-height: 70svh;
  color: var(--content-text-default);
}

/* ── Cabecera ─────────────────────────────────────────────────────────── */
.listing__head { margin-bottom: clamp(24px, 3.5vw, 36px); }
.listing__head .breadcrumb { margin-bottom: clamp(12px, 2vw, 16px); }
.listing__title {
  font-family: var(--font-sans);
  font-size: clamp(var(--text-heading-md), 4.5vw, var(--text-heading-xl));
  font-weight: 600;
  letter-spacing: var(--tracking-display);
  line-height: var(--lh-heading);
  /* Cap al MISMO ancho que el párrafo (≈48ch del subtítulo) para que título y
     texto rompan en el mismo borde. En rem (absoluto) — nunca `ch` en headings:
     a tamaño display `ch` se dispara (regla del MDS). */
  max-width: 40rem;
  margin: 0;
}
.listing__subtitle {
  font-family: var(--font-sans);
  font-size: var(--text-body-lg);
  font-weight: 300;
  line-height: 1.3;
  color: var(--content-text-default-weak);
  max-width: 48ch;
  margin: 12px 0 0;
}
.listing__count {
  font-family: var(--font-sans);
  font-size: var(--text-body-sm);
  color: var(--content-text-default-weak);
  margin: 4px 0 clamp(16px, 3.5vw, 22px);
}
.listing__count strong { color: var(--content-text-default); font-weight: 600; }

/* ── Barra sticky (buscador + filtros) ────────────────────────────────────
   Se pega bajo la nav; sube con ella cuando se oculta. El fondo de cristal lo
   pinta ::before a 100vw y solo aparece al pegarse (.is-stuck · lo activa el JS
   de script.js). Padding simétrico arriba/abajo cuando se pega. */
.listing__bar {
  display: flex;
  flex-direction: column;
  position: sticky;
  top: calc(var(--nav-height) + env(safe-area-inset-top, 0px));
  z-index: 40;
  margin: 0 0 clamp(24px, 3.5vw, 36px);
  padding: 10px 0;
  transform: translateY(0);
  transition: transform var(--dur-soft) var(--ease-out);
}
.listing__bar::before {
  content: "";
  position: absolute;
  top: 0; bottom: 0; left: 50%;
  width: 100vw;
  transform: translateX(-50%);
  background: var(--glass-bg-panel);
  -webkit-backdrop-filter: var(--glass-filter-strong);
  backdrop-filter: var(--glass-filter-strong);
  box-shadow: 0 1px 0 var(--border-neutral-soft);
  opacity: 0;
  transition: opacity var(--dur-instant) var(--ease-out);
  z-index: -1;
  pointer-events: none;
}
.listing__bar.is-stuck::before { opacity: 1; }
body:has(.nav.hidden) .listing__bar {
  transform: translateY(calc(-1 * (var(--nav-height) + env(safe-area-inset-top, 0px))));
}
.listing__search { max-width: 640px; }
.listing__search .input::-webkit-search-cancel-button { display: none; }

/* Filtros colapsables · al pegarse la barra, la franja de filtros se pliega
   suavemente (altura real vía grid-rows 1fr→0fr) dejando solo el buscador. La
   separación (14px) vive como MARGEN del contenedor (se anima a 0), para que no
   deje residuo al colapsar. */
.listing__collapse {
  display: grid;
  grid-template-rows: 1fr;
  margin-top: 14px;
  transition: grid-template-rows var(--dur-soft) var(--ease-soft),
              margin-top var(--dur-soft) var(--ease-soft);
}
.listing__bar.is-stuck .listing__collapse { grid-template-rows: 0fr; margin-top: 0; }
.listing__filters { display: flex; flex-wrap: wrap; gap: 8px; min-height: 0; overflow: hidden; }
/* Chip que no cabe entero en la barra pegada (una sola línea) → se oculta, no se
   corta a media píldora. Lo marca el JS del listado según el espacio disponible. */
.listing__filters .chip.is-clipped { display: none; }
.listing__bar.is-stuck .listing__filters {
  opacity: 0;
  transition: opacity var(--dur-instant) var(--ease-out);
}
@media (max-width: 720px) {
  /* En móvil la franja de chips va en UNA línea con scroll horizontal y SANGRA a
     los bordes de la pantalla. El bleed va en `.listing__collapse` (flex item →
     crece con margen negativo a ambos lados), NO en `.listing__filters` (grid
     item → no sangra a la derecha). */
  .listing__collapse { margin-left: calc(-1 * var(--gutter)); margin-right: calc(-1 * var(--gutter)); }
  .listing__filters {
    flex-wrap: nowrap;
    max-width: none;
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    padding: 0 var(--gutter);
  }
  .listing__filters::-webkit-scrollbar { display: none; }
  .listing__filters .chip,
  .listing__filters .tablist__item { flex: 0 0 auto; white-space: nowrap; }
  .listing__bar .listing__search { max-width: none; }
}
@media (prefers-reduced-motion: reduce) {
  .listing__collapse { transition: none; }
  .listing__bar.is-stuck .listing__filters { transition: none; }
}

/* Al pegarse en ESCRITORIO (≥1024): en vez de ocultar los chips, la barra se
   compacta a UNA fila — buscador a la izquierda, chips a la derecha. En reposo
   los chips siguen DEBAJO; solo cambian de sitio al quedarse pegada. (En
   móvil/tablet no caben en fila → se ocultan, como arriba.) */
@media (min-width: 1024px) {
  .listing__bar:not(.listing__bar--inline).is-stuck { flex-direction: row; align-items: center; gap: clamp(16px, 3vw, 32px); }
  /* El buscador CONSERVA su ancho de la página (640) — nunca se encoge. */
  .listing__bar:not(.listing__bar--inline).is-stuck .listing__search { flex: 0 0 640px; max-width: 640px; }
  /* Los chips ocupan lo que sobre a la derecha, en UNA línea; los que no quepan
     se recortan (no se muestran). Prioridad: el ancho correcto del buscador. */
  .listing__bar:not(.listing__bar--inline).is-stuck .listing__collapse { grid-template-rows: 1fr; margin-top: 0; flex: 1 1 auto; min-width: 0; overflow: hidden; }
  .listing__bar:not(.listing__bar--inline).is-stuck .listing__filters { opacity: 1; flex-wrap: nowrap; overflow: hidden; }
}

/* Barra en fila (variante genérica ≥1200 · Search): buscador a la izquierda +
   filtros a la derecha en una sola fila → ya es compacta, NO se pliega. */
@media (min-width: 1200px) {
  .listing__bar--inline { flex-direction: row; align-items: center; gap: clamp(16px, 3vw, 32px); }
  .listing__bar--inline .listing__search { flex: 0 1 640px; }
  .listing__bar--inline .listing__collapse { margin-top: 0; margin-left: auto; align-self: center; }
  .listing__bar--inline.is-stuck .listing__collapse { grid-template-rows: 1fr; }
  .listing__bar--inline.is-stuck .listing__filters { opacity: 1; }
}

/* ── Grid · cards CON fondo (.card del DS), 3 columnas ────────────────────
   La card es la unidad de resultado del DS: media 16/9, `.card__meta-row` +
   `.card__meta` para el antetítulo + píldora (todo ya definido en `.card`).
   Aquí solo el layout del grid y el play como etiqueta abajo-izquierda. */
.listing__grid {
  --card-ratio: 16 / 9;
  display: grid;
  grid-template-columns: 1fr;
  gap: 24px;
}
@media (min-width: 720px)  { .listing__grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .listing__grid { grid-template-columns: repeat(3, 1fr); } }
/* Variante GENÉRICA (Search): la MISMA card, solo más densidad → 4 columnas en
   desktop (misma card 16/9, título 22, gap 24 · lo único que cambia es la
   rejilla). La card sin píldora es decisión de MARKUP (no incluye `.card__meta`),
   ver "Patrón de listado" en el MDS. Su consumidor es search/. */
@media (min-width: 1024px) { .listing__grid--generic { grid-template-columns: repeat(4, 1fr); } }
/* En MÓVIL las cards del listado son HORIZONTALES (miniatura + texto, SIN
   snippet) — patrón validado de read-next / resultados de Search: más compactas
   y escaneables que la vertical a ancho completo (decisión Irene 2026-08). */
@media (max-width: 720px) {
  .listing__grid .card { flex-direction: row; align-items: stretch; border-radius: var(--radius-m); }
  .listing__grid .card__media { flex: none; width: clamp(96px, 28vw, 120px); aspect-ratio: 1 / 1; }
  /* Cuerpo apretado: poco aire entre antetítulo, título y autor. */
  .listing__grid .card__body { flex: 1 1 auto; min-width: 0; justify-content: center; gap: 3px; padding: 12px 14px; }
  .listing__grid .card__text { display: none; }
  /* En la fila estrecha manda el título; se retira la píldora de meta (duración/
     lectura) para no apretar el antetítulo. */
  .listing__grid .card__meta { display: none; }
  /* El play del vídeo va CENTRADO en la miniatura en móvil (no abajo-izquierda). */
  .listing__grid .card__play { inset: 0; margin: auto; width: 36px; height: 36px; }
  .listing__grid .card__play svg { width: 15px; height: 15px; }
}
/* Play como etiqueta abajo-izquierda SOLO en desktop (en móvil va centrado, arriba). */
@media (min-width: 721px) {
  .listing__grid .card__play { inset: auto auto 10px 10px; margin: 0; width: 40px; height: 40px; }
  .listing__grid .card__play svg { width: 16px; height: 16px; }
}

/* ── Estados · vacío + paginación "cargar más" ────────────────────────────── */
.listing__empty { text-align: center; padding: clamp(48px, 8vw, 96px) 0; }
.listing__empty[hidden] { display: none; }
.listing__empty__icon { color: var(--content-text-default-weak); margin-bottom: 16px; }
.listing__empty__title { font-family: var(--font-sans); font-size: var(--text-heading-sm); font-weight: 600; margin: 0 0 8px; }
.listing__empty__title strong { color: var(--content-text-highlight); font-weight: 600; }
.listing__empty__text { font-family: var(--font-sans); font-size: var(--text-body-sm); color: var(--content-text-default-weak); margin: 0 0 18px; }
.listing__empty .btn { text-decoration: none; }
.listing__more { display: flex; justify-content: center; margin-top: clamp(28px, 4vw, 44px); }

@media (max-width: 480px) {
  .listing__title { font-size: var(--text-heading-md); }
}

/* ===========================================================================
   STATUS BADGE (chip de estado) · glass + dot · familia semántica de
   disponibilidad · usado en las cards de Missions y en el CTA de plazas de
   las Expeditions. Base glass neutra + `.mis-badge--pastel` que añade el
   color de estado (bg del paso -7/-8 al 82% + texto blanco) y un punto
   (`.mis-badge__dot`) del paso -5 delante del label.
   Estados:
     · --pastel-available · NEUTRO (bg-bold 82%) · punto BLANCO · "disponible / N spots"
     · --pastel-few       · amarillo (yellow-8)  · punto yellow-5 · "quedan pocas"
     · --pastel-soldout   · rojo (red-7)         · punto red-5    · "agotado"
     · --pastel-coming    · azul (blue-7)        · punto blue-5   · "próximamente"
   Excepción AA: yellow usa -8 (en -7 el blanco daba 3.0-3.8:1). Contraste
   peor caso (alpha .82 sobre foto clara): blue 5.4 · yellow 4.9 · red 5.5 ·
   neutral > 8 — todos pasan 4.5:1. Nota: en Missions el estado "open" (con
   plazas de sobra) NO lleva chip; la variante --pastel-available es para
   cuando el estado disponible SÍ debe mostrarse (p. ej. el CTA de plazas de
   Expeditions). Clase legacy `mis-` por su origen en Missions; componente
   compartido del DS. */
.mis-badge {
  display: inline-flex;
  align-items: center;
  height: 26px;
  padding: 0 10px;
  border-radius: var(--radius-full);
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: var(--glass-filter-strong);
  -webkit-backdrop-filter: var(--glass-filter-strong);
  color: var(--content-text-default);
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs);
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.mis-badge--pastel {
  backdrop-filter: var(--glass-filter-strong);
  -webkit-backdrop-filter: var(--glass-filter-strong);
  font-weight: 600;
  gap: 8px;
  padding-left: 9px;
}
/* Available · fondo neutro oscuro · lleva un filete claro muy sutil (hairline
   canónico del DS, blanco 16%) para no perderse sobre fondos negros. Las demás
   variantes tienen tinte de color y no lo necesitan. */
.mis-badge--pastel-available { background: color-mix(in srgb, var(--bg-bold) 82%, transparent); color: var(--gray-white); border: 1px solid var(--border-neutral-soft); }
.mis-badge--pastel-coming    { background: color-mix(in srgb, var(--blue-7) 82%, transparent);   color: var(--gray-white); }
.mis-badge--pastel-few       { background: color-mix(in srgb, var(--yellow-8) 82%, transparent); color: var(--gray-white); }
.mis-badge--pastel-soldout   { background: color-mix(in srgb, var(--red-7) 82%, transparent);    color: var(--gray-white); }

/* Dot · punto de 6px del color saturado `-5` (sin alpha) delante del texto. */
.mis-badge__dot {
  width: 6px;
  height: 6px;
  border-radius: var(--radius-circle);
  display: inline-block;
  flex-shrink: 0;
}
.mis-badge--pastel-available .mis-badge__dot { background: var(--gray-white); }
.mis-badge--pastel-coming    .mis-badge__dot { background: var(--blue-5);   }
.mis-badge--pastel-few       .mis-badge__dot { background: var(--yellow-5); }
.mis-badge--pastel-soldout   .mis-badge__dot { background: var(--red-5);    }

.prep-chips {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px;
  max-width: 1100px;
  margin: 1.5rem auto 2rem;
}

.prep-chip {
  display: inline-flex;
  align-items: center;
  padding: 9px 16px;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: var(--radius-full);
  color: rgba(255, 255, 255, 0.9);
  font-family: inherit;
  /* Sits one notch above fs-body-sm (14) for legibility, without
     jumping all the way to fs-body (17). Mirrors .exp-story-chip-name. */
  font-size: var(--text-body-sm);
  font-weight: 400;
  letter-spacing: 0;
  cursor: pointer;
  transition: background var(--dur-soft) ease,
    border-color var(--dur-soft) ease,
    color var(--dur-soft) ease,
    transform var(--dur-soft) ease;
  white-space: nowrap;
  -webkit-tap-highlight-color: transparent;
}

.prep-chip:hover {
  background: rgba(255, 255, 255, 0.09);
  border-color: rgba(255, 255, 255, 0.24);
  color: var(--gray-white);
}

.prep-chip:focus-visible {
  outline: 2px solid var(--bg-primary-default);
  outline-offset: 3px;
}

@keyframes finalCtaHeadline {
  from { opacity: 0; transform: scale(0.96); filter: blur(8px); }
  to   { opacity: 1; transform: scale(1);    filter: blur(0); }
}

@keyframes finalCtaFade {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: translateY(0); }
}

.reveal.visible {
  opacity: 1;
  transform: translateY(0);
}

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

@keyframes slowZoom {
  /* Gentle Ken-Burns drift — bumped from 1.05 to 1.10 so the zoom is a
     touch more cinematic without ever calling attention to itself. */
  from { transform: scale(1); }
  to   { transform: scale(1.10); }
}

/* ── Gallery zoom · utilidad de slideshow ────────────────────────────────
   Añade `gallery-zoom` al contenedor de slides de cualquier galería (el que
   tiene overflow:hidden). La foto de la slide activa (`.is-active img`) hace
   un zoom-in lento con el `slowZoom` canónico — mismo gesto que los heroes.
   Es el efecto compartido entre TODAS las galerías de slideshow del sitio.
   La animación se reinicia al cambiar de slide (la clase .is-active se mueve). */
.gallery-zoom .is-active img {
  animation: slowZoom 12s var(--ease-out) forwards;
}
@media (prefers-reduced-motion: reduce) {
  .gallery-zoom .is-active img { animation: none; transform: none; }
}

.btn-primary {
  background: var(--bg-primary-default);
  color: var(--gray-9);
}
.btn-primary:hover  { background: var(--yellow-6);             color: var(--gray-9); }
.btn-primary:active { background: var(--bg-primary-strong); color: var(--gray-9); }

.field-ready {
  color: var(--gray-9);
}

.btn-secondary:not(.get-app-trigger) {
  background: transparent !important;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border: none !important;
  padding: 0 !important;
  height: auto !important;
  font-size: var(--text-body-md);
  font-weight: 500;
  color: var(--gray-white);
  display: inline-flex;
  align-items: center;
  gap: 2px;
}


.btn-secondary:not(.get-app-trigger)::after {
  content: "\203A";
  display: inline-block;
  margin-left: 6px;
  font-size: 1.35em;
  font-weight: 300;
  line-height: 1;
  transition: transform var(--dur-instant) var(--ease-out);
}


.btn-secondary:not(.get-app-trigger):hover {
  background: transparent !important;
  color: var(--gray-white);
  opacity: 0.85;
}


.btn-secondary:not(.get-app-trigger):hover::after {
  transform: translateX(3px);
}


.section-subtitle {
  font-size: clamp(var(--text-body-lg), 2vw, var(--text-lead));
  line-height: 1.3;
  font-weight: 300;
  letter-spacing: -0.01em;
  color: var(--gray-white);
  max-width: 720px;
  margin-left: auto;
  margin-right: auto;
  margin-bottom: 2.5rem;
  text-wrap: pretty;
}

/* ── Word-joining SOLO en títulos (2026-08, decisión de la usuaria) ────
   La norma de "juntar palabras" / equilibrar líneas (`text-wrap: balance`)
   se aplica ÚNICAMENTE a titulares y subtítulos. Los PÁRRAFOS y LISTAS
   envuelven de forma NORMAL (greedy) — antes llevaban `text-wrap: pretty`,
   que reordenaba líneas para evitar huérfanos y provocaba cortes que no
   tenían sentido (sobre todo en los checks cortos y en párrafos anchos). */
p, li, dd, dt, figcaption, blockquote {
  text-wrap: wrap;
}

h1, h2, h3, h4,
.section-subtitle,
.statement-line {
  text-wrap: balance;
}

/* Cinturón para la norma anti-viudas donde el motor no llega (p.ej.
   statements con las palabras en spans coreografiados, o Safari sin
   `pretty`): envolver las DOS últimas palabras en `.keep-together`. */
.keep-together {
  white-space: nowrap;
}

/* Eyebrow line — mono yellow uppercase text that introduces a page or
   section title. The "title above the title" pattern. Used on the page
   intros (Premium, Design System styleguide). Pair with margin-bottom
   in the parent layout to space it from the headline below. */
.eyebrow-line {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--text-mono-lg);
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--yellow-5);
  margin: 0;
}

/* (.section-eyebrow retired in 2026-04 coherence pass — replaced by
   .eyebrow-line above. The previous gray-sans pattern had zero uses
   in the homepage and was not picked up by any new page.) */

/* Brand accent — a single keyword highlighted in yellow within a larger
   statement (e.g. "Preparation is not."). Site-wide pattern. */
.statement-accent-word {
  color: var(--brand-yellow);
}

/* Ghost pill — glass-style secondary CTA. Comparte el MISMO glass que
   `.btn-tertiary` (blur 2.5px / saturate 120% / white 0.16). Si cambias el
   valor del glass, cámbialo en AMBOS para no divergir (ver nota en
   .btn-tertiary). Use when a hero/CTA row needs two or three button-shaped
   actions (e.g. Experiences hero). */
.btn-ghost {
  background: var(--glass-bg);
  backdrop-filter: var(--glass-filter);
  -webkit-backdrop-filter: var(--glass-filter);
  color: var(--gray-white);
}

.btn-ghost:hover {
  background: rgba(255, 255, 255, 0.22);
  color: var(--gray-white);
}

.btn-ghost:active {
  background: rgba(255, 255, 255, 0.28);
}

/* Ghost / Dark / Outline variants no longer override `.btn:focus-visible`.
   The base box-shadow ring (yellow, follows pill border-radius) applies to
   every variant — one ring colour for the whole .btn family. */

.btn-tertiary.get-app-trigger {
  color: var(--gray-white);
}

.btn-tertiary.get-app-trigger:hover {
  color: var(--gray-white);
}

.btn-dark {
  background: var(--gray-11);
  color: var(--gray-white);
}

.btn-dark:hover {
  background: var(--gray-white);
  color: var(--gray-9);
}

.btn-dark:active {
  background: var(--gray-1);
  color: var(--gray-9);
}

/* (Inherits .btn:focus-visible — see comment above btn-ghost.) */

.btn-outline {
  background: transparent;
  color: var(--gray-white);
  box-shadow: inset 0 0 0 1px var(--gray-white);
}

.btn-outline:hover {
  background: var(--gray-white);
  color: var(--gray-9);
}

.btn-outline:active {
  background: var(--gray-1);
  color: var(--gray-9);
}

/* (Inherits .btn:focus-visible — see comment above btn-ghost.) */

/* Section title — sans 600 SemiBold by default. Editorial/marketing
   sections (.product-copy, .loopD-copy, .final-cta, .statement-*) all
   inherit this weight without overrides. The previous default of 400 was
   inconsistent with the home, where every section title rendered 600 via
   a catch-all override in style.css. Source of truth aligned 2026-05. */
.section-title {
  font-family: var(--font-sans);
  font-weight: 600;
  letter-spacing: var(--tracking-heading);
  line-height: var(--lh-heading);
  font-feature-settings: 'ss01' on;
  font-size: clamp(var(--text-heading-lg), 5.5vw, var(--text-display-lg));
  margin-bottom: 1.5rem;
  text-wrap: balance;
}

.section-title + .section-subtitle {
  margin-top: -0.25rem;
}

/* Product hero title — COMPONENTE COMPARTIDO (Pricing + Premium usan el mismo
   H1 "PhotoPills Premium Beta"). Vivía duplicado en cada page CSS; centralizado
   aquí para que actualizar uno actualice ambos (decisión Irene 2026-08).
   Desktop: suelo display-md (64) → display-lg (78), una línea. Móvil: suelo
   heading-xl (56), repartido. El badge (.badge--inline-title) escala con él.
   NOTA: nombre legacy `pricing-intro__title-v2` (heredado del markup de las 3
   páginas) — App NO lo usa (se le retiró la clase para no tocar su desktop). */
.pricing-intro__title-v2 {
  font-size: var(--text-hero-title);
  font-weight: 600;
  white-space: nowrap;
  text-wrap: nowrap;
  margin-bottom: 1.5rem;
}

@media (max-width: 720px) {
  .pricing-intro__title-v2 {
    font-size: var(--text-hero-title-sm);
    white-space: normal;
    text-wrap: balance;
  }
}

/* `.section` y `.section-lg` retiradas (mayo 2026): eran utilidades
   placebo — todas las secciones que las usaban hacían override. El padding
   vertical de cada sección se aplica directamente con un token
   `--section-pad-y-{sm,md,lg,xl}` en su CSS específico. */

.reveal {
  opacity: 0;
  transform: translateY(32px);
  transition: opacity var(--dur-cinema) var(--ease-reveal),
    transform var(--dur-cinema) var(--ease-reveal);
  will-change: opacity, transform;
}

/* Active chip: subtle yellow accent — a soft yellow tint on the fill +
   a low-opacity yellow border. The chrome reads as selected without
   shouting. */
.prep-chip.is-active {
  background: color-mix(in srgb, var(--yellow-5) 10%, transparent);
  border-color: color-mix(in srgb, var(--yellow-5) 55%, transparent);
  color: var(--gray-white);
  font-weight: 500;
}
.prep-chip.is-active:hover {
  background: color-mix(in srgb, var(--yellow-5) 16%, transparent);
  border-color: color-mix(in srgb, var(--yellow-5) 75%, transparent);
  color: var(--gray-white);
}

.plans-dot.active {
  background: var(--gray-white);
}

/* ════════════════════════════════════════════════════════════════════════════
   SITE CHROME — nav, footer, global focus
   Moved from style.css so all landings share the same chrome.
   ════════════════════════════════════════════════════════════════════════════ */

/* style.css — page-specific styles (nav, hero, product sections, footer, etc.) */

/* Global focus ring — for any focusable element that doesn't have its own
   override. Outline (not box-shadow) here so we don't break the layout of
   container-y elements that use box-shadow for other reasons.
   IMPORTANT: no `border-radius` declaration — the outline follows the
   element's own radius natively in modern browsers. Setting one here would
   mutate pill buttons into rounded squares on focus. */
:focus-visible {
  outline: 2px solid var(--content-link-default);
  outline-offset: 2px;
}



/* ════════════════════════════════════════════════════════════════════════════
   NAVIGATION
   ════════════════════════════════════════════════════════════════════════════ */

.nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  /* Altura total = nav-height + safe area (status bar notch/dynamic
     island). El fondo y blur cubren hasta arriba del todo del display
     · el padding-top desplaza el contenido (logo, links) por debajo
     del status bar. Sin esto, el contenido se "comería" la status
     bar en iOS Safari con viewport-fit=cover. */
  height: calc(var(--nav-height) + env(safe-area-inset-top, 0px));
  padding-top: env(safe-area-inset-top, 0px);
  background: var(--nav-bg);
  /* Fondo NEGRO SÓLIDO (Apple-style: barra fija, nada del fondo se ve a
     través, en ningún lado). Antes tenía `backdrop-filter: blur` (glass),
     pero en iOS Safari con `viewport-fit=cover` el backdrop-filter impedía
     que el fondo OPACO pintara → se transparentaba el hero por TODA la barra.
     Lo sustituimos por `transform: translateZ(0)`: crea el MISMO bloque
     contenedor que el drawer móvil necesita (lo que antes daba el
     backdrop-filter) SIN romper el pintado del fondo opaco. */
  transform: translateZ(0);
  z-index: var(--z-nav);
  transition: transform var(--dur-soft) var(--ease-out);
}

/* iOS Safari · con `viewport-fit=cover` + `backdrop-filter`, el fondo de la
   nav a veces NO pinta la franja del notch (env(safe-area-inset-top)) y se
   transparenta el contenido de detrás (p.ej. el hero). Este pseudo pinta esa
   franja superior en negro sólido, por encima, SIN tocar el backdrop-filter
   (que debe seguir creando el bloque contenedor del drawer móvil). El
   contenido de la nav va por debajo (padding-top), así que no se solapa. */
.nav::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: env(safe-area-inset-top, 0px);
  background: var(--nav-bg);
}

.nav.hidden {
  transform: translateY(-100%);
}

/* Progressbar acoplada a la nav · en páginas de lectura (article/dolomites) la
   barra vive a `top: var(--nav-height)` con position:fixed, independiente de la
   nav. Al esconderse la nav (translateY(-100%)) la barra se descolgaba. Aquí la
   la SUBIMOS con la nav (misma transición) pero SOLO la altura de la nav, para
   que la barra quede pegada al borde superior y SIGA VISIBLE (decisión Irene
   2026-08: la progressbar siempre visible; al esconderse la nav, la barra ocupa
   su hueco arriba, no se esconde). Solo páginas con `.scroll-progress` (lectura). */
.scroll-progress {
  transition: transform var(--dur-soft) var(--ease-out);
}
body:has(.nav.hidden) .scroll-progress {
  transform: translateY(calc(-1 * (var(--nav-height) + env(safe-area-inset-top, 0px))));
}

.nav-inner {
  /* Contenido de la topbar a FULL WIDTH en TODO el sitio (decisión Irene
     2026-08: unificar). Antes capaba a --max-full (1440) centrado y solo
     experiences/dolomites/article lo overrideaban → incoherencia. */
  max-width: none;
  height: 100%;
  margin: 0 auto;
  padding: 0 1.5rem;
  /* Grid 3-col (1fr auto 1fr) · logo izq · links CENTRADOS de verdad
     en el viewport (columna central equidistante) · acciones der.
     Antes era flex con `margin-right/left: auto`, que centraba los
     links en el hueco entre logo y acciones — como el bloque de
     acciones es más ancho que el logo, los links quedaban desplazados
     a la izquierda del centro real. El grid los centra sin importar
     el ancho de logo/acciones. En móvil (≤1024) vuelve a flex (ver
     media query). */
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 2rem;
}

.nav-logo {
  display: flex;
  align-items: center;
  justify-self: start;
}

.nav-logo img {
  /* 20px · reducido desde 24 (feedback usuaria jul 2026) · uniforme en
     todos los breakpoints (antes 24 desktop / 20 phone). A 20px el logo
     mide ~119px de ancho — sobre el mínimo de 80px del MDS (QA #46). */
  height: 20px;
}

.nav-links {
  display: flex;
  gap: 0;
  align-items: center;
  justify-self: center;
}

.nav-link {
  color: rgba(255, 255, 255, 0.9);
  font-size: var(--text-body-sm);
  font-weight: 400;
  padding: 0 0.85rem;
  line-height: var(--nav-height);
  transition: color var(--dur-instant) var(--ease-out);
  position: relative;
  white-space: nowrap;
}

.nav-link:hover {
  color: var(--gray-white);
}

.nav-link.active {
  color: var(--gray-white);
}

.nav-link.active::after {
  content: '';
  position: absolute;
  bottom: 8px;
  left: 0.75rem;
  right: 0.75rem;
  height: 2px;
  background: var(--content-link-default);
}

.nav-link.has-dropdown::after {
  content: none;
}

.nav-caret {
  display: inline-block;
  width: 10px;
  height: 10px;
  margin-left: 6px;
  opacity: 0.6;
  transition: transform var(--dur-instant) var(--ease-out), opacity var(--dur-instant) ease;
}

.nav-item {
  position: relative;
  display: inline-flex;
  align-items: center;
}

.nav-item-has-sub .nav-link {
  display: inline-flex;
  align-items: center;
}

.nav-sub-link {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 10px 12px;
  border-radius: var(--radius-s);
  color: var(--gray-white);
  text-decoration: none;
  line-height: 1.3;
  transition: background var(--dur-instant) ease;
  min-height: 44px;
  justify-content: center;
}

.nav-sub-link:hover {
  background: rgba(255, 255, 255, 0.06);
}

.nav-sub-link:focus-visible {
  background: rgba(255, 255, 255, 0.06);
  outline: 2px solid var(--content-link-default);
  outline-offset: -2px;
}

.nav-sub-title {
  font-size: var(--text-body-sm);
  font-weight: 600;
  color: var(--gray-white);
}

.nav-sub-desc {
  font-size: var(--text-body-xs);
  color: rgba(255, 255, 255, 0.78);
}

/* Item de menú cuya página aún no existe: inerte (no clicable) + atenuado +
   etiqueta "Soon". Se activa cambiando el <span> por <a href> cuando la página
   esté validada. */
.nav-sub-link--soon {
  pointer-events: none;
  cursor: default;
  opacity: 0.55;
}
.nav-soon {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 6px;
  border-radius: var(--radius-full);
  border: 1px solid var(--border-neutral-soft);
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs);
  font-weight: 500;
  font-style: normal;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--content-text-default-weak);
  vertical-align: middle;
}

.nav-actions {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  justify-self: end;
}

.nav-search {
  width: 20px;
  height: 20px;
  color: rgba(255, 255, 255, 0.8);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: color var(--dur-instant);
}

.nav-login {
  display: inline-flex;
  align-items: center;
  height: 32px;
  padding: 0 14px;
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: var(--radius-full);
  color: rgba(255, 255, 255, 0.92);
  font-size: var(--text-body-sm);
  font-weight: 500;
  letter-spacing: -0.005em;
  text-decoration: none;
  white-space: nowrap;       /* never wraps to two lines */
  flex-shrink: 0;            /* don't squeeze when nav-actions runs short */
  transition: background-color var(--dur-instant) var(--ease-out),
              border-color var(--dur-instant) var(--ease-out),
              color var(--dur-instant) var(--ease-out);
  -webkit-tap-highlight-color: transparent;
}
@media (max-width: 480px) {
  .nav-login {
    height: 28px;
    padding: 0 11px;
    font-size: var(--text-mono-sm);   /* 12px — still readable */
  }
}
.nav-login:hover {
  background: rgba(255, 255, 255, 0.06);
  border-color: rgba(255, 255, 255, 0.32);
  color: var(--gray-white);
}
.nav-login:focus-visible {
  outline: 2px solid var(--yellow-5);
  outline-offset: 2px;
}

.nav-search:hover {
  color: white;
}

.nav-lang {
  color: rgba(255, 255, 255, 0.78);
  font-size: var(--text-body-xs);
  letter-spacing: 0.5px;
  display: flex;
  gap: 4px;
}

.nav-lang .active {
  color: white;
  font-weight: 600;
}

.nav-lang .sep {
  color: rgba(255, 255, 255, 0.5);
}

.nav-lang a {
  color: rgba(255, 255, 255, 0.78);
  transition: color var(--dur-instant);
}

.nav-lang a:hover {
  color: var(--gray-white);
}
/* ESP deshabilitado (mockup solo en inglés · reactivable con ESP_ENABLED en i18n.js). */
.nav-lang .is-disabled {
  opacity: 0.4;
  pointer-events: none;
  cursor: not-allowed;
}

.nav-toggle {
  display: none;
  width: 40px;
  height: 40px;
  background: transparent;
  border: 0;
  padding: 0;
  cursor: pointer;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  -webkit-tap-highlight-color: transparent;
  border-radius: var(--radius-s);
  transition: background var(--dur-instant) var(--ease-out);
}

/* Botón hamburguesa LIMPIO · sin fondo (como el resto de iconos del topbar).
   En hover/active las barras se aclaran levemente; el aro amarillo solo con
   navegación por teclado (:focus-visible), sin relleno. */
.nav-toggle:hover .nav-toggle-bar {
  background: var(--gray-white);
}

.nav-toggle:focus-visible {
  outline: 2px solid var(--content-link-default);
  outline-offset: 2px;
}

.nav-toggle-bar {
  display: block;
  width: 22px;
  height: 2px;
  background: var(--gray-white);
  border-radius: 1px;
  transition: transform var(--dur-soft) var(--ease-out), opacity var(--dur-soft) var(--ease-out);
}

.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}

.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(2) {
  opacity: 0;
}

.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}

@media (min-width: 1025px) {
  .nav-item-has-sub:hover .nav-caret,
  .nav-item-has-sub:focus-within .nav-caret,
  .nav-item-has-sub.is-open .nav-caret {
    transform: rotate(-180deg);
    opacity: 1;
  }
}

@media (min-width: 1025px) {
  .nav-sub {
    position: absolute;
    top: 100%;
    left: 50%;
    transform: translateX(-50%) translateY(6px);
    min-width: 280px;
    padding: 12px;
    background: var(--bg-neutral-default);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: var(--radius-m);
    box-shadow:
      0 2px 4px rgba(0, 0, 0, 0.22),
      0 16px 36px rgba(0, 0, 0, 0.45),
      inset 0 1px 0 rgba(255, 255, 255, 0.05);
    display: flex;
    flex-direction: column;
    gap: 2px;
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--dur-instant) var(--ease-out), transform var(--dur-instant) var(--ease-out);
    z-index: var(--z-chip);
  }
}

@media (min-width: 1025px) {
  .nav-item-has-sub:hover .nav-sub,
  .nav-item-has-sub:focus-within .nav-sub,
  .nav-item-has-sub.is-open .nav-sub {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
    pointer-events: auto;
  }

  /* Invisible bridge so hover doesn't drop when moving parent → submenu */
  .nav-item-has-sub::after {
    content: '';
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    height: 10px;
    pointer-events: none;
  }

  .nav-item-has-sub:hover::after {
    pointer-events: auto;
  }
}

/* =============================================================================
   MEGA-MENÚ DE NAVEGACIÓN (estilo Apple) · desplegable a TODO EL ANCHO.
   Chrome canónico (decisión Irene + jefes · ago 2026). Se activa con la clase
   `.nav--mega` en el <nav> + un <div class="nav-scrim"> hermano. El panel cae
   desde la barra a ancho completo, la página se atenúa (scrim) y los enlaces
   quedan aireados. Solo desktop (≥1025); en móvil el nav usa el drawer canónico.
   ========================================================================== */
@media (min-width: 1025px) {
  /* El item no crea contenedor: el panel se ancla a la barra (la .nav con
     transform es el bloque contenedor del position:fixed → ancho completo). */
  .nav--mega .nav-item-has-sub { position: static; }
  .nav--mega .nav-item-has-sub::after { content: none; }  /* sin bridge: el panel toca la barra */

  .nav--mega .nav-sub {
    position: fixed;
    top: calc(var(--nav-height) + env(safe-area-inset-top, 0px));
    left: 0;
    right: 0;
    width: 100%;
    min-width: 0;
    margin: 0;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 4px 28px;
    /* padding lateral = margen que centra el contenido a --max-wide (como Apple). */
    padding: 28px max(24px, calc((100vw - var(--max-wide)) / 2)) 40px;
    background: var(--nav-bg);
    border: 0;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 0;
    box-shadow: 0 28px 56px rgba(0, 0, 0, 0.5);
    opacity: 0;
    pointer-events: none;
    transform: translateY(-10px);
    transition: opacity var(--dur-soft) var(--ease-out),
                transform var(--dur-soft) var(--ease-out);
    z-index: var(--z-chip);
  }
  .nav--mega .nav-item-has-sub:hover .nav-sub,
  .nav--mega .nav-item-has-sub:focus-within .nav-sub,
  .nav--mega .nav-item-has-sub.is-open .nav-sub {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
  }

  /* Enlaces más aireados y tipografía más tranquila. */
  .nav--mega .nav-sub-link { padding: 12px 10px; }
  .nav--mega .nav-sub-title { font-size: var(--text-body-md); font-weight: 500; }
  .nav--mega .nav-sub-desc { font-size: var(--text-body-xs); color: rgba(255, 255, 255, 0.55); }

  /* Scrim · atenúa la página con un panel abierto (va bajo la barra z-nav 100;
     los paneles viven dentro de la nav → quedan por encima del scrim). */
  .nav-scrim {
    position: fixed;
    inset: 0;
    top: calc(var(--nav-height) + env(safe-area-inset-top, 0px));
    background: rgba(0, 0, 0, 0.55);
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--dur-soft) var(--ease-out);
    z-index: 40;
  }
  body:has(.nav--mega .nav-item-has-sub:hover) .nav-scrim,
  body:has(.nav--mega .nav-item-has-sub:focus-within) .nav-scrim,
  body:has(.nav--mega .nav-item-has-sub.is-open) .nav-scrim {
    opacity: 1;
  }
}
@media (max-width: 1024px) {
  .nav-scrim { display: none; }   /* en móvil manda el drawer canónico */
}
@media (prefers-reduced-motion: reduce) {
  .nav--mega .nav-sub, .nav-scrim { transition: none; }
}

/* ── Buscador DESPLEGABLE de la topbar (estilo Apple) ──────────────────────
   Baja desde la barra al pulsar la lupa (`body.search-open`). No navega: el
   usuario escribe aquí; Enter / un quick link llevan a /search/?q=…
   Global (vive en el partial de la nav) → funciona en todas las páginas. */
.nav-search-panel {
  position: fixed;
  top: calc(var(--nav-height) + env(safe-area-inset-top, 0px));
  left: 0;
  right: 0;
  z-index: 90;                     /* bajo la barra (z-nav 100), sobre el scrim */
  background: var(--bg-bold);
  border-bottom: 1px solid var(--border-neutral-soft);
  box-shadow: var(--shadow-strong);
  transform: translateY(-10px);
  opacity: 0;
  visibility: hidden;
  transition:
    transform var(--dur-soft) var(--ease-out),
    opacity var(--dur-soft) var(--ease-out),
    visibility 0s linear var(--dur-soft);
}
body.search-open .nav-search-panel {
  transform: translateY(0);
  opacity: 1;
  visibility: visible;
  transition:
    transform var(--dur-soft) var(--ease-out),
    opacity var(--dur-soft) var(--ease-out);
}
.nav-search-panel__inner {
  padding-top: clamp(20px, 3vw, 32px);
  padding-bottom: clamp(20px, 3vw, 32px);
}
.nav-search-form {
  display: flex;
  align-items: center;
  gap: 12px;
  border-bottom: 1px solid var(--border-neutral-soft);
  padding-bottom: 14px;
}
.nav-search-form__icon { display: flex; color: var(--content-text-default-weak); flex: none; }
.nav-search-form__input {
  flex: 1 1 auto;
  min-width: 0;
  appearance: none;
  background: transparent;
  border: 0;
  color: var(--content-text-default);
  font-family: var(--font-sans);
  font-size: clamp(var(--text-heading-sm), 3vw, var(--text-heading-md));   /* grande, tipo Apple */
  font-weight: 300;
  padding: 6px 0;
}
.nav-search-form__input::placeholder { color: var(--content-text-default-weak); }
.nav-search-form__input:focus { outline: none; }
.nav-search-form__input::-webkit-search-cancel-button { display: none; }
.nav-search-form__close {
  appearance: none;
  background: transparent;
  border: 0;
  cursor: pointer;
  color: var(--content-text-default-weak);
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 40px;
  min-height: 40px;
  border-radius: var(--radius-full);
  flex: none;
  transition: color var(--dur-instant) var(--ease-out);
}
.nav-search-form__close:hover { color: var(--content-text-default); }
.nav-search-links { margin-top: clamp(16px, 2.5vw, 22px); }
.nav-search-links__label {
  font-family: var(--font-mono);
  font-size: var(--text-mono-sm);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--content-text-default-weak);
  margin: 0 0 12px;
}
.nav-search-links ul { list-style: none; display: flex; flex-wrap: wrap; gap: 10px; }
.nav-search-links a {
  display: inline-block;
  padding: 8px 14px;
  border-radius: var(--radius-full);
  border: 1px solid var(--border-neutral-soft);
  color: var(--content-text-default);
  font-size: var(--text-body-sm);
  text-decoration: none;
  transition: background var(--dur-instant) var(--ease-out), border-color var(--dur-instant) var(--ease-out);
}
.nav-search-links a:hover { background: rgba(255, 255, 255, 0.06); border-color: rgba(255, 255, 255, 0.3); }
.nav-search-scrim {
  position: fixed;
  inset: 0;
  top: calc(var(--nav-height) + env(safe-area-inset-top, 0px));
  background: rgba(0, 0, 0, 0.55);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  z-index: 80;
  transition: opacity var(--dur-soft) var(--ease-out), visibility 0s linear var(--dur-soft);
}
body.search-open .nav-search-scrim {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity var(--dur-soft) var(--ease-out);
}
@media (prefers-reduced-motion: reduce) {
  .nav-search-panel, .nav-search-scrim { transition: opacity var(--dur-instant) linear; }
  .nav-search-panel { transform: none; }
}

/* Variante MINIMAL del topbar · pantallas de foco (login, checkout…): se queda
   solo el logo + el selector de idioma, sin links, buscador, "Log in" ni
   hamburguesa. Sigue siendo el MISMO componente `.nav` (mismo fondo, alto,
   hide-on-scroll) — solo oculta el ruido. */
.nav--minimal .nav-links,
.nav--minimal .nav-search,
.nav--minimal .nav-login,
.nav--minimal .nav-toggle { display: none; }
/* Sin los `.nav-links`, el grid 3-col dejaría las acciones en el centro:
   con flex + space-between el logo va a la izquierda y las acciones a la derecha. */
.nav--minimal .nav-inner { display: flex; justify-content: space-between; align-items: center; }

/* =============================================================================
   CONTACTO DE TOPBAR · WhatsApp + teléfono + horario (`.v8-contact`)
   Componente del chrome que SOLO aparece en las páginas de Expeditions
   (decisión Irene + jefes · ago 2026). Va dentro de `.nav-actions`, antes del
   buscador. Su presencia se controla por markup (solo se incluye en Expeditions);
   este CSS solo lo estiliza. Icono monocromo blanco (sin verde de marca).
   El teléfono es PLACEHOLDER. Se oculta en móvil (≤720). Promovido desde
   dolomites v10/v11 a common.css para reutilizarlo. */
.v8-contact {
  position: relative;                            /* ancla del tooltip de horario */
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
  white-space: nowrap;
  color: var(--content-text-default);
  text-decoration: none;
}
.v8-contact__icon { display: block; width: 15px; height: 15px; flex-shrink: 0; }
.v8-contact__phone {
  font-family: var(--font-sans);
  font-size: var(--text-body-xs);
  font-weight: 500;
  line-height: 1;
  white-space: nowrap;
}
.v8-contact__hours {
  position: absolute;
  top: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%) translateY(-4px);
  padding: 5px 10px;
  background: var(--bg-neutral-default);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: var(--radius-s);
  color: var(--gray-white);
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs);
  line-height: 1;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.35);
  z-index: var(--z-overlay);
  transition: opacity var(--dur-instant) var(--ease-out),
    transform var(--dur-instant) var(--ease-out),
    visibility 0s linear var(--dur-instant);
}
.v8-contact:hover .v8-contact__hours,
.v8-contact:focus-visible .v8-contact__hours {
  opacity: 1;
  visibility: visible;
  transform: translateX(-50%) translateY(0);
  transition: opacity var(--dur-instant) var(--ease-out),
    transform var(--dur-instant) var(--ease-out);
}
/* En modo drawer (≤1024) el contacto del topbar se oculta: pasa DENTRO del
   menú hamburguesa (ver .nav-drawer-contact). */
@media (max-width: 1024px) {
  .v8-contact { display: none; }
}

/* Contacto DENTRO del drawer · solo Expeditions · solo modo hamburguesa (≤1024).
   Va lo PRIMERO del menú (que se vea antes que nada), separado por un filete
   abajo, con icono + teléfono + horario (el horario en línea: aquí hay sitio). */
.nav-drawer-contact { display: none; }
@media (max-width: 1024px) {
  .nav-drawer-contact {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 8px;
    padding: 4px 8px 16px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
    color: var(--content-text-default);
    text-decoration: none;
  }
  .nav-drawer-contact__icon { width: 22px; height: 22px; flex-shrink: 0; }
  .nav-drawer-contact__text { display: flex; flex-direction: column; gap: 3px; }
  .nav-drawer-contact__phone {
    font-family: var(--font-sans);
    font-size: var(--text-body-sm);
    font-weight: 500;
    line-height: 1.2;
  }
  .nav-drawer-contact__hours {
    font-family: var(--font-mono);
    font-size: var(--text-mono-xs);
    color: var(--content-text-default-weak);
    line-height: 1;
  }
}

@media (max-width: 1024px) {
  .nav-toggle {
    display: inline-flex;
    /* Las barras (22px) van centradas en el botón de 40px (touch target),
       lo que dejaba el icono a ~33px del borde mientras el logo está a 24px
       (asimetría · "mucho espacio a la derecha"). Con margin-right -9px el
       botón se acerca al borde y las barras quedan a 24px = mismo inset que
       el logo. El touch target de 40px se conserva (solapa el padding). */
    margin-right: -9px;
  }

  /* Móvil · vuelve a FLEX · los `.nav-links` pasan a `position: fixed`
     (panel desplegable, fuera de flujo), así que el grid 3-col del
     desktop no aplica · con flex + auto-margins el logo queda a la
     izquierda y las acciones + hamburguesa a la derecha. */
  .nav-inner {
    display: flex;
  }
  .nav-logo {
    margin-right: auto;
  }
  .nav-actions {
    margin-left: auto;
  }

  .nav-links {
    /* DRAWER LATERAL DERECHO · entra deslizando desde el borde derecho
       (no un desplegable centrado/a lo ancho). Ocupa desde debajo de la
       barra de nav hasta el fondo, con un ancho de panel cómodo dejando
       ver un poco de la página detrás. */
    position: fixed;
    /* OJO · el .nav tiene `transform: translateZ(0)` (antes era backdrop-filter),
       y eso lo convierte en el BLOQUE CONTENEDOR de este position:fixed (no el
       viewport). Por eso el panel se posiciona relativo a la BARRA NAV, no a la
       pantalla:
         · top: 100% → el borde inferior de la nav (soporta safe-area).
         · la altura la fijamos con dvh del viewport (no con bottom:0, que
           sería el fondo de la nav de 48px). Sin esto el panel salía de 48px.
       (Este era el bug de las "franjas"/panel pequeño: top+bottom+height se
       resolvían contra la nav de 48px, no contra la pantalla.) */
    top: 100%;
    right: 0;
    bottom: auto;
    left: auto;
    height: calc(100vh - var(--nav-height));
    height: calc(100svh - var(--nav-height));
    height: calc(100dvh - var(--nav-height));
    width: min(80vw, 320px);
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 1.5rem;
    background: var(--bg-neutral-bold);
    border-left: 1px solid rgba(255, 255, 255, 0.08);
    box-shadow: -12px 0 32px rgba(0, 0, 0, 0.4);
    overflow-y: auto;
    opacity: 0;
    pointer-events: none;
    transform: translateX(100%);
    transition: transform var(--dur-soft) var(--ease-out), opacity var(--dur-instant) var(--ease-out);
  }

  .nav.is-open .nav-links {
    /* Force override — la regla base de .nav-links (desktop) gana la
       cascada en algunos Chrome pese a menor especificidad · !important
       lo mantiene fiable. */
    transform: translateX(0) !important;
    opacity: 1 !important;
    pointer-events: auto !important;
  }

  .nav-links .nav-link {
    padding: 14px 8px;
    font-size: var(--text-body-md);
    line-height: 1.4;
  }

  .nav-links .nav-link.active::after {
    display: none;  /* underline doesn't make sense stacked */
  }

  /* Mobile: the submenu is ALWAYS expanded — no toggle, no confusion
     between "go to Academy" vs "open Academy". Every sub-item is a
     first-class link. The parent link still works ("Academy" goes to
     the index page, "Guides" goes directly to Guides). */
  .nav-item,
  .nav-item-has-sub {
    display: block;
    position: static;
  }

  .nav-item-has-sub > .nav-link {
    display: flex;
    justify-content: space-between;
    align-items: center;
  }

  /* Chevron de colapso (QA #69) · en móvil el grupo (Experiences,
     Academy) es un accordion: el chevron indica el estado y rota como
     en Dolomites. Desplegado por defecto → apunta ARRIBA (180°);
     colapsado → apunta abajo (0°, "hay más, toca para abrir").
     GATED tras `.js-nav-collapse` (clase que añade script.js): sin el
     JS del toggle el chevron sería una flecha muerta — p.ej. la página
     de Dolomites tiene los grupos pero carga map.js, no script.js, así
     que ahí el caret sigue oculto (comportamiento previo). */
  .nav-item-has-sub .nav-caret {
    display: none;
  }
  .js-nav-collapse .nav-item-has-sub .nav-caret {
    display: block;
    width: 14px;
    height: 14px;
    flex-shrink: 0;
    color: var(--content-text-default-weak);
    transform: rotate(180deg);
    transition: transform var(--dur-instant) var(--ease-out);
  }
  .js-nav-collapse .nav-item-has-sub.is-collapsed .nav-caret {
    transform: rotate(0deg);
  }

  .nav-sub {
    position: static;
    transform: none;
    opacity: 1;
    pointer-events: auto;
    min-width: 0;
    /* Más sangría · las subsecciones cuelgan claramente del padre (antes 20px).
       El texto del sub-item queda a ~40px del borde del panel vs ~8px del
       padre → jerarquía inequívoca sin necesidad de líneas divisorias. */
    padding: 0 0 8px 32px;
    background: transparent;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    gap: 0;
    margin-top: -4px;
    display: flex;
    flex-direction: column;
    /* Colapsable (QA #69) · desplegado por defecto; is-collapsed lo cierra.
       max-height generoso (cabe holgado el grupo más largo) → 0. */
    max-height: 320px;
    overflow: hidden;
    transition: max-height var(--dur-soft) var(--ease-out),
                opacity var(--dur-soft) var(--ease-out);
  }
  .nav-item-has-sub.is-collapsed .nav-sub {
    max-height: 0;
    opacity: 0;
    margin-top: 0;
    padding-bottom: 0;
  }

  .nav-sub-link {
    padding: 10px 8px;
  }

  .nav-sub-title {
    /* Smaller than top-level nav-link (17px) — stays clearly subordinate. */
    font-size: var(--text-body-sm);
    font-weight: 400;
    color: rgba(255, 255, 255, 0.82);
  }

  /* Description is desktop-only — mobile hides it to avoid making
     sub-items look more important than top-level parents. */
  .nav-sub-desc {
    display: none;
  }

  /* Keep nav-lang + search inline in the bar, just hide the big links.
     Position nav-actions right, hamburger at the very end. */
  .nav-actions {
    gap: 1rem;
  }
}

@media (max-width: 480px) {
  .nav-lang {
    display: none;  /* save horizontal room — available inside mobile panel if needed */
  }
}

@media (prefers-reduced-motion: reduce) {
  .nav-links,
  .nav-toggle-bar {
    transition: none !important;
  }
}

/* ════════════════════════════════════════════════════════════════════════════
   FOOTER
   ════════════════════════════════════════════════════════════════════════════ */

.footer-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2rem;
  padding: 2rem 0 2.5rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  margin-bottom: 2.5rem;
  flex-wrap: wrap;
}

.footer-trip-cta {
  height: 56px;
  padding: 0 28px;
  font-size: var(--text-body-md);
}

.footer-socials-block {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.footer-socials-label {
  margin: 0;
  font-size: var(--text-body-xs);
  font-weight: 600;
  letter-spacing: 2.5px;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.78);
}

.footer-socials {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-left: -10px;
}

.footer-social {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-s);
  color: rgba(255, 255, 255, 0.65);
  transition: background var(--dur-instant) var(--ease-out),
    color var(--dur-instant) var(--ease-out),
    transform var(--dur-instant) var(--ease-out);
}

.footer-social[data-tooltip]::after {
  content: attr(data-tooltip);
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%) translateY(4px);
  padding: 5px 10px;
  background: var(--bg-neutral-default);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: var(--radius-s);
  color: var(--gray-white);
  font-size: var(--text-body-xs);
  font-weight: 500;
  letter-spacing: 0.2px;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--dur-instant) var(--ease-out), transform var(--dur-instant) var(--ease-out);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.35);
  z-index: var(--z-overlay);
}

.footer-social:hover::after {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

.footer-social:focus-visible::after {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

.footer-social svg {
  width: 20px;
  height: 20px;
  display: block;
}

.footer-social:hover {
  background: rgba(255, 255, 255, 0.08);
  color: var(--gray-white);
}

.footer-social:focus-visible {
  background: rgba(255, 255, 255, 0.08);
  color: var(--gray-white);
  outline: 2px solid var(--content-link-default);
  outline-offset: 2px;
}

.footer {
  /* Deepest band of the page — solid `--bg-bold` (= --g-black) anchors
     the bottom edge against the slightly-lifted final CTA gradient. */
  background: var(--bg-bold);
  color: rgba(255, 255, 255, 0.78);
  padding: 3.5rem 1.5rem 0;
}

.footer-inner {
  max-width: var(--max-wide);
  margin: 0 auto;
}

.footer-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 2rem;
  margin-bottom: 2.5rem;
}

.footer-col h5 {
  font-size: var(--text-body-xs);
  font-weight: 700;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--content-text-default);
  margin-bottom: 1.1rem;
}

.footer-col ul {
  list-style: none;
}

.footer-col li {
  margin-bottom: 0.55rem;
}

.footer-col a {
  color: rgba(255, 255, 255, 0.78);
  font-size: var(--text-body-sm);
  font-weight: 400;
  transition: color var(--dur-instant);
}

.footer-col a:hover {
  color: var(--content-link-default);   /* amarillo · acento interactivo del DS */
}

.footer-col a:active {
  color: var(--yellow-6);               /* clic/pressed · amarillo más profundo (= pressed de los botones) */
}

/* Item de footer cuya página aún no existe: inerte + atenuado + badge "Soon"
   (mismo criterio que la nav). Es un <span>, no un <a> → nunca es enlace muerto. */
.footer-col .footer-soon {
  display: inline-flex;
  align-items: baseline;
  color: rgba(255, 255, 255, 0.4);
  font-size: var(--text-body-sm);
  font-weight: 400;
  pointer-events: none;
  cursor: default;
}

.footer-bottom {
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  padding: 1.5rem;
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 1rem;
  background: var(--bg-bold);   /* MISMO fondo que el footer (antes --bg-neutral-bold → franja más clara) */
  margin: 0 -1.5rem;
}

.footer-bottom span {
  font-size: var(--text-body-xs);
  color: rgba(255, 255, 255, 0.78);
}

.footer-bottom a {
  font-size: var(--text-body-xs);
  color: rgba(255, 255, 255, 0.78);
}

.footer-bottom-links {
  display: flex;
  gap: 1.5rem;
}

@media (prefers-reduced-motion: reduce) {
  .footer-social[data-tooltip]::after { transition: opacity var(--dur-instant); }
}

@media (max-width: 720px) {
  .footer-top {
    justify-content: center;
    text-align: center;
    flex-direction: column;
    gap: 2rem;
  }
  .footer-socials-block { align-items: center; }
  .footer-socials { justify-content: center; margin-left: 0; }
}


/* ════════════════════════════════════════════════════════════════════════════
   HERO HELPERS — shared across all landing heroes
   ════════════════════════════════════════════════════════════════════════════ */

/* `.hero-scroll-hint` — small "scroll for more" affordance
   Used at the bottom of any hero or first-viewport zone (home hero,
   premium-pricing __hero, future landings). Component lives entirely
   here so every consumer renders identical typography + animation. */
.hero-scroll-hint {
  position: absolute;
  bottom: 2rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 4;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  color: rgba(255, 255, 255, 0.7);
  text-transform: uppercase;
  animation:
    scrollHintFade 1.5s var(--ease-out) var(--dur-glide) both,
    scrollHintPulse 2.4s var(--ease-out) 2.4s infinite,
    scrollHintBounce 2.6s var(--ease-soft) 2.4s infinite;
  pointer-events: none;
}

/* The label inside — mono firma técnica (no editorial), small.
   These overrides used to live in `mockup/style.css` (home-specific);
   promoted to the component 2026-05 so every page gets the same font. */
.hero-scroll-hint span {
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs);     /* 10px */
  font-weight: 400;
  letter-spacing: 0.3em;
  font-feature-settings: 'ss01' off;
}

.hero-scroll-hint svg {
  width: 20px;
  height: 20px;
}

/* Mobile · subir el hint para que su rebote no pise el photo-credit
   (que se ancla abajo). */
@media (max-width: 720px) {
  .hero-scroll-hint { bottom: 3.75rem; }
}

.hero-scroll-hint.hidden {
  opacity: 0;
  transition: opacity var(--dur-soft) var(--ease-out);
  animation: none;
}


/* ════════════════════════════════════════════════════════════════════════════
   CAPTURED PLANS PATTERN — shared before/after carousel used by home's
   Captured Plans section and Experiences' True Stories.
   ════════════════════════════════════════════════════════════════════════════ */

/* ════════════════════════════════════════════════════════════════════════════
   BEFORE/AFTER SLIDER
   ════════════════════════════════════════════════════════════════════════════ */
.ba-layer {
  position: absolute;
  inset: 0;
  overflow: hidden;
}

.ba-layer-shot {
  z-index: 1;
}

.ba-layer-plan {
  z-index: 2;
  clip-path: inset(0 50% 0 0);
  transition: clip-path 0s;
}

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

.ba-layer-plan::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(160deg, color-mix(in srgb, var(--yellow-5) 8%, transparent), rgba(14, 21, 35, 0.95) 50%),
    linear-gradient(45deg, #0d1117, #161b22, #1f2a3a);
  background-size: cover;
}

.ba-layer-plan .ba-content {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  /* Placeholder hasta que llegue la foto real del case — el 30% de alpha
     NO pasa AA como texto; no llevar a producción tal cual. */
  color: color-mix(in srgb, var(--yellow-5) 30%, transparent);
  font-size: var(--text-body-sm);
  letter-spacing: 3px;
  text-transform: uppercase;
  font-weight: 600;
  z-index: 1;
}

.ba-layer-shot::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(160deg, #1a1a2e, #16213e, #0f3460);
}

.ba-layer-shot .ba-content {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  color: rgba(254, 217, 37, 0.3);
  font-size: var(--text-body-sm);
  letter-spacing: 3px;
  text-transform: uppercase;
  font-weight: 600;
}

.ba-label {
  position: absolute;
  top: 16px;
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs);
  font-weight: 600;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: white;
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: var(--glass-filter-strong);
  -webkit-backdrop-filter: var(--glass-filter-strong);
  padding: 6px 12px;
  border-radius: var(--radius-full);
  z-index: 4;
  pointer-events: none;
}

.ba-label-plan {
  left: 16px;
  color: rgba(255, 255, 255, 0.92);
  border: 1px solid rgba(255, 255, 255, 0.12);
}

.ba-label-shot {
  right: 16px;
  color: rgba(255, 255, 255, 0.92);
  border: 1px solid rgba(255, 255, 255, 0.12);
}

.ba-handle {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 48px;
  margin-left: -24px;
  z-index: 3;
  cursor: ew-resize;
  display: grid;
  place-items: center;
  pointer-events: none;
}

.ba-handle::before {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 2px;
  margin-left: -1px;
  background: var(--gray-white);
  box-shadow: 0 0 1px rgba(0, 0, 0, 0.4);
}

.ba-handle-knob {
  width: 28px;
  height: 44px;
  border-radius: var(--radius-full);
  background: var(--gray-white);
  display: grid;
  place-items: center;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15),
    0 6px 18px rgba(0, 0, 0, 0.35);
  pointer-events: auto;
  cursor: ew-resize;
  /* El knob reclama el gesto táctil (drag horizontal) · sin esto el
     navegador se lleva el touch para hacer scroll y el slider no se
     puede arrastrar en mobile. Solo afecta al knob (target pequeño),
     así que el swipe del carrusel en el resto del slider sigue libre. */
  touch-action: none;
  transition: transform var(--dur-instant) var(--ease-soft),
    background var(--dur-instant) ease;
  position: relative;
  z-index: 1;
  border: 0;
}

.ba-slider:hover .ba-handle-knob {
  background: var(--gray-white);
  transform: scale(1.06);
}

.ba-slider.dragging .ba-handle-knob {
  transform: scale(1.1);
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2),
    0 10px 24px rgba(0, 0, 0, 0.45);
}

.ba-handle-knob:focus-visible {
  outline: 2px solid rgba(255, 255, 255, 0.9);
  outline-offset: 3px;
}

.ba-handle-knob svg {
  width: 14px;
  height: 14px;
  color: #1a1a1c;
  opacity: 0.85;
}

/* (CSS knob-bounce removed — the JS nudgeHint now drives both the
   handle position AND the clip-path together so the line moves
   with the knob from the very first hint.) */

.ba-slider {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius-s);
  overflow: hidden;
  user-select: none;
  touch-action: pan-y;
  background: linear-gradient(160deg, #0d1117, #161b22, #1f2a3a);
  cursor: ew-resize;
  box-shadow: var(--shadow-md), inset 0 1px 0 rgba(255, 255, 255, 0.08);
}
/* Mobile · pequeño margen lateral (12px) para que el slider no vaya a
   sangre contra los bordes del viewport. Componente base → lo heredan
   todas las instancias del before/after. */
@media (max-width: 720px) {
  .ba-slider {
    width: calc(100% - 24px);
    margin-inline: 12px;
  }
}




/* ════════════════════════════════════════════════════════════════════════════
   CAPTURED PLANS CAROUSEL
   ════════════════════════════════════════════════════════════════════════════ */

.plan-case-title {
  font-size: var(--text-heading-md);
  line-height: 38px;
  font-weight: 500;
  margin-bottom: 0.5rem;
}

.plan-case-meta {
  font-size: var(--text-body-sm);
  color: var(--content-text-default-weak);
  margin-bottom: 1.5rem;
  letter-spacing: 1px;
}

/* (.plan-author absorbed into .author-credit__name in common.css) */

.plans-carousel {
  max-width: var(--max-wide);
  margin: 0 auto;
  position: relative;
}

.plans-viewport {
  display: flex;
  align-items: center;
  gap: 1.5rem;
}

.plans-track-wrapper {
  overflow: hidden;
  border-radius: var(--radius-m);
  flex: 1;
  min-width: 0;
}

.plans-arrow {
  flex: 0 0 56px;
  width: 56px;
  height: 56px;
  border-radius: var(--radius-circle);
  background: var(--bg-tertiary-default);
  border: 1px solid var(--border-neutral-soft);
  display: grid;
  place-items: center;
  cursor: pointer;
  transition: background-color var(--dur-instant) var(--ease-out),
              color var(--dur-instant) var(--ease-out),
              border-color var(--dur-instant) var(--ease-out),
              transform var(--dur-instant) var(--ease-out);
  color: var(--content-text-default);
}

.plans-arrow:disabled {
  opacity: 0.25;
  cursor: not-allowed;
  pointer-events: none;
}

.plans-arrow svg {
  width: 22px;
  height: 22px;
}

.plans-arrow:hover:not(:disabled) {
  background: var(--gray-white);
  color: var(--gray-9);
  border-color: var(--gray-white);
  transform: scale(1.08);
}

@media (min-width: 1025px) {
  .plan-slide-inner {
    /* Visual-dominant layout — the before/after IS the proof; give it
       ~65% of the width and let the story breathe as a sidebar. */
    grid-template-columns: 2fr 1fr;
    align-items: center;
    gap: 3rem;
  }
}

@media (min-width: 720px) {
  .plan-quote { font-size: var(--text-body-lg); line-height: 30px; }
}

@media (max-width: 720px) {
  .plans-viewport {
    gap: 0.5rem;
  }
  .plans-arrow {
    flex-basis: 40px;
    width: 40px;
    height: 40px;
  }
  .plans-arrow svg {
    width: 18px;
    height: 18px;
  }
}


/* ════════════════════════════════════════════════════════════════════════════
   CAPTURED PLANS (STORY SLIDES)
   ════════════════════════════════════════════════════════════════════════════ */

.captured-plans .reveal {
  opacity: 1;
  transform: none;
  transition: none;
}

.captured-plans .plans-track {
  display: flex;
  transition: transform var(--dur-soft) var(--ease-out);
  will-change: transform;
}

.captured-plans .plan-slide {
  /* Each slide is exactly the track-wrapper width so transform
     translateX(-N * 100%) lands cleanly without leaking the next
     case on the right at wide breakpoints. The whole carousel is
     already constrained by .plans-carousel { max-width }. */
  flex: 0 0 100%;
  min-width: 0;
  padding: 0 1rem;
  display: grid;
  grid-template-rows: auto auto;
  gap: 2.25rem;
  margin: 0 auto;
}

/* Columna del caso · UNA sola anchura compartida por foto e historia
   (regla 2026-07): el slider cede ancho (y por aspect-ratio, alto) en
   viewports bajos para que foto + texto quepan en pantalla con ~16px
   de aire arriba y abajo. Presupuesto: 100svh − ~300px (16×2 de aire
   + gap 36 + story más alta ~225px). Suelo de 560px para que la foto
   nunca quede tímida; techo 100% (móvil y pantallas altas, como antes).
   El texto usa la MISMA variable — sus columnas no se separan más que
   el ancho de la foto. */
.captured-plans .plan-slide {
  --case-col: min(100%, max(560px, calc((100vh - 300px) * 16 / 9)));
  --case-col: min(100%, max(560px, calc((100svh - 300px) * 16 / 9)));
}

.captured-plans .plan-slide .ba-slider {
  width: var(--case-col);
  max-width: none;
  margin-inline: auto;
  /* Frame the slider: a thin outer stroke + a strong inset corner vignette
     so the photo reads as its own object. */
  border: 1px solid rgba(255, 255, 255, 0.10);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.08),
    inset 0 0 140px 20px rgba(0, 0, 0, 0.55),
    0 0 0 1px rgba(0, 0, 0, 0.4);
}

/* Story block: 2-col grid — col 1 stacks the head (eyebrow+title+meta) and
   the attribution (anchored bottom); col 2 holds the pull quote spanning
   both rows so it visually balances the column on the left. This avoids
   the previous overlap where the attribution sat in row 1 col 2 and the
   quote in row 2 col 2 (the layout broke when titles wrapped). */
/* Plan story = 2-col grid: left col is .plan-story-head (a flex column
   that holds eyebrow + title + meta + attribution as siblings — true
   "auto layout" with one consistent gap between every line); right
   col is the pull quote. */
.captured-plans .plan-story {
  /* Mismo carril que la foto (--case-col) · las dos columnas del
     relato quedan alineadas con los bordes del slider, no con el
     contenedor de sección (2026-07). */
  width: var(--case-col, 100%);
  margin: 0 auto;
  padding: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  column-gap: 3rem;
  /* Both columns share the same vertical centre — when the quote is
     longer or shorter than the head, neither column is anchored to
     the top of the row. */
  align-items: center;
  text-align: left;
}

.captured-plans .plan-story .plan-story-head {
  grid-column: 1;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  align-items: flex-start;
}

.captured-plans .plan-story .plan-case-eyebrow {
  margin-bottom: 0;
  font-size: var(--text-body-md);
}

.captured-plans .plan-story .plan-case-title {
  font-size: clamp(var(--text-heading-sm), 3vw, var(--text-heading-md));
  line-height: 1.2;
  margin-bottom: 0;
}

.captured-plans .plan-story .plan-case-meta {
  margin-top: 0;
  margin-bottom: 0;
  font-size: var(--text-body-sm);
}

/* The author-credit sits in the same flex column as the head meta
   lines and inherits its 8px gap. Extra 8px on top so the total gap
   between the date and the author block is 16px — a small breath
   that separates "the moment" (case + title + date) from "the maker"
   (avatar + name + tier). */
.captured-plans .plan-story .author-credit {
  margin: 0.5rem 0 0;
}

.captured-plans .plan-story .plan-quote {
  margin: 0;
  padding: 0;
  border-left: 0;
  max-width: none;
  text-align: left;
  grid-column: 2;
  align-self: center;
  /* Same body-paragraph styling as .product-copy .pitch-body — same
     clamp ramp + tight line-height + weight 300 + subtle colour. */
  font-size: var(--text-editorial-body);
  line-height: 1.2;
  font-weight: 300;
  color: var(--content-text-subtitle);
}

/* Quote-mark SVG component — drop-in glyph that any quote/blockquote
   can use. The viewBox is tightened to 7 7 13 9 (matches the visible
   path bounds) so the SVG bounding box has zero extra padding around
   the glyph: the left edge aligns flush with the quote paragraph. */
.quote-mark {
  display: block;
  width: 28px;
  /* 13:9 aspect → height = 28 * 9 / 13 ≈ 19.4px */
  height: 19.4px;
  color: var(--yellow-5);
  margin-bottom: 0.75rem;
}

/* Position-only override — visuals come from the shared .pager
   component in common.css. */
.captured-plans .plans-pager {
  margin-top: clamp(20px, 3vw, 36px);
}

.plan-case-eyebrow {
  color: var(--content-text-subtitle);
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: var(--text-body-sm);
  letter-spacing: 2px;
  text-transform: uppercase;
  margin-bottom: 1rem;
  display: block;
}

/* (.plan-tier was a duplicate of the unified .badge above — its second
   definition was retired 2026-04. The legacy alias near .badge keeps
   existing markup working until the HTML migrates to .badge.) */

.plan-quote {
  font-size: var(--text-body-md);
  line-height: var(--lh-body);
  font-weight: 300;
  font-style: normal;
  color: var(--content-text-subtitle);
  margin-bottom: 1.5rem;
  padding-left: 1.25rem;
  border-left: 3px solid var(--content-link-default);
}

/* (.plan-attribution / .plan-attribution-text / .plan-avatar absorbed
   into .author-credit / .author-credit__body / .author-credit__avatar.) */
.author-credit__body .plan-tier {
  margin-left: 0;
  vertical-align: 0;
}

.captured-plans {
  padding: 100px 0;
}


/* El relato se apila a 1-col SOLO en móvil (≤720). En tablet (721-1024, p.ej.
   iPad en vertical) se mantienen las 2 columnas (case-head | quote) como en
   landscape/desktop — la foto va arriba y el texto a 2-col debajo. */
@media (max-width: 720px) {
  .captured-plans .plan-story {
    grid-template-columns: 1fr;
    row-gap: 1rem;
    text-align: left;
  }
  .captured-plans .plan-story .plan-story-head {
    grid-column: 1;
  }
  .captured-plans .plan-story .plan-quote {
    grid-column: 1;
    margin-top: 0.25rem;
  }
}

/* ── Mobile: native horizontal scroll-snap, no arrows ───────────────────
   The transform-based slider is replaced by native overflow-scroll. The
   arrows would be cramped at this size and add noise — we hide them and
   let the dots act as both indicator and quick jump. JS detects this
   breakpoint and switches modes. */
@media (max-width: 720px) {
  .captured-plans .plans-viewport {
    gap: 0;
    align-items: stretch;
  }
  .captured-plans .plans-arrow {
    display: none;
  }
  .captured-plans .plans-track-wrapper {
    border-radius: 0;
    overflow-x: auto;
    overflow-y: visible;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    /* Escape el padding lateral del .container (var(--gutter)) para que las
       IMÁGENES (.ba-slider) puedan ir full-bleed. El TEXTO de cada slide
       (.plan-story) recupera el gutter con su propio padding. */
    margin: 0 calc(-1 * var(--gutter));
    padding: 0;
  }
  .captured-plans .plans-track-wrapper::-webkit-scrollbar {
    display: none;
  }
  .captured-plans .plans-track {
    transition: none;
    transform: none !important;
    will-change: auto;
  }
  .captured-plans .plan-slide {
    scroll-snap-align: center;
    scroll-snap-stop: always;
    /* Sin padding horizontal aquí · la IMAGEN va edge-to-edge.
       El TEXTO recupera 32px abajo con su propio padding. */
    padding: 0;
    /* Mobile: tighter gap; dots return to normal flow below the story. */
    gap: 1.75rem;
  }
  /* Slider · margen lateral = gutter (antes iba full-bleed / 12px) · esta
     regla, más específica (0,3,0), pisa a `.captured-plans .plan-slide .ba-slider`
     que fijaba width:var(--case-col) + margin-inline:auto (= 100% en móvil).
     Sin esto el margen del componente base no llega a la home. */
  .captured-plans .plan-slide .ba-slider {
    width: calc(100% - 2 * var(--gutter));
    margin-inline: var(--gutter);
    /* Móvil · de 16/9 (muy apaisado, se veía pequeño en vertical) a CUADRADO ·
       aprovecha mejor la pantalla del teléfono. Para "más vertical" aún:
       4/5 o 3/4. */
    aspect-ratio: 1 / 1;
  }
  /* Captured Plans · iteración móvil (2026-07):
     · alineado a la IZQUIERDA (coincide con desktop · centrado se veía
       flotante y costaba leer un bloque caso/título/fecha/quote/autor).
     · orden caso → título → fecha → QUOTE → AUTOR · se logra con
       display:contents en el head (promueve eyebrow/título/meta/autor a
       hermanos de la quote) + `order` · SOLO móvil, DOM intacto → desktop
       no cambia.
     · quote DESACOPLADA del token editorial y un paso más pequeña (había
       crecido al subir --text-editorial-body en móvil; una cita no es un
       párrafo editorial).
     · nombre de autor a SANS (el mono topa en 16px) para que tenga presencia. */
  .captured-plans .plan-slide .plan-story {
    /* El texto ocupa EXACTAMENTE el ancho de la imagen del slider: la foto
       (.ba-slider) va al gutter (margin-inline: var(--gutter)), así que el
       texto usa el mismo padding y sus bordes coinciden con los de la foto. */
    padding-left: var(--gutter);
    padding-right: var(--gutter);
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    text-align: left;
    gap: 0.5rem;
  }
  .captured-plans .plan-slide .plan-story .plan-story-head {
    display: contents;
  }
  .captured-plans .plan-slide .plan-story .plan-case-eyebrow { order: 1; }
  .captured-plans .plan-slide .plan-story .plan-case-title   { order: 2; }
  .captured-plans .plan-slide .plan-story .plan-case-meta    { order: 3; }
  .captured-plans .plan-slide .plan-story .plan-quote {
    order: 4;
    text-align: left;
    margin-top: 0.75rem;
    font-size: var(--text-body-md);
  }
  .captured-plans .plan-slide .plan-story .quote-mark {
    margin-left: 0;
    margin-right: 0;
  }
  .captured-plans .plan-slide .plan-story .author-credit {
    order: 5;
    justify-content: flex-start;
    margin-top: 0.75rem;
  }
  .captured-plans .plans-dots {
    position: static;
    top: auto;
    margin-top: 1.75rem;
  }
}

@media (max-width: 720px) {
  .phone-mock {
    width: 220px;
  }
  .pm-shoot-time {
    font-size: var(--text-heading-md);
  }
}


/* ════════════════════════════════════════════════════════════════════════════
   SR-ONLY — visually-hidden utility for screen-reader-only labels/text.
   Accessibility staple (form labels, aria headings). Promovido al DS
   2026-07: antes solo vivía en missions/style.css; ahora cualquier página
   con `<label class="sr-only">` (Coming Soon, Missions) lo hereda de aquí.
   ════════════════════════════════════════════════════════════════════════════ */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}


/* ════════════════════════════════════════════════════════════════════════════
   FORM INPUTS — autofill reset (dark surfaces)
   Chrome/Safari repintan el campo con fondo claro + texto oscuro al
   autocompletar (sugerencia de email, etc.), rompiendo los inputs oscuros del
   sistema. Mantiene el campo TRANSPARENTE (delay ~infinito del background de
   autofill) y el texto/caret en blanco. Fix a nivel DS · si se crea una nueva
   clase de input oscuro, añadirla a esta lista — NO re-parchear por página.
   ════════════════════════════════════════════════════════════════════════════ */
.input:-webkit-autofill,
.input:-webkit-autofill:hover,
.input:-webkit-autofill:focus,
.input:-webkit-autofill:active,
.mis-input:-webkit-autofill,
.mis-input:-webkit-autofill:hover,
.mis-input:-webkit-autofill:focus,
.mis-input:-webkit-autofill:active,
.cs-input:-webkit-autofill,
.cs-input:-webkit-autofill:hover,
.cs-input:-webkit-autofill:focus,
.cs-input:-webkit-autofill:active {
  -webkit-text-fill-color: var(--content-text-default);
  caret-color: var(--content-text-default);
  transition: background-color 9999s ease-in-out 0s;
  /* Tipografía del valor ya CONFIRMADO (al elegir la sugerencia). Nota: el
     PREVIEW del autofill (al hacer hover sobre una sugerencia, antes de
     elegirla) lo pinta Chrome en una capa propia con su fuente por defecto y
     NO es alcanzable por CSS — ese "salto" de fuente en el hover es una
     limitación del navegador, no del DS. Inputs oscuros: sans · body-sm · 300. */
  font-family: var(--font-sans);
  font-size: var(--text-body-sm);
  font-weight: 300;
}


/* ════════════════════════════════════════════════════════════════════════════
   SKIP LINK — keyboard-only "Skip to content" jumping past the nav.
   Visually hidden until focused.
   ════════════════════════════════════════════════════════════════════════════ */
.skip-link {
  position: absolute;
  top: 0;
  left: 0;
  z-index: var(--z-toast);
  padding: 0.75rem 1.25rem;
  background: var(--yellow-5);
  color: var(--gray-9);
  font-family: var(--font-sans);
  font-size: var(--text-body-sm);
  font-weight: 600;
  text-decoration: none;
  border-radius: 0 0 var(--radius-s) 0;
  transform: translateY(-110%);
  transition: transform var(--dur-instant) var(--ease-out);
}
.skip-link:focus-visible {
  transform: translateY(0);
  outline: none;
}


/* ════════════════════════════════════════════════════════════════════════════
   CTA ROW — shared horizontal row of CTAs (wraps on mobile)
   Used by hero, App / Premium pitch, The Loop, Experiences, final CTA.
   ════════════════════════════════════════════════════════════════════════════ */
.cta-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  flex-wrap: wrap;
}
.cta-row--start { justify-content: flex-start; }


/* ════════════════════════════════════════════════════════════════════════════
   AUTHOR CREDIT — shared "avatar + name [+ tier badge]" component
   Used by Captured Plans (with .plan-tier badge) and Experiences
   (just the name). 40px grayscale avatar, mono 16px caption, 1rem gap.
   ════════════════════════════════════════════════════════════════════════════ */
.author-credit {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
  /* Avatar height drives line-height so the text vertically matches
     the avatar mass when on a single line. */
  --_avatar-h: var(--avatar-md);
  line-height: var(--_avatar-h);
  font-family: var(--font-mono);
  font-size: var(--text-mono-xl);
  font-weight: 400;
  color: var(--gray-white);
}
.author-credit__avatar {
  width: var(--avatar-md);
  height: var(--avatar-md);
  border-radius: var(--radius-circle);
  object-fit: cover;
  filter: grayscale(1) contrast(1.05) brightness(0.9);
  border: 1px solid rgba(255, 255, 255, 0.18);
  flex-shrink: 0;
}
/* Body wraps name + optional tier badge so a long badge can drop to a
   second line, anchored flush-left under the name. */
.author-credit__body {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.45rem 0.85rem;
  line-height: inherit;
  min-height: var(--_avatar-h);
}
.author-credit__name { color: var(--gray-white); }


/* ════════════════════════════════════════════════════════════════════════════
   APP ICON — iOS-style squircle + glass highlight
   Reusable "app icon" chrome: rounded-square mask (radius-l ≈ iOS
   squircle at this scale), strong shadow (home-screen elevation), and
   an elliptical specular highlight (::after) that simulates the glass
   reflection of classic iOS icons.

   Usage:
     <span class="app-icon" style="width: clamp(64px, 6vw, 84px)">
       <img src="..." alt="">
     </span>

   Size and margins are set by the instance (page CSS or inline). This
   class only provides the chrome. Used in: app hero, app pricing card,
   premium apps-compare. Promoted to DS in 2026-05 (was duplicated in
   3 page CSS files: `.app-hero__app-icon`, `.app-pricing__app-icon`,
   `.apps-compare__icon-wrap`).
   ════════════════════════════════════════════════════════════════════════════ */
.app-icon {
  position: relative;
  display: inline-block;
  border-radius: var(--radius-l);
  overflow: hidden;
  box-shadow: var(--shadow-strong);
}

.app-icon::after {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(
    ellipse 130% 65% at 50% -8%,
    rgba(255, 255, 255, 0.42) 0%,
    rgba(255, 255, 255, 0.10) 45%,
    rgba(255, 255, 255, 0) 70%
  );
  pointer-events: none;
  border-radius: inherit;
}

.app-icon > img {
  display: block;
  width: 100%;
  height: auto;
}


/* ════════════════════════════════════════════════════════════════════════════
   PAGER — shared paginator (prev arrow · counter · next arrow)
   Used by Plan Every Shot, Captured Plans and Experiences. Two size
   modifiers: --lg (56px arrows, default) and --md (44px arrows, used
   when overlaid on a photo).
   ════════════════════════════════════════════════════════════════════════════ */
.pager {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(16px, 2.5vw, 28px);
}

.pager__arrow {
  width: 56px;
  height: 56px;
  border-radius: var(--radius-circle);
  background: rgba(0, 0, 0, 0.55);
  border: 1px solid rgba(255, 255, 255, 0.12);
  color: rgba(255, 255, 255, 0.9);
  display: grid;
  place-items: center;
  cursor: pointer;
  margin: 0;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  transition: background-color var(--dur-instant) var(--ease-out),
              border-color var(--dur-instant) var(--ease-out),
              color var(--dur-instant) var(--ease-out);
  -webkit-tap-highlight-color: transparent;
}
.pager__arrow:hover:not(:disabled) {
  background: rgba(0, 0, 0, 0.75);
  border-color: rgba(255, 255, 255, 0.24);
  color: var(--gray-white);
}
.pager__arrow:disabled {
  opacity: 0.3;
  cursor: not-allowed;
  pointer-events: none;
}
.pager__arrow svg { width: 24px; height: 24px; display: block; }

.pager__counter {
  font-family: var(--font-mono);
  font-size: var(--text-mono-lg);
  letter-spacing: 0.08em;
  color: var(--gray-white);
  display: inline-flex;
  align-items: baseline;
  gap: 0.4ch;
  min-width: 6ch;
  justify-content: center;
  font-variant-numeric: tabular-nums;
}
.pager__sep   { color: rgba(255, 255, 255, 0.35); }
.pager__total { color: rgba(255, 255, 255, 0.55); }

/* --md modifier: 44px arrows for overlays inside a photo. */
.pager--md { gap: clamp(12px, 1.6vw, 20px); }
.pager--md .pager__arrow { width: 44px; height: 44px; }
.pager--md .pager__arrow svg { width: 20px; height: 20px; }
.pager--md .pager__counter { text-shadow: 0 1px 4px rgba(0, 0, 0, 0.7); }

@media (max-width: 720px) {
  .pager__arrow { width: 44px; height: 44px; }
  .pager__arrow svg { width: 20px; height: 20px; }
}


/* ════════════════════════════════════════════════════════════════════════════
   PRODUCT SECTIONS — shared 2-col grid for App / Premium / The Tool
   Used by home (App, Premium) and Experiences (The Tool).
   ════════════════════════════════════════════════════════════════════════════ */

.store-price {
  text-align: center;
  font-size: var(--text-body-sm);
  font-weight: 500;
  line-height: 20px;
  color: var(--content-text-subtitle);
}

/* ════════════════════════════════════════════════════════════════════════════
   PRODUCT SECTIONS — THE APP + PREMIUM
   ════════════════════════════════════════════════════════════════════════════ */

.product-section {
  padding: clamp(64px, 7vw, 96px) 0;
  overflow: hidden;
}

.product-grid--reverse .product-copy {
  order: 2;
}

/* ════════════════════════════════════════════════════════════════════════════
   .editorial-stack  ·  patrón canónico de cabecera editorial
   Title → Subtitle → Rule → Pitch-body. La receta tipográfica que se repite
   en hero de premium-pricing, hero de premium, sección Premium de la home,
   The Loop, statement slides… cualquier sitio donde introducimos un bloque
   con el lenguaje editorial de la marca.

   Centrado por defecto (el uso más común). Modificador `--start` para
   layouts de columna (grids 2-col). El título conserva su tamaño global
   .section-title — si una página necesita un display más grande (heroes
   tipo PhotoPills Premium · Beta), bumpea el font-size en su CSS local.

   Tamaños y pesos:
     .section-title    → globl (.section-title), weight 600
     .section-subtitle → clamp(heading-sm, 3vw, heading-md) · weight 300 · lh 1.125
     .section-rule     → 64×2px gray-6 centrado
     .pitch-body       → clamp(body, 1.7vw, body-lg) · weight 300 · lh 1.2
   ════════════════════════════════════════════════════════════════════════════ */
.editorial-stack {
  max-width: 720px;
  margin: 0 auto;
  text-align: center;
}

.editorial-stack .section-title {
  margin: 0 0 1.25rem;
}

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

.editorial-stack .section-rule {
  margin: 0 auto 2rem;
}

.editorial-stack .pitch-body {
  font-size: var(--text-editorial-body);
  line-height: 1.2;
  font-weight: 300;
  text-align: center;
  margin: 0 auto;
}

/* Modificador --start: alinea a la izquierda. Para columnas de product
   grids (`.product-section--app`, `.product-section--premium`) y bloques
   editoriales con visual al lado.

   Coexiste con `.product-copy` (legacy de la home), que aplica los mismos
   overrides + un max-width de 48ch para encajar en el grid 2-col. Si vas
   a crear un bloque editorial en columna nuevo, usa `.editorial-stack
   .editorial-stack--start` para no inventar otra vez. */
.editorial-stack--start {
  text-align: left;
}
.editorial-stack--start .section-subtitle,
.editorial-stack--start .section-rule,
.editorial-stack--start .pitch-body {
  text-align: left;
  margin-left: 0;
  margin-right: 0;
}


/* ════════════════════════════════════════════════════════════════════════════
   .tablist  ·  segmented control reusable
   Pill-shape track con varios items dentro · el activo destaca con fondo
   amarillo (--color-action-default). Hover: oscurece el track sin
   reemplazar el activo. Tipografía Public Sans (sans), igual que .btn —
   no usamos mono aquí porque actúa como control interactivo, no como
   metadata.

   Markup:
     <div class="tablist" role="tablist">
       <button class="tablist__item is-active" role="tab" aria-selected="true">A</button>
       <button class="tablist__item" role="tab" aria-selected="false">B</button>
     </div>

   El comportamiento (swap del contenido al pulsar, auto-advance) lo
   gestiona JS en cada página.
   ════════════════════════════════════════════════════════════════════════════ */
.tablist {
  display: inline-flex;
  padding: 4px;
  background: var(--gradient-subtle);
  border: 1px solid var(--border-neutral-soft);
  border-radius: var(--radius-full);
  gap: 2px;
}

.tablist__item {
  appearance: none;
  background: transparent;
  border: 0;
  color: var(--content-text-default-weak);
  font-family: var(--font-sans);
  font-size: var(--text-body-sm);
  font-weight: 500;
  letter-spacing: 0;
  padding: 10px 18px;
  border-radius: var(--radius-full);
  cursor: pointer;
  transition:
    color var(--dur-instant) var(--ease-out),
    background var(--dur-instant) var(--ease-out);
}

.tablist__item:hover {
  color: var(--content-text-default);
  background: rgba(255, 255, 255, 0.04);
}

.tablist__item.is-active,
.tablist__item[aria-selected="true"] {
  color: var(--bg-bold);
  background: var(--color-action-default);
}

/* La tab ACTIVA se queda en el amarillo vivo también al hover. NO oscurecer con
   `--color-action-bold`: sobre amarillo, "bold" (#988216) vira a mostaza oliva y
   la tab parece deshabilitada (bug recurrente de tabs — oct 2026). Una tab ya
   seleccionada no necesita feedback de hover. */
.tablist__item.is-active:hover,
.tablist__item[aria-selected="true"]:hover {
  background: var(--color-action-default);
}


.product-grid--reverse .laptop-showcase {
  order: 1;
}

.product-copy {
  max-width: 48ch;
}

.product-copy .section-title {
  text-align: left;
  margin-bottom: 1.25rem;
}

.product-copy .pitch-cta {
  /* Visuals from .cta-row + .cta-row--start; only the section-specific
     bottom margin lives here. */
  margin: 0 0 1rem;
}

.product-copy .store-price {
  text-align: left;
  margin: 0;
}

.product-copy > .section-rule {
  margin: 0 0 2rem;
}

.pitch-cta {
  /* Visuals from .cta-row in common.css; just the top spacing here. */
  margin-top: 2.5rem;
}

.pm-chip-active {
  color: var(--gray-9);
}

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

.product-section--app .product-copy .section-subtitle {
  font-weight: 300;
}

.pm-icon {
  color: var(--yellow-5);
}

.pm-ar-delta {
  color: var(--yellow-5);
}

.pm-shoot-time {
  color: var(--yellow-5);
}

.section-lead {
  line-height: var(--lh-body);
}

.pitch-body {
  font-size: clamp(var(--text-body-lg), 2.2vw, var(--text-lead));
  line-height: var(--lh-body);
  font-weight: 300;
  color: var(--content-text-subtitle);
}

.product-copy .pitch-body {
  font-size: var(--text-editorial-body);
  line-height: 1.2;
  font-weight: 300;
  text-align: left;
  margin: 0 0 2rem;
}


.product-grid {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
  align-items: center;
  gap: clamp(48px, 6vw, 96px);
}

.product-grid--reverse {
  grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
}

@media (max-width: 1024px) {
  .product-grid {
    /* minmax(0, 1fr) — NO `1fr` a secas (QA #72): un `1fr` crece hasta el
       min-content de su contenido, y el showcase de móviles de The App
       (~354px, dos teléfonos) forzaba la columna a 354 en un área de
       311 → arrastraba la columna de copy y el párrafo se CORTABA por la
       derecha ("...imagined" / "Exact" recortados). minmax(0,...) fija la
       pista al área disponible (igual que el grid de escritorio). */
    grid-template-columns: minmax(0, 1fr);
    gap: 3rem;
    min-height: auto;
  }
  .product-grid--reverse .product-copy { order: 1; }
  .product-grid--reverse .laptop-showcase { order: 2; }
  .product-copy { max-width: 100%; text-align: center; }
  .product-copy .eyebrow,
  .product-copy .section-title,
  .product-copy .section-subtitle,
  .product-copy .pitch-body,
  .product-copy .store-price { text-align: center; }
  .product-copy .pitch-cta { justify-content: center; }
  .product-copy > .section-rule { margin-left: auto; margin-right: auto; }
  .app-showcase { justify-content: center; gap: 12px; }
  .laptop-showcase { justify-content: center; }
  .laptop-mockup {
    transform: none;
    /* Capeamos el mockup al 88% del column track para que la
       .laptop-base (que es 112% del mockup con margin-left -6%)
       NO sobresalga del track ni del .container. Sin esto, el body
       overflow-x: hidden recorta el base por la derecha en viewports
       estrechos. 88% × 1.12 = 98.56% del track → base cabe entera. */
    width: 88%;
    max-width: 480px;
    margin-left: 0;
  }
}

/* ════════════════════════════════════════════════════════════════════════════
   STATEMENT SLIDE
   ════════════════════════════════════════════════════════════════════════════ */

.statement-slide {
  position: relative;
  background: var(--bg-neutral-bold, #010B18);
  min-height: 100svh;
  padding: clamp(64px, 7vw, 96px) var(--gutter);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  text-align: center;
}

.statement-inner {
  position: relative;
  z-index: 2;
  max-width: 1100px;
  margin: 0 auto;
  width: 100%;
}

.statement-logo {
  display: inline-block;
  margin-bottom: 2.5rem;
  opacity: 0;
  transform: translateY(16px) scale(0.95);
  filter: blur(8px);
  transition: opacity var(--dur-glide) var(--ease-soft),
    transform var(--dur-glide) var(--ease-soft),
    filter var(--dur-glide) var(--ease-soft);
}

.statement-slide.is-visible .statement-logo {
  opacity: 1;
  transform: translateY(0) scale(1);
  filter: blur(0);
}

/* Shared hero tagline — used by home and landing heroes. Top of the
   weight hierarchy (500 > section-title 400 > statement-headline 300).
   Overridable per page if a softer tone is needed (experiences: 300). */
.hero-tagline {
  font-family: var(--font-sans);
  font-weight: 500;
  letter-spacing: var(--tracking-display);
  line-height: var(--lh-display);
  font-feature-settings: 'ss01' on;
  font-size: clamp(var(--text-heading-xl), 8vw, var(--text-display-lg));
  color: var(--gray-white);
  margin: 0 0 2rem;
}

.statement-headline {
  font-family: var(--font-sans);
  font-weight: 300;
  letter-spacing: -0.03em;
  line-height: 1.05;
  font-feature-settings: 'ss01' on;
  font-size: clamp(var(--text-heading-lg), 6.5vw, var(--text-display-lg));
  color: var(--gray-white);
  margin: 0;
}

.statement-line {
  display: block;
}

.statement-line-2 {
  margin-top: 0.5em;
}

.statement-headline .word {
  display: inline-block;
  opacity: 0;
  transform: translateY(18px);
  filter: blur(10px);
  transition: opacity var(--dur-glide) var(--ease-soft),
    transform var(--dur-glide) var(--ease-soft),
    filter var(--dur-glide) var(--ease-soft);
}

.statement-slide.is-visible .word {
  opacity: 1;
  transform: translateY(0);
  filter: blur(0);
}

/* Per-word transition-delay is assigned by script.js at runtime so the
   stagger works for any language / word count. See: "Statement headline
   dynamic delays" in script.js. */

@media (prefers-reduced-motion: reduce) {
  .statement-logo,
  .statement-headline .word {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
    transition: none !important;
  }
}


/* Bridge variant — a standalone transition statement between two sections,
   set against pure black so it reads as the dramatic pause-point of the page. */
.statement-slide--bridge {
  background: var(--gray-black);
}

.statement-slide--bridge .statement-inner {
  max-width: var(--max-wide);
}


/* =============================================================================
   LEAFLET · CONTROLES UNIFICADOS DEL DS

   Patrón compartido para CUALQUIER mapa Leaflet de la web (Missions, plan
   maps de expedición, futuros mapas editoriales). Antes vivía duplicado
   en `missions/style.css` y `dolomites-068-oct-2027/style.css` — al
   unificarlo aquí garantizamos que todos los mapas hablen el mismo idioma
   visual (zoom como tab capsule `.btn-dark`, atribución mono discreta,
   contenedor con bg-bold).

   Si una página necesita variaciones (e.g. atribución full-width con
   text-shadow en Missions, o tunning específico de tiles), las hace
   localmente sobre estos defaults. NO redefinir el control de zoom por
   página — debe ser idéntico en toda la web.
   ============================================================================= */

/* Contenedor base · fondo bold del DS + fuente sans para overlays. */
.leaflet-container {
  background: var(--bg-bold);
  font-family: var(--font-sans);
}

/* Controles de zoom (+/−) · diseño TAB CAPSULE estilo `.btn-dark`
   (gray-11 + hover flip a blanco). Iconos SVG inyectados por JS
   (los caracteres tipográficos `+` y `−` no se centran consistentemente
   entre fuentes — el SVG centra por viewBox).

   ATENCIÓN: Leaflet aplica border-radius asimétrico a :first-child y
   :last-child con especificidad (0,2,2). Para ganarle usamos selectores
   con la clase específica de cada botón (.leaflet-control-zoom-in /
   .leaflet-control-zoom-out → 0,2,1 → empata pero gana por orden de
   carga, ya que `common.css` siempre va DESPUÉS de `leaflet.css`). */
.leaflet-control-zoom {
  border: 0;
  box-shadow: var(--shadow-strong);
  background: transparent;
  margin: clamp(12px, 1.6vw, 18px);
  border-radius: var(--radius-full);
  overflow: hidden;
}
.leaflet-bar a.leaflet-control-zoom-in,
.leaflet-bar a.leaflet-control-zoom-out {
  background: var(--gray-11);
  color: var(--gray-white);
  border: 0;
  width: 36px;
  height: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  box-sizing: border-box;
  border-radius: 0;
  transition: background var(--dur-instant) var(--ease-out),
              color var(--dur-instant) var(--ease-out),
              opacity var(--dur-instant) var(--ease-out);
}
.leaflet-bar a.leaflet-control-zoom-in {
  border-bottom: 1px solid var(--border-neutral-soft);
}
.leaflet-bar a.leaflet-control-zoom-in:hover,
.leaflet-bar a.leaflet-control-zoom-out:hover {
  background: var(--gray-white);
  color: var(--gray-9);
}
.leaflet-bar a.leaflet-control-zoom-in:active,
.leaflet-bar a.leaflet-control-zoom-out:active {
  background: var(--gray-1);
  color: var(--gray-9);
}
/* Disabled · atenua al llegar al zoom mínimo/máximo. NO se oculta — el
   affordance siempre visible permite al usuario entender los límites. */
.leaflet-bar a.leaflet-control-zoom-in.leaflet-disabled,
.leaflet-bar a.leaflet-control-zoom-out.leaflet-disabled {
  opacity: 0.4;
  cursor: not-allowed;
  pointer-events: none;
}
.leaflet-bar a.leaflet-control-zoom-in.leaflet-disabled:hover,
.leaflet-bar a.leaflet-control-zoom-out.leaflet-disabled:hover {
  background: var(--gray-11);
  color: var(--gray-white);
}

/* Atribución · estilo discreto mono del DS. Por defecto Leaflet pone
   bg blanco con texto oscuro — lo invertimos. Variaciones (e.g. Missions
   con text-shadow + full-width) se hacen localmente sobre este default. */
.leaflet-control-attribution {
  background: rgba(0, 0, 0, 0.45);
  color: rgba(255, 255, 255, 0.6);
  font-family: var(--font-mono);
  font-size: var(--text-mono-xs);
  letter-spacing: 0.04em;
  padding: 4px 10px;
}
.leaflet-control-attribution a {
  color: rgba(255, 255, 255, 0.75);
}
.leaflet-control-attribution a:hover {
  color: var(--content-text-highlight);
}


/* =============================================================================
   COOKIE / CMP · banner de consentimiento + panel de preferencias granular
   Chrome global (LSSI 22.2 · "Aceptar" y "Rechazar" al mismo nivel, sin casillas
   no esenciales premarcadas). Se muestra en la 1ª visita (JS · sin consentimiento
   guardado) y se reabre desde "Cookie settings" del footer.
   ========================================================================== */
.cookie-banner {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: var(--z-toast);
  padding: 16px var(--gutter);
  padding-bottom: calc(16px + env(safe-area-inset-bottom, 0px));
  background: var(--bg-bold);   /* negro puro */
  border-top: 1px solid var(--border-neutral-soft);
  box-shadow: 0 -12px 32px rgba(0, 0, 0, 0.4);
}
.cookie-banner[hidden] { display: none; }
.cookie-banner__inner {
  max-width: var(--max-wide);
  margin: 0 auto;
  display: flex;
  align-items: center;
  gap: clamp(16px, 3vw, 40px);
  flex-wrap: wrap;
}
.cookie-banner__text { flex: 1 1 320px; min-width: 0; }
.cookie-banner__title {
  font-family: var(--font-sans);
  font-size: var(--text-body-sm);
  font-weight: 600;
  color: var(--content-text-default);
  margin: 0 0 4px;
}
.cookie-banner__body {
  font-family: var(--font-sans);
  font-size: var(--text-body-xs);
  line-height: 1.45;
  color: var(--content-text-default-weak);
  margin: 0;
  max-width: 68ch;
}
.cookie-banner__body a { color: var(--content-link-default); text-decoration: underline; text-underline-offset: 2px; }
.cookie-banner__actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; flex-shrink: 0; }

/* Panel de preferencias (modal) */
.cookie-prefs { position: fixed; inset: 0; z-index: calc(var(--z-toast) + 1); }
.cookie-prefs[hidden] { display: none; }
.cookie-prefs__scrim { position: absolute; inset: 0; background: rgba(0, 0, 0, 0.6); }
.cookie-prefs__panel {
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: min(92vw, 520px);
  max-height: min(86vh, 640px);
  overflow-y: auto;
  background: var(--bg-neutral-default);
  border: 1px solid var(--border-neutral-soft);
  border-radius: var(--radius-l);
  box-shadow: var(--shadow-strong);
  padding: clamp(20px, 3vw, 32px);
}
.cookie-prefs__title {
  font-family: var(--font-sans);
  font-size: var(--text-heading-sm);
  font-weight: 600;
  color: var(--content-text-default);
  margin: 0 0 8px;
}
.cookie-prefs__intro {
  font-size: var(--text-body-sm);
  color: var(--content-text-default-weak);
  line-height: 1.5;
  margin: 0 0 20px;
}
.cookie-prefs__list { list-style: none; margin: 0 0 20px; padding: 0; }
.cookie-cat { padding: 14px 0; border-top: 1px solid var(--border-neutral-soft); }
.cookie-cat:first-child { border-top: 0; }
.cookie-cat__head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.cookie-cat__name { font-family: var(--font-sans); font-size: var(--text-body-sm); font-weight: 600; color: var(--content-text-default); }
.cookie-cat__always { font-family: var(--font-mono); font-size: var(--text-mono-xs); text-transform: uppercase; letter-spacing: .08em; color: var(--content-text-default-weak); }
.cookie-cat__desc { font-size: var(--text-body-xs); color: var(--content-text-default-weak); line-height: 1.45; margin: 6px 0 0; max-width: 52ch; }
.cookie-prefs__actions { display: flex; gap: 8px; justify-content: flex-end; flex-wrap: wrap; }

/* Interruptor (switch) */
.cookie-switch { position: relative; display: inline-block; width: 44px; height: 26px; flex-shrink: 0; }
.cookie-switch input { position: absolute; inset: 0; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; }
.cookie-switch__track {
  position: absolute; inset: 0;
  background: var(--gray-7);
  border-radius: var(--radius-full);
  transition: background var(--dur-instant) var(--ease-out);
}
.cookie-switch__track::after {
  content: ''; position: absolute; top: 3px; left: 3px;
  width: 20px; height: 20px; border-radius: 50%;
  background: var(--gray-white);
  transition: transform var(--dur-instant) var(--ease-out);
}
.cookie-switch input:checked + .cookie-switch__track { background: var(--yellow-5); }
.cookie-switch input:checked + .cookie-switch__track::after { transform: translateX(18px); }
.cookie-switch input:focus-visible + .cookie-switch__track { outline: 2px solid var(--yellow-5); outline-offset: 2px; }

@media (max-width: 720px) {
  .cookie-banner__actions { width: 100%; justify-content: center; }
}
@media (prefers-reduced-motion: reduce) {
  .cookie-switch__track, .cookie-switch__track::after { transition: none; }
}
