/* =========================================================================
   WuolahPass landing — Design System

   Tokens: color, type scale (fluid, Inter), spacing (8pt grid), radii and
   containers/breakpoints. Components below consume these tokens instead of
   one-off pixel values, so the whole page scales coherently from small
   phones to desktop.

   Breakpoints: >=640px tablet, >=1024px desktop.
   ========================================================================= */

:root {
  /* ---------- Color ---------- */
  --wp-bg: #0f182a;
  --wp-hero-bg: #1f2b45;
  --wp-stroke: #273757;
  --wp-stroke-soft: rgba(91, 117, 192, 0.35);

  --wp-text: #ffffff;
  --wp-text-soft: #cdd4e3;
  --wp-text-muted: #aab2c7;

  --wp-ink: #111111;
  --wp-ink-soft: #5b5b5b;

  --wp-blue: #145bec;
  --wp-blue-hover: #0f4bc7;
  --wp-yellow: #ffc712;
  --wp-green: #22c55e;
  --wp-green-strong: #219653;
  --wp-green-soft: #cff89e;
  /* Darkened from the original #ff1b1b: white-on-red only hit 3.9:1
     (fails WCAG AA 4.5:1 at this text size). This shade clears 5.4:1. */
  --wp-red: #d21414;

  /* ---------- Typography ---------- */
  --wp-font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial,
    sans-serif;

  --text-2xs: 0.8125rem; /* 13px — fine print */
  --text-xs: 0.875rem; /* 14px — captions, labels */
  --text-sm: 0.9375rem; /* 15px */
  --text-base: 1rem; /* 16px — body */
  --text-md: 1.125rem; /* 18px — lead paragraphs */
  --text-lg: 1.25rem; /* 20px */

  /* Headings scale fluidly between mobile and desktop instead of jumping
     at breakpoints. H1 (hero) is deliberately the largest text on the
     page — the previous build had generic section titles bigger than
     the hero headline, which inverted the hierarchy. */
  --text-h3: clamp(1.25rem, 1.15rem + 0.5vw, 1.5rem); /* 20 → 24px */
  --text-h2: clamp(1.75rem, 1.5rem + 1.1vw, 2.25rem); /* 28 → 36px */
  --text-h1: clamp(2rem, 1.55rem + 2vw, 3rem); /* 32 → 48px */

  --leading-tight: 1.15;
  --leading-snug: 1.3;
  --leading-normal: 1.5;

  /* ---------- Spacing (8pt grid) ---------- */
  --space-1: 0.25rem; /* 4px */
  --space-2: 0.5rem; /* 8px */
  --space-3: 0.75rem; /* 12px */
  --space-4: 1rem; /* 16px */
  --space-5: 1.5rem; /* 24px */
  --space-6: 2rem; /* 32px */
  --space-7: 3rem; /* 48px */
  --space-8: 4rem; /* 64px */
  --space-9: 6rem; /* 96px */

  /* ---------- Radii ---------- */
  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-pill: 999px;

  /* ---------- Containers ---------- */
  --container-sm: 30rem; /* 480px */
  --container-md: 45rem; /* 720px */
  --container-lg: 70rem; /* 1120px */
  --container-pad: 1.375rem; /* 22px */

  /* ---------- Interactive sizing ---------- */
  --tap-min: 2.75rem; /* 44px — minimum touch target */
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

/* El atributo `hidden` se apoya en `[hidden] { display: none }` de la hoja del
   navegador, que pierde contra cualquier regla de clase que fije `display`
   (un `display: flex`, por ejemplo). Sin esto, ocultar algo desde JS con
   `.hidden = true` no tiene efecto en esos elementos. */
[hidden] {
  display: none !important;
}

html {
  font-size: 100%;
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 6rem;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
}

body {
  margin: 0;
  background: var(--wp-bg);
  color: var(--wp-text);
  font-family: var(--wp-font);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img {
  max-width: 100%;
  display: block;
}

h1,
h2,
h3,
p,
dl {
  margin: 0;
}

ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

a {
  color: inherit;
}

.u-visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  background: var(--wp-blue);
  color: #fff;
  padding: var(--space-3) var(--space-4);
  border-radius: 0 0 var(--radius-sm) 0;
  font-size: var(--text-xs);
  font-weight: 700;
  text-decoration: none;
}

.skip-link:focus {
  left: 0;
}

:focus-visible {
  outline: 2px solid var(--wp-yellow);
  outline-offset: 2px;
}

/* ---------- Layout primitives ----------
   Sections keep a full-bleed background band; `.l-container` is what
   constrains and centers the actual content, and grows at each
   breakpoint instead of being capped at mobile width everywhere. */

.l-container {
  width: 100%;
  max-width: var(--container-sm);
  margin-inline: auto;
  padding-inline: var(--container-pad);
}

@media (min-width: 640px) {
  .l-container {
    max-width: var(--container-md);
    padding-inline: var(--space-7);
  }
}

@media (min-width: 1024px) {
  .l-container {
    padding-inline: var(--space-6);
  }
}

.section {
  border-top: 1px solid var(--wp-stroke);
  padding-top: var(--space-9);
  padding-bottom: var(--space-9);
}

.section--pitch {
  border-top: 0;
}

.section__title {
  font-size: var(--text-h2);
  line-height: var(--leading-tight);
  font-weight: 800;
  margin-bottom: var(--space-8);
}

/* ---------- Top nav ---------- */

.top-nav {
  position: sticky;
  top: 0;
  z-index: 30;
  background: var(--wp-hero-bg);
  border-bottom: 1px solid transparent;
  transition: box-shadow 0.2s ease, border-color 0.2s ease;
}

.top-nav.is-scrolled {
  border-bottom-color: var(--wp-stroke-soft);
  box-shadow: 0 6px 18px rgba(2, 9, 27, 0.45);
}

.top-nav__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding-block: var(--space-4);
}

.top-nav__logo {
  font-size: var(--text-base);
  font-weight: 800;
  white-space: nowrap;
}

.top-nav__cta {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--tap-min);
  padding-inline: var(--space-4);
  border-radius: var(--radius-sm);
  background: var(--wp-blue);
  color: #fff;
  font-size: var(--text-xs);
  font-weight: 700;
  line-height: 1;
  text-decoration: none;
  transition: background-color 0.2s ease;
}

.top-nav__cta:hover {
  background: var(--wp-blue-hover);
}

/* ---------- Hero ---------- */

.hero {
  background: var(--wp-hero-bg);
  /* padding (not a child margin) so the hero background stays flush
     against the sticky nav */
  padding-top: var(--space-5);
  padding-bottom: var(--space-8);
}

.hero__title {
  font-size: var(--text-h1);
  line-height: var(--leading-tight);
  font-weight: 800;
  max-width: 22ch;
}

.hero__title-accent {
  color: var(--wp-yellow);
}

.hero__badge {
  display: block;
  width: fit-content;
  margin-top: var(--space-3);
  vertical-align: 1px;
  transform: rotate(2.3deg);
  background: var(--wp-red);
  color: #fff;
  border-radius: 7px;
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-lg);
  line-height: 1.2;
  font-weight: 800;
  white-space: nowrap;
}


.hero__lead {
  margin-top: var(--space-6);
  font-size: var(--text-md);
  line-height: var(--leading-snug);
  font-style: italic;
  font-weight: 400;
  max-width: 40ch;
}

.hero__lead strong {
  font-weight: 700;
}

.hero__lead--last {
  margin-top: var(--space-4);
}

/* ---------- Pitch ---------- */

.pitch__partner {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  font-size: var(--text-2xs);
  font-weight: 700;
  color: var(--wp-text-soft);
}

.pitch__partner-logo {
  width: 100px;
  height: auto;
}

.pitch__title {
  margin-top: var(--space-4);
  font-size: var(--text-h2);
  line-height: var(--leading-tight);
  font-weight: 800;
  max-width: 24ch;
}

.u-green {
  color: var(--wp-green);
}

.u-underline {
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 2px;
}

.pitch__claim {
  margin-top: var(--space-5);
  font-size: var(--text-md);
  line-height: var(--leading-snug);
  font-weight: 700;
}

.pitch__claim-soft {
  display: block;
  color: var(--wp-text-soft);
  font-size: var(--text-base);
  font-weight: 400;
}

.bullets {
  display: grid;
  gap: var(--space-5);
  margin-top: var(--space-7);
  max-width: 40ch;
}

.bullets__item {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  font-size: var(--text-base);
  line-height: var(--leading-snug);
  color: var(--wp-text-soft)
}

.bullets__text strong {
  color:#fff
}

.bullets__icon {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  margin-top: -2px;
  border-radius: 50%;
  background: var(--wp-blue);
  color: #fff;
}

/* Font Awesome's exported SVGs use fill="currentColor" on the path, so this
   sizes whatever gets pasted inside .bullets__icon without touching color. */
.bullets__icon svg {
  width: 20px;
  height: 20px;
  fill: currentColor;
}

.cta-block__intro {
  margin-top: var(--space-8);
  font-size: var(--text-xs);
  line-height: var(--leading-normal);
  max-width: 40ch;
}

@media (min-width: 640px) {
  .cta-block__intro {
    max-width: none;
    white-space: nowrap;
    font-weight:600
  }
}

.cta-block__note {
  margin-top: var(--space-2);
  font-size: var(--text-2xs);
  line-height: var(--leading-normal);
  color: var(--wp-text-muted);
}

.cta-block__note strong {
  font-weight: 700;
}

/* ---------- Primary button ---------- */

.btn-primary {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: var(--tap-min);
  margin-top: var(--space-4);
  padding: var(--space-2) var(--space-4);
  border: 0;
  border-radius: var(--radius-sm);
  background: var(--wp-blue);
  color: #fff;
  font-family: inherit;
  font-size: var(--text-base);
  font-weight: 700;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.2s ease, transform 0.15s ease;
}

.btn-primary:hover {
  background: var(--wp-blue-hover);
}

.btn-primary:active {
  transform: translateY(1px);
}

/* ---------- Cómo funciona (3 slides con scroll-snap) ----------
   The stage is pinned while three empty spacers supply the scroll distance
   and the snap stops. `.how-track` is added by script.js only when the
   effect can actually run, so the no-JS and reduced-motion paths fall back
   to three stacked steps with no pinning and no snapping. */

/* --- Fallback layout (no JS / reduced motion): plain stacked steps --- */

.how-stage__inner > .how-meter {
  margin-top: var(--space-6);
}

.how-panels {
  display: grid;
  gap: var(--space-6);
  margin-top: var(--space-7);
}

.how-dots {
  display: none;
}

.section--how .section__title {
  padding-top: var(--space-7);
}

/* --- Enhanced layout: pinned stage + snap slides --- */

.how-track {
  position: relative;
}

.how-track {
  /* Explicit height = three slides. The stage is the only in-flow child, so
     its sticky range runs from the track top to (track height - stage height)
     — i.e. it releases exactly as the third slide ends, instead of running on
     over the following sections. */
  height: 300svh;
}

.how-track .how-stage {
  position: sticky;
  top: 0;
  /* svh, not vh: mobile browser chrome resizing vh mid-scroll makes a pinned
     stage jump. svh stays put. */
  height: 100svh;
  display: grid;
  align-content: center;
  overflow: hidden;
}

.how-track .section__title {
  padding-top: 0;
}

.how-track .how-panels {
  /* every panel shares one grid cell, so the box is as tall as the tallest
     one and swapping panels never shifts the layout */
  display: grid;
  margin-top: var(--space-6);
}

.how-track .how-panel {
  grid-area: 1 / 1;
  opacity: 0;
  transform: translateY(14px);
  /* Leaving: quick and accelerating. Short on purpose, so the outgoing text
     has cleared before the next arrives — sharing one grid cell, a symmetric
     cross-fade leaves both legible at once and the copy turns to mush. */
  transition: opacity 150ms ease-in, transform 150ms ease-in;
  pointer-events: none;
}

.how-track .how-panel.is-active {
  opacity: 1;
  transform: none;
  pointer-events: auto;
  /* Arriving: slower, decelerating, held back until the exit has finished. */
  transition: opacity 320ms ease-out 160ms,
    transform 460ms cubic-bezier(0.22, 0.75, 0.3, 1) 160ms;
}

.how-track .how-dots {
  display: flex;
  gap: var(--space-3);
  margin-top: var(--space-7);
}

/* Out of flow so they add no height of their own; they exist only to place
   the snap stops at 0 / 100 / 200svh inside the track. */
.how-track .how-snap {
  position: absolute;
  left: 0;
  right: 0;
  height: 100svh;
  scroll-snap-align: start;
  scroll-snap-stop: always;
  pointer-events: none;
}

.how-track .how-snap[data-snap="0"] { top: 0; }
.how-track .how-snap[data-snap="1"] { top: 100svh; }
.how-track .how-snap[data-snap="2"] { top: 200svh; }

/* --- Meter head (label + big number) --- */

.how-meter {
  margin-top: var(--space-5);
}

.how-meter__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
}

.how-meter__label {
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--wp-text-muted);
}

.how-meter__value {
  font-size: clamp(2rem, 1.5rem + 2.2vw, 3rem);
  line-height: 1;
  font-weight: 800;
  color: var(--wp-green);
  font-variant-numeric: tabular-nums;
}

/* --- The diagram ----------------------------------------------------------
   One 0-100 rail that builds across the three steps, driven by
   [data-viz-step] on the wrapper:
     0 · your level on the scale
     1 · + the gap the plan covers
     2 · + that gap split into checkpoints
   The fallback (no JS / reduced motion) uses step 2, the complete picture. */

.how-viz {
  margin-top: var(--space-4);
}

.how-viz__axis {
  display: flex;
  justify-content: space-between;
  margin-bottom: var(--space-2);
  font-size: var(--text-2xs);
  font-weight: 600;
  color: var(--wp-text-muted);
}

.how-viz__axis-end {
  color: var(--wp-green);
}

.how-viz__rail {
  display: flex;
  gap: 4px;
  height: 52px;
  padding: 4px;
  border: 1px solid var(--wp-stroke);
  border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, 0.03);
}

/* What you already know: fixed at 35% of the scale. */
.how-viz__known {
  flex: 0 0 35%;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-pill);
  background: linear-gradient(90deg, #f97316, #fb923c);
  color: #24160a;
  font-size: var(--text-xs);
  font-weight: 800;
}

/* The remaining 65%: empty on step 0, the plan from step 1 on. */
.how-viz__plan {
  position: relative;
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-pill);
  border: 2px dashed var(--wp-stroke);
  background: transparent;
  /* revealed left-to-right: clip-path keeps the label undistorted, unlike
     animating width or scaleX */
  transition: background-color 420ms ease-out, border-color 420ms ease-out;
}

.how-viz[data-viz-step="1"] .how-viz__plan,
.how-viz[data-viz-step="2"] .how-viz__plan {
  border-style: solid;
  border-color: var(--wp-green);
  background: rgba(34, 197, 94, 0.16);
}

.how-viz__plan-label {
  position: absolute;
  font-size: var(--text-xs);
  font-weight: 700;
  color: #fff;
  white-space: nowrap;
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 380ms ease-out, transform 380ms ease-out;
}

.how-viz[data-viz-step="1"] .how-viz__plan-label {
  opacity: 1;
  transform: none;
}

/* Step 2: the plan splits into checkpoints. */
.how-viz__chunks {
  display: flex;
  gap: 4px;
  width: 100%;
  height: 100%;
  padding: 3px;
}

.how-viz__chunk {
  flex: 1 1 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-pill);
  background: #fff;
  color: var(--wp-green-strong);
  opacity: 0;
  transform: scale(0.72);
  transition: opacity 300ms ease-out, transform 380ms cubic-bezier(0.22, 0.75, 0.3, 1);
}

.how-viz[data-viz-step="2"] .how-viz__chunk {
  opacity: 1;
  transform: none;
}

/* staggered so they read as "one after another", not "all at once" */
.how-viz[data-viz-step="2"] .how-viz__chunk:nth-child(1) { transition-delay: 60ms; }
.how-viz[data-viz-step="2"] .how-viz__chunk:nth-child(2) { transition-delay: 170ms; }
.how-viz[data-viz-step="2"] .how-viz__chunk:nth-child(3) { transition-delay: 280ms; }
.how-viz[data-viz-step="2"] .how-viz__chunk:nth-child(4) { transition-delay: 390ms; }

/* Points at the boundary between "what you know" and "what is missing". */
.how-viz__marker {
  position: relative;
  margin-top: var(--space-2);
  height: 1.25rem;
  opacity: 0;
  transition: opacity 380ms ease-out;
}

.how-viz[data-viz-step="0"] .how-viz__marker {
  opacity: 1;
}

.how-viz__marker span {
  position: absolute;
  left: 35%;
  transform: translateX(-50%);
  white-space: nowrap;
  font-size: var(--text-2xs);
  font-weight: 700;
  color: #fb923c;
}

.how-viz__marker span::before {
  content: "";
  position: absolute;
  left: 50%;
  top: -7px;
  width: 2px;
  height: 5px;
  background: #fb923c;
}

@media (min-width: 640px) {
  .how-viz__rail {
    height: 60px;
  }

  .how-viz__known,
  .how-viz__plan-label {
    font-size: var(--text-sm);
  }
}

/* --- Panels --- */

.how-panel__num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  margin-bottom: var(--space-3);
  border-radius: 50%;
  background: var(--wp-blue);
  color: #fff;
  font-size: var(--text-xs);
  font-weight: 700;
}

.how-panel__title {
  font-size: var(--text-h3);
  line-height: var(--leading-snug);
  font-weight: 800;
}

.how-panel__text {
  margin-top: var(--space-2);
  max-width: 46ch;
  color: var(--wp-text-soft);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
}

/* --- Dots --- */

.how-dots {
  list-style: none;
  padding: 0;
}

.how-dot {
  /* 10px visual dot inside a 44px hit area, per the touch-target minimum */
  display: grid;
  place-content: center;
  width: var(--tap-min);
  height: var(--tap-min);
  margin: calc(var(--tap-min) / -4) calc(var(--tap-min) / -4);
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}

.how-dot::before {
  content: "";
  display: block;
  width: 10px;
  height: 10px;
  border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, 0.25);
  transition: width 320ms ease-out, background-color 320ms ease-out;
}

.how-dot[aria-current="true"]::before {
  width: 28px;
  background: var(--wp-green);
}

@media (prefers-reduced-motion: reduce) {
  .how-panel,
  .how-dot::before,
  .how-viz__plan,
  .how-viz__plan-label,
  .how-viz__chunk,
  .how-viz__marker {
    transition: none;
  }
}

/* ---------- Testimonials marquee ----------
   Auto-scrolling row of tweet screenshots. Each card's width comes from its
   own image (height:100% / width:auto) rather than a fixed box, since
   different tweets crop to very different aspect ratios — so the loop can't
   rely on "N equal cards" arithmetic like a naive version would.

   Instead the track holds two .marquee__set groups with IDENTICAL content
   (same images, same order); each set carries its own trailing gap as a
   margin, so the two groups are always exactly the same width as each
   other no matter what the images measure. Animating the track by exactly
   -50% then always lands it on a pixel-perfect repeat of frame zero — the
   loop seam works regardless of how many tweets get added later, as long
   as both .marquee__set lists stay in sync. */

.marquee {
  margin-top: var(--space-8);
  padding-block: var(--space-2);
  overflow: hidden;
}

.marquee__track {
  display: flex;
  width: max-content;
  animation: marquee-scroll 36s linear infinite;
}

.marquee__set {
  flex: 0 0 auto;
  display: flex;
  gap: var(--space-4);
  margin-right: var(--space-4);
}

.marquee__card {
  flex: 0 0 auto;
  height: 130px;
  border-radius: var(--radius-md);
  overflow: hidden;
  background: #fff;
  box-shadow: 0 10px 24px rgba(2, 9, 27, 0.4);
}

.marquee__card img {
  display: block;
  height: 100%;
  width: auto;
}

@keyframes marquee-scroll {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(-50%);
  }
}

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

@media (min-width: 640px) {
  .marquee__card {
    height: 160px;
  }
}

/* ---------- Comparativa ---------- */

.compare__heading {
  text-align: center;
}

.compare {
  display: grid;
  gap: var(--space-4);
  align-items: start;
  max-width: 26rem;
  margin-inline: auto;
}

.compare__vs {
  justify-self: center;
  /* The cards align to the grid's start (top); "vs" is the one exception,
     centered on its own between them regardless of how tall either card is. */
  align-self: center;
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--wp-text-muted);
}

.compare-card {
  border-radius: var(--radius-md);
  padding: var(--space-5);
  border: 1px solid var(--wp-stroke);
}

/* The winning card carries the weight: accent border, lifted surface and a
   glow. The losing card stays flat and recessed — but its text still meets
   4.5:1, since "de-emphasised" must not mean "unreadable". */
.compare-card--win {
  border-color: var(--wp-green);
  background: linear-gradient(180deg, rgba(34, 197, 94, 0.12), rgba(34, 197, 94, 0.02));
  box-shadow: 0 0 0 1px rgba(34, 197, 94, 0.25), 0 18px 40px rgba(2, 9, 27, 0.55);
}

.compare-card--lose {
  background: rgba(255, 255, 255, 0.02);
  color: var(--wp-text-soft);
}

.compare-card__flag {
  font-size: var(--text-2xs);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--wp-text-muted);
}

.compare-card--win .compare-card__flag {
  color: var(--wp-green);
}

.compare-card__name {
  margin-top: var(--space-1);
  font-size: var(--text-lg);
  line-height: var(--leading-snug);
  font-weight: 800;
}

.compare-card__price {
  margin-top: var(--space-3);
  font-size: 1.75rem;
  line-height: 1.1;
  font-weight: 800;
}

.compare-card--lose .compare-card__price {
  color: var(--wp-text-soft);
}

.compare-card__price-unit {
  display: block;
  margin-top: var(--space-1);
  font-size: var(--text-xs);
  font-weight: 500;
  color: var(--wp-text-muted);
}

.compare-card__list {
  display: grid;
  gap: var(--space-3);
  margin-top: var(--space-5);
  padding-top: var(--space-5);
  border-top: 1px solid var(--wp-stroke);
}

.compare-card__item {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  font-size: var(--text-sm);
  line-height: var(--leading-snug);
}

/* Shape, not just hue, carries the meaning: a tick vs a cross reads the
   same for a colour-blind or monochrome reader. */
.compare-card__icon {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  border-radius: 50%;
}

.compare-card--win .compare-card__icon {
  background: rgba(34, 197, 94, 0.15);
  color: var(--wp-green);
}

.compare-card--lose .compare-card__icon {
  background: rgba(255, 255, 255, 0.06);
  color: var(--wp-text-muted);
}

@media (min-width: 640px) {
  .compare {
    max-width: 46rem;
    grid-template-columns: 1fr auto 1fr;
    gap: var(--space-4);
  }

  /* The winner sits slightly proud of the alternative. */
  .compare-card--win {
    transform: scale(1.03);
  }
}

/* ---------- Spoiler ---------- */

/* Manual peek carousel: no autoplay — pure scroll-snap. Each card is sized
   so the viewport shows one full card plus a fixed sliver of the next
   (--slider-peek), which is the visual cue that there's more to swipe to.
   Cards snap flush to the left edge of the viewport (not the container's
   inset) once scrolled — that's the standard peek-carousel behaviour, the
   same one Instagram/Netflix use, not a misalignment.

   Touch and trackpad scroll this natively; a plain mouse has no built-in
   way to move horizontal content, so script.js adds click-and-drag for
   mouse/pen pointers only (touch is left to the native scroll). The cursor
   states below signal that affordance. */

.slider {
  --slider-peek: var(--space-8); /* 64px sliver of the next card */
  /* How far the first card sits from the true viewport edge. Not just
     --container-pad: .l-container caps out and centers itself once the
     viewport exceeds its max-width, so a fixed padding here would drift
     away from the heading above it on anything wider than the container —
     this keeps the two in sync at every width. */
  --slider-inset: calc(var(--container-pad) + max(0px, (100vw - var(--container-sm)) / 2));

  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  /* Without this, `scroll-snap-align: start` on the first card snaps it
     flush to the scrollport's true edge on load, eating the left inset
     entirely (measured: the card sat at x=0 while the heading above it
     sat at x=22px). This tells the snap machinery where "start" actually
     is, so the resting position keeps the inset instead of erasing it. */
  scroll-padding-inline-start: var(--slider-inset);
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  cursor: grab;
  /* Eases the final snap into place instead of an instant jump. Turned off
     during drag below so the card doesn't lag behind the cursor. */
  scroll-behavior: smooth;
}

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

.slider.is-dragging {
  cursor: grabbing;
  scroll-snap-type: none; /* let the drag track the cursor 1:1, no snap fighting mid-drag */
  scroll-behavior: auto; /* instant 1:1 tracking; smooth resumes for the snap settle on release */
  user-select: none;
}

.slider__inner {
  display: flex;
  gap: var(--space-3);
  width: max-content;
  min-width: 100%;
  padding-inline-start: var(--slider-inset);
  padding-inline-end: var(--container-pad);
}

.slider__card {
  flex: 0 0 auto;
  width: calc(100vw - var(--slider-inset) - var(--slider-peek));
  /* keeps the peek proportionally sensible instead of ballooning on tablets */
  max-width: 22rem;
  scroll-snap-align: start;
}

.slider__card-title {
  margin-bottom: var(--space-2);
  font-size: var(--text-s);
  font-weight: 600;
  line-height: var(--leading-normal);
}

/* Fixed frame so every card is the same height regardless of the source
   screenshot's own proportions — the app screens are near-square, the
   desktop ones are wide. object-fit: contain never crops, so no UI text
   in a screenshot is ever cut off; the frame's own background fills
   whatever margin that leaves instead of stretching the image to match. */
.slider__card-media {
  /* All 5 current screenshots are 800x800; object-fit: contain below still
     protects against a future one arriving in a different ratio. */
  aspect-ratio: 1 / 1;
  display: grid;
  place-items: center;
  overflow: hidden;
  background: var(--wp-hero-bg);
  border: 1.5px solid #fff;
  border-radius: var(--radius-sm);
}

.slider__card-media img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  /* Chrome/Safari still start a native image drag-ghost on mousedown+move
     unless this is set explicitly; script.js's dragstart preventDefault
     covers Firefox, which ignores this property. */
  -webkit-user-drag: none;
}

@media (min-width: 640px) {
  .slider {
    /* More room at tablet+, so the peek can be a touch more generous */
    --slider-peek: var(--space-9);
    /* .l-container itself caps out at --container-md from here on */
    --slider-inset: calc(var(--space-7) + max(0px, (100vw - var(--container-md)) / 2));
    --slider-card-width: 30rem;
  }

  .slider__inner {
    padding-inline-start: var(--slider-inset);
    /* Enough trailing room for the last card to scroll all the way to the
       start position, same as the first card — otherwise on wide viewports
       the scrollable area runs out before the last card can snap flush and
       the carousel looks like it stops short. */
    padding-inline-end: max(var(--space-7), calc(100vw - var(--slider-inset) - var(--slider-card-width)));
  }

  .slider__card {
    width: var(--slider-card-width);
    max-width: none;
  }
}

@media (min-width: 1024px) {
  .slider {
    /* Match .l-container's own padding-inline at this breakpoint (--space-6)
       so the first card lines up with the section title above it. */
    --slider-inset: calc(var(--space-6) + max(0px, (100vw - var(--container-md)) / 2));
  }

  .slider__inner {
    padding-inline-end: max(var(--space-6), calc(100vw - var(--slider-inset) - var(--slider-card-width)));
  }
}

/* ---------- FAQ ---------- */

.faq {
  max-width: 36rem;
  font-size: var(--text-xs);
  line-height: var(--leading-normal);
}

.faq__item {
  border-bottom: 1px solid var(--wp-stroke);
}

.faq__item + .faq__item {
  margin-top: 0;
}

/* Native <details>/<summary>: keyboard and screen-reader support come
   free, with no JS. Custom marker replaces the default triangle. */
.faq__q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  margin: 0;
  padding-block: var(--space-4);
  font-size: var(--text-base);
  font-weight: 700;
  line-height: var(--leading-snug);
  cursor: pointer;
  list-style: none;
}

.faq__q::-webkit-details-marker {
  display: none;
}

.faq__q::after {
  content: "+";
  flex: 0 0 auto;
  font-size: var(--text-lg);
  font-weight: 400;
  color: var(--wp-text-soft);
}

.faq__item[open] > .faq__q::after {
  content: "\2212";
}

.faq__a {
  margin: 0 0 var(--space-4);
  color: var(--wp-text-soft);
}

/* ---------- Checkout card ---------- */

.buy {
  /* Same width as the rest of the section's content — no narrower cap. */
  margin-top: var(--space-9);
  background: #fff;
  color: var(--wp-ink);
  border-radius: var(--radius-md);
  padding: var(--space-5) var(--space-4) var(--space-7);
  scroll-margin-top: 6rem;
  box-shadow: 0 12px 30px rgba(1, 9, 31, 0.45);
}

.buy__title {
  font-size: var(--text-lg);
  line-height: var(--leading-snug);
  font-weight: 800;
}

.buy__form {
  margin-top: var(--space-5);
}

/* ---------- Progressive reveal ----------
   Animating `grid-template-rows` from 0fr to 1fr transitions to the content's
   natural height without hardcoding a max-height. The inner element clips
   during the move and carries the slide/fade, easing out (decelerating) as
   it arrives — the field is entering, not leaving. */

.reveal {
  display: grid;
  grid-template-rows: 0fr;
  opacity: 0;
  transition: grid-template-rows 420ms cubic-bezier(0.22, 0.75, 0.3, 1),
    opacity 260ms ease-out;
}

.reveal__inner {
  overflow: hidden;
  min-height: 0;
  /* The 4px inset keeps the focus ring (2px outline + 2px offset) from being
     clipped; the negative margins cancel it out of the layout. No padding-top
     here — with border-box, padding survives the 0fr row and would leave a
     gap while the step is closed, so the gap lives on the child below. */
  padding: 0 4px 4px;
  margin-inline: -4px;
  margin-bottom: -4px;
  transform: translateY(-10px);
  transition: transform 420ms cubic-bezier(0.22, 0.75, 0.3, 1);
}

/* overflow:hidden makes .reveal__inner a block formatting context, so this
   margin stays clipped inside it instead of collapsing out. */
.reveal__inner > :first-child {
  margin-top: var(--space-4);
}

.reveal.is-open {
  grid-template-rows: 1fr;
  opacity: 1;
}

.reveal.is-open > .reveal__inner {
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .reveal,
  .reveal__inner {
    transition: none;
  }

  .reveal__inner {
    transform: none;
  }
}

.field {
  display: grid;
  gap: var(--space-1);
}

.field + .field {
  margin-top: var(--space-4);
}

.field__label {
  font-size: var(--text-xs);
  line-height: var(--leading-normal);
  font-weight: 700;
}

/* Wraps just the <select> (not the label) so the green check badge can be
   positioned against the control itself, regardless of label length. */
.field__control-wrap {
  position: relative;
}

.field__control {
  width: 100%;
  min-height: var(--tap-min);
  padding-block: 0;
  padding-inline-start: var(--space-3);
  /* Room for the chevron *and* the check badge without either crowding
     selected text. The badge sits at right:34px and is 20px wide, so it ends
     54px in — anything less and long option labels (real degree names run
     long) render underneath it. */
  padding-inline-end: 56px;
  border: 1px solid #3a3a3a;
  border-radius: var(--radius-sm);
  background: #fff;
  color: var(--wp-ink);
  font-family: inherit;
  font-size: var(--text-sm);
  appearance: none;
  -webkit-appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, #3a3a3a 50%),
    linear-gradient(135deg, #3a3a3a 50%, transparent 50%);
  background-position: calc(100% - 16px) 50%, calc(100% - 11px) 50%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  cursor: pointer;
  transition: background-color 200ms ease-out, border-color 200ms ease-out, color 200ms ease-out;
}

/* Placeholder ("Elige tu grado"): the field is usable but nothing is picked
   yet. Uses the HTML `required` attribute purely for this CSS hook — the
   form still submits nothing natively (novalidate) and script.js does the
   real gating. Muted, but clearly darker than the :disabled state below, so
   the two "not done yet" reasons (locked vs. simply unanswered) don't read
   as the same thing. */
.field__control:invalid {
  color: var(--wp-ink-soft);
}

/* Answered: a real option is picked. Green border + a faint green tint on
   the control itself, plus the check badge (below) — two independent
   signals, so this doesn't rely on color alone. */
.field__control:valid:not(:disabled) {
  border-color: var(--wp-green);
  background-color: rgba(34, 197, 94, 0.07);
}

.field__check {
  position: absolute;
  top: 50%;
  /* Clears the chevron, which sits in the ~11-16px-from-edge zone. */
  right: 34px;
  transform: translateY(-50%) scale(0.6);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--wp-green);
  color: #fff;
  opacity: 0;
  pointer-events: none;
  transition: opacity 200ms ease-out, transform 200ms ease-out;
}

.field__control-wrap:has(.field__control:valid:not(:disabled)) .field__check {
  opacity: 1;
  transform: translateY(-50%) scale(1);
}

/* Locked: visible but unmistakably not-yet-usable, until the field before
   it gets a value. Muted chevron too, not just the border/text, so the
   "disabled" read doesn't rely on border contrast alone. */
.field__control:disabled {
  border-color: #d6d6d6;
  background-color: #f2f2f2;
  color: #9a9a9a;
  cursor: not-allowed;
  background-image: linear-gradient(45deg, transparent 50%, #b3b3b3 50%),
    linear-gradient(135deg, #b3b3b3 50%, transparent 50%);
}

/* The label dims a touch too, so the whole field — not just the control —
   reads as locked. Progressive enhancement: without :has() support the
   select's own disabled styling above still carries the meaning. */
.field:has(.field__control:disabled) .field__label {
  color: var(--wp-ink-soft);
}

.buy__summary {
  margin-top: var(--space-6);
  border: 1px solid var(--wp-green-strong);
  border-radius: var(--radius-sm);
  background: var(--wp-green-soft);
  padding: var(--space-3);
}

.buy__summary-title {
  font-size: var(--text-base);
  line-height: var(--leading-snug);
  font-weight: 700;
}

.buy__summary-text {
  margin-top: var(--space-2);
  font-size: var(--text-xs);
  line-height: var(--leading-normal);
}

.buy__summary-text strong {
  font-weight: 700;
}

.buy__ready {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-5);
  font-size: var(--text-md);
  line-height: var(--leading-snug);
  font-weight: 700;
}

.buy__ready-icon {
  flex: 0 0 auto;
  display: inline-flex;
  color: var(--wp-green-strong);
}

.buy .btn-primary {
  margin-top: var(--space-5);
}

/* Kept in the DOM and focusable (so its purpose is discoverable) but
   visibly and programmatically inactive until a subject is chosen. */
.btn-primary[aria-disabled="true"] {
  background: #c8ccd6;
  color: #55596a;
  cursor: not-allowed;
}

.btn-primary[aria-disabled="true"]:active {
  transform: none;
}

.buy__note {
  margin-top: var(--space-2);
  font-size: var(--text-2xs);
  line-height: var(--leading-normal);
  color: var(--wp-ink-soft);
}

.buy__note strong {
  color: #3f3f3f;
  font-weight: 700;
}

/* ---------- Footer ---------- */

.footer {
  padding-block: var(--space-5) var(--space-5);
  text-align: center;
  font-size: var(--text-2xs);
  line-height: var(--leading-normal);
  color: var(--wp-text-muted);
}

.footer__links {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-5);
}

.footer__links a {
  text-decoration: none;
}

.footer__links a:hover {
  text-decoration: underline;
}

/* ---------- Small phones ---------- */

@media (max-width: 359px) {
  :root {
    --container-pad: 1rem;
  }
}

/* =========================================================================
   Páginas de una sola tarjeta (gracias.html, 404.html)

   Las dos son lo mismo: una tarjeta blanca centrada sobre el fondo oscuro,
   con distintivo, titular, copy y salida. Lo común vive en `.sheet`; lo
   propio de cada página va con su prefijo.
   ========================================================================= */

.sheet {
  min-height: 100svh;
  display: grid;
  place-items: center;
  padding: var(--space-6) var(--container-pad);
}

.sheet__card {
  width: 100%;
  max-width: var(--container-md);
  background: #fff;
  color: var(--wp-ink);
  border-radius: var(--radius-md);
  padding: var(--space-6) var(--space-5) var(--space-5);
  text-align: center;
  box-shadow: 0 12px 30px rgba(1, 9, 31, 0.45);
}

.sheet__eyebrow {
  margin: 0 0 var(--space-2);
  font-size: var(--text-2xs);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--wp-ink-soft);
}

.sheet__title {
  margin: 0;
  font-size: var(--text-h2);
  line-height: var(--leading-tight);
  font-weight: 700;
}

.sheet__lead {
  margin: var(--space-4) auto 0;
  max-width: 34rem;
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  color: var(--wp-ink-soft);
}

.sheet__lead + .sheet__lead {
  margin-top: var(--space-3);
}

/* El mismo distintivo girado del hero, reutilizado para rematar el chiste en
   cada página: en rojo cuando la cosa va mal, en verde cuando va bien. */
.sheet__aura {
  display: inline-block;
  margin: var(--space-5) 0 0;
  transform: rotate(-2.3deg);
  background: var(--wp-red);
  color: #fff;
  border-radius: 7px;
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-lg);
  line-height: 1.2;
  font-weight: 800;
  white-space: nowrap;
}

.sheet__aura--good {
  background: var(--wp-green);
}

.sheet__actions {
  margin-top: var(--space-6);
}

.sheet__back {
  display: inline-block;
  margin-top: var(--space-6);
  font-size: var(--text-2xs);
  color: var(--wp-ink-soft);
}

/* ---------- gracias.html ---------- */

.thanks__check {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3.5rem;
  height: 3.5rem;
  margin-bottom: var(--space-4);
  border-radius: 50%;
  background: var(--wp-green);
  color: #fff;
}

.thanks__eyebrow {
  color: var(--wp-green-strong);
}

.thanks__subject {
  margin: var(--space-3) 0 0;
  font-size: var(--text-md);
  font-weight: 600;
}

.thanks__survey {
  margin-top: var(--space-7);
  padding-top: var(--space-6);
  border-top: 1px solid #e6e8ee;
}

.thanks__survey-title {
  margin: 0;
  font-size: var(--text-lg);
  line-height: var(--leading-snug);
  font-weight: 700;
}

.thanks__survey-text {
  margin: var(--space-2) auto 0;
  max-width: 34rem;
  font-size: var(--text-xs);
  line-height: var(--leading-normal);
  color: var(--wp-ink-soft);
}

/* Typeform inyecta un iframe que ocupa el 100% del contenedor, así que la
   altura tiene que salir de aquí. */
.thanks__embed {
  margin-top: var(--space-5);
  height: min(70svh, 34rem);
}
