/* =============================================
   TOKENS
============================================= */
:root {
  /* -------- SPACING: a 4px grid -------- */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-8: 32px;
  --space-10: 40px;
  --space-12: 48px;
  --space-14: 56px;
  --space-16: 64px;
  --space-18: 72px;
  --space-22: 88px;
  --space-24: 96px;

  --section-y: var(--space-24);
  --section-gap: var(--space-22);
  --block-gap: var(--space-12);

  /* -------- RADII -------- */
  --radius-sm: 8px;
  --radius: 12px;
  --radius-lg: 16px;
  --radius-xl: 24px;
  --radius-2xl: 32px;
  --radius-pill: 999px;

  /* -------- COLOUR -------- */
  --color-primary: #4135e6;
  --color-primary-dark: #3a2fd4;
  --color-primary-light: #493ee6;
  --color-primary-soft: #f1f0fe;
  --color-primary-softer: #f8f8ff;

  --ring-rgb: 65 53 230;

  --color-text-primary: #1c2024;
  --color-text-secondary: #4e5358;
  --color-text-muted: #6d7277;
  --color-border: #e2e5e8;
  --color-bg-page: #f9fafc;
  --color-white: #ffffff;

  --pastel-1: #e8e7f3;
  --pastel-2: #d2d0ec;
  --pastel-3: #b6b3e6;
  --pastel-4: #9892e2;
  --pastel-5: #7770e1;

  --color-success: #a7e82a;

  --color-success-green: #a7e82a;
  --color-success-green-soft: #f2fce0;
  --color-success-green-ink: #5a8a10;

  --cta-tint: #f3f2fe;

  /* -------- CARD GRAIN -------- */
  --grain-1: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.40' numOctaves='4' seed='7'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23g)'/%3E%3C/svg%3E");
  --grain-2: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='turbulence' baseFrequency='0.85' numOctaves='2' seed='23'/%3E%3C/filter%3E%3Crect width='100' height='100' filter='url(%23g)'/%3E%3C/svg%3E");
  --grain-3: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.22' numOctaves='5' seed='41'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23g)'/%3E%3C/svg%3E");
  --grain-4: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.60' numOctaves='3' seed='63'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23g)'/%3E%3C/svg%3E");
  --grain-strength: 0.16;

  /* -------- LAYOUT -------- */
  --header-height: 64px;
  --header-top: 16px;
  --header-bottom: calc(var(--header-top) + var(--header-height));
  /* Tighter than it was: the copy has to clear the top half of the reel now,
     and every pixel above the headline is a pixel the reel cannot have. */
  --hero-gap-top: clamp(32px, 3.5vw, 56px);
  --lux-tail: 260px;

  /* How much room the hero palette gets to dissolve into white after the reel.
     The reel straddles the hero seam, so the colour field stays intact behind
     its lower half and only begins to lift once the reel has cleared. */
  --lux-fall: clamp(140px, 16vw, 260px);

  /* Sampled from the bottom edge of stagelight-hero-poster.webp. The centre is
     a muted blue-green pool; the sides fall into an almost-black plum/navy.
     The seam itself is true black on both sides; these tones are revealed just
     below it to rebuild the video's horizontal light shape without a jump. */
  --lux-seam-black: #000000;
  --lux-green: #18352f;
  --lux-shadow: #0b171a;
  --lux-plum: #090711;
  --edge-shift: 16px;
  --container-width: 1140px;
  --container-wide: 1300px;
  --card-scroll: 75vh;

  /* The hero copy block's width. The copy is centred under the beam rather
     than pushed out of its way, so this is a typographic figure again: wide
     enough that the headline breaks in two lines instead of four, and no
     wider. The lede sets its own, narrower measure inside it — a subhead
     running the full width of the headline is a wall of text. Nothing else on
     the page follows this number; the reel used to, and no longer does. */
  --hero-copy-max: min(940px, 88vw);

  /* The reel's width, set on its own terms: it is centred in the hero and has
     nothing to line up with. --hero-copy-max is a separate figure describing
     a separate column; the two were once deliberately equal and are now
     deliberately unrelated.
     --hero-reel-w is the resolved width, and three things read it: the reel
     sizes itself from it, the band below works out how much top padding the
     overhanging half needs, and the hero's own floor is built from it. The
     phone block near the end of the file replaces it outright. */
  --hero-reel-max: 1100px;

  --hero-reel-w: min(var(--hero-reel-max), 76vw);

  /* --hero-copy-floor is measured, not chosen: the line the hero copy reaches
     at its tallest — the French headline runs a line longer than the English
     one — plus the gap that keeps the reel off it. Re-measure it if the copy
     or its type sizes change; the short-viewport block further down tightens
     the copy and moves it.

     The hero will not be shorter than that line plus the top half of the
     reel, whatever the viewport does. Centred copy is short enough that on a
     900px screen 100svh wins outright and the reel is cut exactly in half by
     the fold, which is the point of the arrangement. The floor only takes
     over on a laptop shorter than that, where it lets the hero run a little
     past the fold rather than shrinking the reel. */
  --hero-copy-floor: 540px;
  --hero-floor: max(
    100svh,
    calc(var(--hero-copy-floor) + var(--hero-reel-w) * 0.28125)
  );

  /* -------- MOTION -------- */
  --transition: 0.25s ease;
  --font-heading: "Montserrat", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-family: "DM Mono", ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;

  /* The next section is pulled up over the band's tail, so the visible run is
     the band's height minus that tail. The colour field mirrors the bottom of
     the hero horizontally. A black veil first matches the hero's final pixel
     and then clears gradually to reveal those greens. Above both sits a white
     veil: transparent through the reel's lower edge, then eased to solid white
     before the progress markers and the light section below. */
  --lux-run: calc(100% - var(--lux-tail));
  --lux-reel-overhang: calc(var(--hero-reel-w) * 0.28125);
  --lux-fade-start: calc(var(--lux-reel-overhang) + clamp(12px, 1.5vw, 24px));
  --lux-grad:
    linear-gradient(
      to bottom,
      rgb(255 255 255 / 0) 0,
      rgb(255 255 255 / 0) var(--lux-fade-start),
      rgb(255 255 255 / 0.03) calc(var(--lux-fade-start) + var(--lux-fall) * 0.10),
      rgb(255 255 255 / 0.10) calc(var(--lux-fade-start) + var(--lux-fall) * 0.22),
      rgb(255 255 255 / 0.23) calc(var(--lux-fade-start) + var(--lux-fall) * 0.38),
      rgb(255 255 255 / 0.42) calc(var(--lux-fade-start) + var(--lux-fall) * 0.55),
      rgb(255 255 255 / 0.64) calc(var(--lux-fade-start) + var(--lux-fall) * 0.72),
      rgb(255 255 255 / 0.84) calc(var(--lux-fade-start) + var(--lux-fall) * 0.87),
      rgb(255 255 255 / 0.96) calc(var(--lux-fade-start) + var(--lux-fall) * 0.97),
      #ffffff var(--lux-run)
    ),
    linear-gradient(
      to bottom,
      var(--lux-seam-black) 0,
      var(--lux-seam-black) 14px,
      rgb(0 0 0 / 0.92) 36px,
      rgb(0 0 0 / 0.70) calc(var(--lux-reel-overhang) * 0.28),
      rgb(0 0 0 / 0.34) calc(var(--lux-reel-overhang) * 0.48),
      rgb(0 0 0 / 0) calc(var(--lux-reel-overhang) * 0.68)
    ),
    radial-gradient(
      ellipse 66% 118% at 53% 0%,
      var(--lux-green) 0%,
      var(--lux-shadow) 58%,
      var(--lux-plum) 100%
    );

  --ease-imessage: cubic-bezier(0.22, 0.95, 0.24, 1.03);
  --ease-out-soft: cubic-bezier(0.16, 1, 0.3, 1);

  /* For motion that changes a box's HEIGHT rather than its paint. --ease-out-soft
     spends about 95% of its travel in the first half, which reads as a snap and
     throws everything below it down the page; this one spreads the distance
     evenly so a tall panel never moves fast at any point. */
  --ease-in-out-soft: cubic-bezier(0.33, 0, 0.3, 1);
}

/* =============================================
   RESET
============================================= */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}

body {
  font-family: var(--font-family);
  color: var(--color-text-primary);
  background-color: var(--color-bg-page);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

a {
  text-decoration: none;
  color: inherit;
}

button {
  font-family: inherit;
  cursor: pointer;
  border: none;
  background: none;
}

ul, ol {
  list-style: none;
}

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

/* =============================================
   SKIP LINK
============================================= */
.skip-link {
  position: absolute;
  top: -100px;
  left: 16px;
  z-index: 1100;
  padding: 12px 20px;
  font-size: 14px;
  font-weight: 500;
  color: var(--color-white);
  background-color: var(--color-primary);
  border-radius: var(--radius);
  transition: top var(--transition);
}

.skip-link:focus {
  top: 12px;
}

main:focus {
  outline: none;
}

main {
  scroll-margin-top: var(--header-height);
}

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

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

/* =============================================
   MAIN SECTIONS: ALTERNATING BACKGROUND
============================================= */
main > section:nth-of-type(odd) {
  background-color: var(--color-white);
}

main > section:nth-of-type(even) {
  background-color: var(--color-bg-page);
}

main > section.reviews      { background-color: var(--color-bg-page); }
main > section.highlights   { background-color: var(--color-white); }
main > section.feature-grid { background-color: var(--color-bg-page); }
main > section.faq          { background-color: var(--color-white); }

main > section {
  position: relative;
  scroll-margin-top: calc(var(--header-bottom) + 16px);
}

/* =============================================
   SECTION RULES
============================================= */
.lux-stage + section::before,
main > section + section:not(.cta-band)::before {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: min(var(--container-wide), calc(100% - 48px));
  height: 1px;
  pointer-events: none;
  background: linear-gradient(
    to right,
    transparent 0%,
    var(--color-border) 18%,
    var(--color-border) 82%,
    transparent 100%
  );
}

/* =============================================
   ARROW ICON
============================================= */
.arrow-ico {
  width: 18px;
  height: 22px;
  flex-shrink: 0;
  display: block;
  transition: transform var(--transition);
}

/* =============================================
   BUTTONS
============================================= */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 12px 24px;
  border-radius: var(--radius);
  font-weight: 500;
  font-size: 14px;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--transition), color var(--transition), border-color var(--transition), transform var(--transition);
}

.btn-primary {
  background-color: var(--color-primary);
  color: var(--color-white);
  border: 1.5px solid var(--color-primary);
}

.btn-primary:hover {
  background-color: var(--color-primary-dark);
  border-color: var(--color-primary-dark);
}

.btn-outline {
  background-color: var(--color-white);
  color: var(--color-primary);
  border: 1.5px solid var(--color-primary);
}

.btn-outline:hover,
.btn-outline:focus-visible {
  background-color: var(--color-primary);
  border-color: var(--color-primary);
  color: var(--color-white);
}

.btn-sm {
  padding: 8px 16px;
  font-size: 14px;
}

.btn-lg {
  padding: 16px 40px;
  font-size: 15px;
  border-radius: var(--radius);
}

.btn-grow:hover {
  transform: scale(1.045);
}

.btn-grow:active {
  transform: scale(1.015);
}

.btn-arrow {
  color: var(--color-white);
}

.btn:hover .arrow-ico {
  transform: translateX(4px);
}

a:focus-visible,
button:focus-visible,
summary:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

/* =============================================
   TEXT LINK
============================================= */
.text-link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  font-weight: 500;
  color: var(--color-primary);
  padding: 4px 0;
  border-bottom: 1.5px solid transparent;
  transition: border-color var(--transition);
}

.text-link:hover {
  border-bottom-color: var(--color-primary);
}

.text-link:hover .arrow-ico {
  transform: translateX(4px);
}

/* =============================================
   EYEBROW PILL
============================================= */
.eyebrow {
  display: inline-block;
  font-size: 13px;
  font-weight: 500;
  color: var(--color-primary);
  background-color: var(--color-white);
  border: 1px solid var(--color-border);
  padding: 8px 16px;
  border-radius: var(--radius-pill);
  margin-bottom: 20px;
}

/* =============================================
   HEADER
============================================= */
.site-header {
  --hd-bg: 255 255 255;
  --hd-fg: var(--color-text-primary);
  --hd-fg-soft: var(--color-text-secondary);
  --hd-accent: var(--color-primary);
  --hd-border: var(--color-border);
  --hd-chip-bg: var(--color-white);
  --hd-chip-border: var(--color-border);
  --hd-chip-hover-bg: var(--color-primary-soft);
  --hd-logo-filter: none;

  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  padding-top: var(--header-top);
  padding-left: 12px;
  padding-right: 12px;
  z-index: 1000;
  pointer-events: none;
  background: none;
  border: none;
  color: var(--hd-fg);
  transition: transform 0.3s ease, color 0.35s ease;
}

.site-header[data-theme="dark"] .header-inner::before {
  box-shadow: none;
}

.site-header[data-theme="dark"] {
  --hd-bg: 0 0 0;
  --hd-fg: #ffffff;
  --hd-fg-soft: rgba(255, 255, 255, 0.72);
  --hd-accent: #ffffff;
  --hd-border: transparent;
  --hd-chip-bg: rgba(255, 255, 255, 0.08);
  --hd-chip-border: rgba(255, 255, 255, 0.24);
  --hd-chip-hover-bg: rgba(255, 255, 255, 0.16);
  --hd-logo-filter: none;
}

@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .header-inner::before { background-color: rgb(var(--hd-bg)); }
}

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

.header-inner {
  max-width: calc(var(--container-width) + var(--edge-shift) * 2);
  margin: 0 auto;
  height: var(--header-height);
  border-radius: var(--radius-pill);
  padding: 0 calc(var(--header-height) / 2 + 8px);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  pointer-events: auto;
  position: relative;
  background: none;
  border: none;
}

.header-inner::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background-color: rgb(var(--hd-bg) / 0.88);
  -webkit-backdrop-filter: blur(28px) saturate(165%);
  backdrop-filter: blur(28px) saturate(165%);
  border: 1px solid var(--hd-border);
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.10);

  transition: opacity 0.42s ease,
              transform 0.42s var(--ease-out-soft),
              background-color 0.35s ease,
              border-color 0.35s ease,
              box-shadow 0.35s ease;
}

.site-header.at-top .header-inner::before {
  opacity: 0;
  transform: translateY(-100%);
}

.site-header.plate-static .header-inner::before {
  transition: none;
}

.logo {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}

.logo-mark {
  height: 32px;
  width: auto;
  filter: var(--hd-logo-filter);
  transition: filter 0.35s ease;
}

.logo-word-stack {
  position: relative;
  display: inline-flex;
  flex-shrink: 0;
}

.logo-word {
  height: 18px;
  width: auto;
  position: relative;
  top: 1px;
  filter: var(--hd-logo-filter);
  transition: filter 0.35s ease;
}

.logo-word-beam {
  position: absolute;
  inset: 0;
  height: 100%;
  clip-path: inset(0 44% 0 0);
  filter: brightness(0) invert(1);
  opacity: 0;
  transition: opacity 0.35s ease;
  pointer-events: none;
}

.site-header[data-theme="dark"] .logo-word-beam {
  opacity: 1;
}

.main-nav {
  display: flex;
  align-items: center;
  gap: 32px;
  flex: 1;
  justify-content: center;
}

.nav-link {
  font-size: 14px;
  font-weight: 500;
  color: var(--hd-fg-soft);
  border-bottom: 2px solid transparent;
  padding-bottom: 2px;
  transition: color var(--transition), border-color var(--transition);
}

.nav-link:hover {
  color: var(--hd-accent);
}

.nav-link.active {
  color: var(--hd-accent);
  border-bottom-color: var(--hd-accent);
}

.header-actions {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-shrink: 0;
}

/* -------- LANGUAGE SWITCH -------- */
.lang-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 64px;
  min-height: 44px;
  padding: 12px 24px;
  font-size: 14px;
  font-weight: 500;
  letter-spacing: 0.04em;
  color: var(--hd-fg-soft);
  background-color: var(--hd-chip-bg);
  border: 1px solid var(--hd-chip-border);
  border-radius: var(--radius-pill);
  text-decoration: none;
  transition: color var(--transition), border-color var(--transition), background-color var(--transition);
}

.lang-toggle:hover {
  color: var(--hd-accent);
  border-color: var(--hd-accent);
  background-color: var(--hd-chip-hover-bg);
}

.lang-current {
  display: block;
  line-height: 1;
  transition: opacity 0.15s ease, transform 0.15s ease;
}

.lang-toggle.swapping .lang-current {
  opacity: 0;
  transform: translateY(-4px);
}

.mobile-menu-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 4px;
  width: 44px;
  height: 44px;
  padding: 8px;
}

.mobile-menu-toggle span {
  display: block;
  height: 2px;
  width: 100%;
  background-color: var(--hd-fg);
  transition: background-color 0.35s ease,
              transform var(--transition),
              opacity var(--transition);
}

/* =============================================
   LUX GRADIENT BAND
============================================= */
.lux-stage {
  position: relative;
  isolation: isolate;
  background-color: #ffffff;
}

.lux-band {
  --corner-w: clamp(186px, 22.5vw, 324px);
  --corner-rise: 0.34;

  position: relative;
  z-index: 0;
  isolation: isolate;
  background-image: var(--lux-grad);
  /* Half the reel above hangs down into here, so the band opens with exactly
     that overhang — --hero-reel-w * 9/16 / 2 — plus the gap that puts the
     progress markers a readable distance under it. The band's own occupant is
     only those markers now, so this padding is the whole of its height above
     the tail: too little and the reel lands on the dots, too much and the
     band reads as a hole.

     --lux-fall is added after that overhang. This padding IS the gradient's
     visible run: the hero palette remains behind the reel, then spends the
     remaining distance fading into white. */
  padding-top: calc(
    var(--hero-reel-w) * 0.28125 + clamp(28px, 3vw, 44px) + var(--lux-fall)
  );
  padding-bottom: var(--lux-tail);
  margin-bottom: calc(var(--lux-tail) * -1);
}

/* The old .lux-glow layers remain removed: the sampled colour field above is
   already soft, and duplicating it with blend modes creates a visible bloom
   instead of a continuous extension of the video. */

.lux-stage > section {
  position: relative;
  z-index: 1;
  background-color: transparent;
  scroll-margin-top: calc(var(--header-bottom) + 16px);
}

.lux-band > .hero-demo {
  position: relative;
  z-index: 1;
}

/* -------- DARK HALF -------- */
.lux-stage [data-lux="dark"] h1,
.lux-stage [data-lux="dark"] h2,
.lux-stage [data-lux="dark"] h3 {
  color: #ffffff;
}

.lux-stage [data-lux="dark"] p,
.lux-stage [data-lux="dark"] .hero-lede,
.lux-stage [data-lux="dark"] .section-sub {
  color: rgba(255, 255, 255, 0.78);
}

.lux-stage [data-lux="dark"] .text-link {
  color: #ffffff;
}

.lux-stage [data-lux="dark"] .hiw-num {
  background-color: #ffffff;
  color: #0b0b12;
}

.lux-stage [data-lux="dark"] .btn-primary {
  background-color: #ffffff;
  border-color: #ffffff;
  color: #0b0b12;
}

.lux-stage [data-lux="dark"] .btn-primary .btn-arrow {
  color: #0b0b12;
}

.lux-stage [data-lux="dark"] .btn-primary:hover {
  background-color: rgba(255, 255, 255, 0.86);
  border-color: rgba(255, 255, 255, 0.86);
}

.lux-stage [data-lux="dark"] .btn-outline {
  background-color: rgba(255, 255, 255, 0.10);
  border-color: rgba(255, 255, 255, 0.24);
  color: #ffffff;
}

.lux-stage [data-lux="dark"] .btn-outline:hover,
.lux-stage [data-lux="dark"] .btn-outline:focus-visible {
  background-color: rgba(255, 255, 255, 0.18);
  border-color: rgba(255, 255, 255, 0.34);
  color: #ffffff;
}

/* =============================================
   HERO
============================================= */
/* The floor under the height is what makes room for the reel: the reel is
   centred on the hero's bottom edge, so that edge has to sit far enough below
   the copy to give the reel's top half somewhere to be. See --hero-floor. */
.hero {
  position: relative;
  isolation: isolate;
  display: block;
  min-height: 100vh;
  min-height: var(--hero-floor);
  padding-top: calc(var(--header-bottom) + var(--hero-gap-top));
  padding-bottom: clamp(40px, 6vw, 88px);
  text-align: center;
}

/* -------- THE LOOPING BACKGROUND VIDEO -------- */
.hero-video {
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
  background-color: #000000;
}

/* Shown straight. The cone's apex sits near the middle of the frame and the
   copy is centred under it, so the beam falls down the middle of the page,
   behind the headline and onto the reel below — nothing needs moving out of
   anything's way. */
.hero-video-el {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  display: block;
}

/* The scrim is what keeps white type readable over a moving picture, and the
   type sits on the lit part of that picture, so the middle stops carry real
   work. They are a little lighter than the ones the UFO loop used: this cone
   is a soft wide fan rather than a hard beam, and held down as far as before
   it stopped reading as light at all.

   The lower stops now complete a gradual close to true black. The band begins
   at that exact value and only then reveals the sampled greens, eliminating
   the horizontal value jump without introducing a hard cutoff inside the
   moving picture. */
.hero-scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0.40) 0%,
    rgba(0, 0, 0, 0.22) 38%,
    rgba(0, 0, 0, 0.26) 52%,
    rgba(0, 0, 0, 0.34) 62%,
    rgba(0, 0, 0, 0.40) 70%,
    rgba(0, 0, 0, 0.48) 77%,
    rgba(0, 0, 0, 0.58) 83%,
    rgba(0, 0, 0, 0.68) 88%,
    rgba(0, 0, 0, 0.78) 92%,
    rgba(0, 0, 0, 0.88) 96%,
    rgba(0, 0, 0, 0.95) 98%,
    var(--lux-seam-black) 100%
  );
}

.hero-inner {
  position: relative;
  z-index: 1;
  display: block;
  width: 100%;
  max-width: var(--container-width);
}

.hero-copy {
  max-width: var(--hero-copy-max);
  margin: 0 auto;
}

.hero h1 {
  font-family: var(--font-heading);
  font-size: clamp(38px, 4.6vw, 58px);
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: -0.01em;
  margin-bottom: 20px;
  color: var(--color-text-primary);
  text-wrap: balance;
}

/* Its own measure, narrower than the headline's and centred inside it. Set in
   ch rather than px so it tracks the type size: about 78 characters, which is
   two comfortable lines of this sentence in English and three in French. */
.hero-lede {
  font-size: 17px;
  line-height: 1.6;
  font-weight: 400;
  color: var(--color-text-secondary);
  max-width: min(78ch, 100%);
  margin: 0 auto 32px;
  text-wrap: pretty;
}

.hero-ctas {
  padding-top: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  flex-wrap: wrap;
}

/* -------- SHORT SCREENS -------- */
/* A 720p laptop has the same width to play with and 180px less height, and on
   the hero that height is the scarce one: the copy has to end early enough
   that the reel's top half still shows above the fold. The copy tightens
   rather than the reel shrinking, and --hero-copy-floor moves with it — it is
   the measured bottom of this smaller copy, and the hero's floor is built
   from it. */
@media (min-width: 901px) and (max-height: 820px) {
  .hero {
    --hero-gap-top: 28px;
  }

  :root {
    --hero-copy-floor: 476px;
  }

  .hero h1 {
    font-size: clamp(34px, 3.9vw, 48px);
  }

  .hero-lede {
    margin-bottom: 24px;
  }

  .hero-ctas {
    padding-top: 4px;
  }
}

.hero-demo {
  --demo-max: calc(var(--container-width) + var(--edge-shift) * 2);
  --hang: clamp(0px, calc((100vw - var(--demo-max)) / 2 - 28px), 225px);

  position: relative;
  z-index: 1;
  width: min(var(--demo-max), calc(100% - 24px));
  margin: 0 auto;
}

.hero-shot {
  width: 100%;
}

.hero-shot img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius);
}

/* -------- THE REEL : THREE CLIPS SHARING ONE SLOT -------- */
/* The reel is a child of the hero, not of the band, and it is not sized to
   agree with anything. It used to be held to --hero-copy-max so that it and
   the copy block made one column edge to edge; it has since moved into the
   hero and grown well past the copy above it, so the two widths are now
   independent on purpose. They sit on the same centre line and that is all
   they share. --hero-reel-w is its own figure. Do not re-tie them.

   left/bottom + translate(-50%, 50%) puts it centred on the hero and hanging
   half its height below the hero's bottom edge: the top half is on the first
   screen, the bottom half reaches into the gradient band and is revealed by
   scrolling. Two things follow from that and both are load-bearing. Neither
   the hero nor .lux-band may clip their overflow, or the bottom half is cut
   away rather than covered. And .lux-band pads its top by the same overhang,
   worked out from --hero-reel-w, so nothing in the band collides with it.

   Centred is the placement, deliberately: it puts the reel in the pool the
   beam throws at the bottom of the background video, so the light reads as
   falling on it.

   The box is a plain 16/9 because every clip is now *delivered* as 16/9. The
   recorders baked a different black letterbox into each one, and that used to
   be corrected here, one hand-measured `top:` offset per clip — which meant
   the CSS silently went wrong the moment a clip was re-recorded. The crop
   happens at encode time instead, so this file no longer knows or cares what
   any individual clip looks like.

   Re-recording a clip means re-normalising it, not editing this rule:
     1. measure the bars — per-pixel-row maximum luminance across EVERY frame,
        not a sample. A single frame will not do it: these are recordings of
        dark pages, and genuinely dark content reads as a bar until another
        frame lights it up. A row is bar only if it never rises above ~2/255.
     2. crop those rows off, then crop the sides around the important UI until
        the frame is exactly 16:9. Do not pad: every pixel must belong to the
        recorded page so the clip fills this box edge to edge.
     3. scale that crop to 1280x720 and 854x480, then emit both encodes with
        +faststart. Never stretch a non-16:9 crop. */
.hero-reel {
  position: absolute;
  left: 50%;
  bottom: 0;
  z-index: 2;
  transform: translate(-50%, 50%);
  width: var(--hero-reel-w);
  aspect-ratio: 16 / 9;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: #05070c;
  box-shadow: 0 32px 64px rgba(0, 0, 0, 0.52),
              0 6px 16px rgba(0, 0, 0, 0.34);
}

/* Stacked, not sequenced: both are always laid out, and only opacity says
   which one is in front. That is what lets the handover be a dissolve
   instead of a reflow.

   Full width with height:auto means the element box is exactly the video
   frame, at its own ratio — there is no scaling and no fitting, so the only
   thing that can ever be cut is what the offset below pushes out of the top
   and what the shorter box leaves off the bottom. */
/* Every clip is the box's own ratio now, so `inset` is the whole story — no
   per-clip offset, and nothing to re-measure here when a clip is replaced. */
.hero-reel-clip {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
  opacity: 0;
  transition: opacity 0.42s var(--ease-out-soft);
}

.hero-reel-clip.is-live {
  opacity: 1;
}

/* -------- THE REEL'S PROGRESS ROW -------- */
/* One marker per clip, no arrows: nothing here is a control, it only reports
   which clip is running and how far in. The clip that is playing stretches
   into a line and fills; the others stay dots. */
.hero-reel-progress {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: min(var(--hero-reel-w), calc(100% - 24px));
  margin: 0 auto;
}

.hrp-item {
  position: relative;
  width: 7px;
  height: 7px;
  border-radius: var(--radius-pill);
  overflow: hidden;
  background-color: rgb(65 53 230 / 0.28);
  transition: width 0.42s var(--ease-out-soft),
              background-color 0.42s var(--ease-out-soft);
}

.hrp-item.is-live {
  width: 38px;
  background-color: rgb(65 53 230 / 0.2);
}

/* scaleX rather than width so the fill costs nothing to animate every frame */
.hrp-fill {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background-color: var(--color-primary);
  transform: scaleX(0);
  transform-origin: left center;
}

/* -------- THE TWO PHOTOS ON THE CONSOLE'S CORNERS -------- */
.hero-corner {
  position: absolute;
  z-index: 2;
  width: var(--corner-w);
  aspect-ratio: 4 / 3;
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: 0 26px 52px rgba(0, 0, 0, 0.46),
              0 4px 12px rgba(0, 0, 0, 0.30);
}

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

.hero-corner-client {
  left: calc(var(--hang) * -1);
  top: 0;
  transform: translateY(calc(var(--corner-rise) * -100%));
}

.hero-corner-vendeur {
  right: calc(var(--hang) * -1);
  bottom: 0;
  transform: translateY(calc(var(--corner-rise) * 100%));
}

/* =============================================
   FONCTIONNEMENT
============================================= */
.features {
  padding: var(--section-y) 0;
}

.section-heading {
  text-align: center;
  max-width: 640px;
  margin: 0 auto 56px;
}

.section-heading h2 {
  font-family: var(--font-heading);
  font-size: clamp(28px, 4.4vw, 40px);
  font-weight: 800;
  line-height: 1.18;
  letter-spacing: 0;
  margin-bottom: var(--space-3);
  color: var(--color-text-primary);
}

.section-heading .section-sub {
  font-size: 15px;
  font-weight: 400;
  color: var(--color-text-secondary);
}

.hiw-blocks {
  display: flex;
  flex-direction: column;
  gap: 88px;
}

.hiw-block {
  position: relative;
  display: grid;
  align-items: center;
  gap: 72px;
}

.hiw-num {
  position: absolute;
  top: -26px;
  z-index: 2;
  width: 54px;
  height: 54px;
  aspect-ratio: 1 / 1;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background-color: var(--color-success-green);
  color: var(--color-text-primary);
  font-family: var(--font-heading);
  font-size: 24px;
  font-weight: 600;
  line-height: 1;
}

.hiw-block[data-side="left"]  .hiw-num { right: 0; }
.hiw-block[data-side="right"] .hiw-num { left: 0; }

.hiw-block[data-side="left"] {
  grid-template-columns: minmax(0, 560px) minmax(0, 1fr);
}

.hiw-block[data-side="right"] {
  grid-template-columns: minmax(0, 1fr) minmax(0, 560px);
}

.hiw-block[data-side="left"] .hiw-frame   { grid-column: 1; grid-row: 1; }
.hiw-block[data-side="left"] .hiw-bubble  { grid-column: 2; grid-row: 1; }
.hiw-block[data-side="right"] .hiw-frame  { grid-column: 2; grid-row: 1; }
.hiw-block[data-side="right"] .hiw-bubble { grid-column: 1; grid-row: 1; }

.hiw-frame {
  aspect-ratio: 1 / 1;
  width: 100%;
  background-color: transparent;
  border: none;
  border-radius: var(--radius-xl);
  overflow: hidden;
  padding: 0;
}

.hiw-frame img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center;
  border-radius: var(--radius-lg);
  transition: transform 0.4s var(--ease-out-soft);
  transform: scale(0.957);
}

.hiw-frame:hover img {
  transform: scale(1);
}

.hiw-frame-button {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 4 / 3;
  padding: var(--space-8);
}

.hiw-frame-button:hover img {
  transform: scale(1.045);
}

.hiw-frame-button img {
  width: 84%;
  height: auto;
  max-height: 100%;
  object-fit: contain;
  border-radius: 0;
  transform: none;
}

.hiw-bubble {
  padding: 8px 4px;
  background-color: transparent;
  border: none;
  box-shadow: none;
}

.hiw-block[data-side="left"] .hiw-bubble  { transform-origin: bottom left; }
.hiw-block[data-side="right"] .hiw-bubble { transform-origin: bottom right; }

.hiw-bubble h3 {
  font-family: var(--font-heading);
  font-size: clamp(28px, 4.4vw, 40px);
  font-weight: 800;
  line-height: 1.18;
  letter-spacing: 0;
  margin-bottom: 16px;
  color: var(--color-text-primary);
}

.hiw-bubble p {
  max-width: 68ch;
  font-size: 15px;
  color: var(--color-text-secondary);
  margin-bottom: 24px;
}

/* -------- EASED ENTER / EXIT ON SCROLL -------- */
.hiw-block.reveal-ready .hiw-bubble,
.hiw-block.reveal-ready .hiw-frame {
  opacity: 0;
  transition: opacity 0.2s ease-in, transform 0.2s ease-in;
}

.hiw-block.reveal-ready .hiw-bubble {
  transform: translateY(18px) scale(0.9);
}

.hiw-block.reveal-ready .hiw-frame {
  transform: translateY(14px) scale(0.96);
}

.hiw-block.reveal-ready.in-view .hiw-bubble,
.hiw-block.reveal-ready.in-view .hiw-frame {
  opacity: 1;
  transform: none;
}

.hiw-block.reveal-ready.in-view .hiw-bubble {
  transition: opacity 0.62s var(--ease-imessage), transform 0.62s var(--ease-imessage);
}

.hiw-block.reveal-ready.in-view .hiw-frame {
  transition: opacity 0.62s var(--ease-out-soft) 0.06s, transform 0.62s var(--ease-out-soft) 0.06s;
}

/* =============================================
   STATISTIQUES
============================================= */
/* The testimony carousel that used to open this section is gone, so the
   section now starts on the panel. Its top padding carries the whole gap to
   the block above — there is no heading above the figures to absorb it — which
   is why it is larger here than --section-y. */
.reviews {
  padding: calc(var(--section-y) + var(--space-10)) 0 var(--section-y);
}

/* -------- THE NUMBERS -------- */
/* One solid panel, not three cards. The grid is unchanged in shape — three
   equal columns, rows still shared through subgrid so the figures line up
   across the three claims — but the background, padding and radius now belong
   to the container instead of to each child, and the only thing between the
   claims is a hairline. */
/* The flat indigo is now a texture, and the texture does not move with the
   panel. background-attachment: fixed anchors it to the viewport instead of to
   the element, so the panel reads as a window cut through the page onto
   something standing still behind it: scroll, and the texture appears to slide
   within the panel while never actually moving. The colour underneath is kept
   as the fallback — it is the same indigo the texture is made of, so a failed
   or slow image is invisible rather than a white hole behind white type.

   The blur is baked into the file (gaussian, at 1920 wide) rather than applied
   with filter: blur(). A filter on this element would make it a containing
   block, and a containing block is exactly what background-attachment: fixed
   resolves against — so the CSS version of the blur would quietly cancel the
   effect it was meant to soften. Re-blurring means re-exporting the asset. */
.rv-stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-template-rows: auto auto 1fr;
  gap: 0;
  padding: clamp(36px, 4vw, 56px) clamp(20px, 2.4vw, 36px);
  border-radius: var(--radius-xl);
  background-color: var(--color-primary-light);
  background-image: url("images/stat-texture-bg.webp");
  background-repeat: no-repeat;
  background-position: center center;
  background-size: cover;
  background-attachment: fixed;
  color: var(--color-white);
}

.rv-stat {
  display: grid;
  grid-row: 1 / -1;
  grid-template-rows: subgrid;
  padding: 0 clamp(20px, 2.6vw, 40px);
  color: inherit;
}

/* The separator is a border on the claim, not a gap between boxes: on a solid
   panel a gap would read as nothing at all. */
.rv-stat + .rv-stat {
  border-left: 1px solid rgb(255 255 255 / 0.2);
}

.rv-stat-lead { grid-row: 1; }
.rv-figure    { grid-row: 2; }
.rv-stat-label { grid-row: 3; }

@supports not (grid-template-rows: subgrid) {
  .rv-stat {
    display: flex;
    flex-direction: column;
  }

  .rv-stat-lead,
  .rv-figure,
  .rv-stat-label {
    grid-row: auto;
  }
}

.rv-stat-lead {
  font-size: 13px;
  font-weight: 500;
  color: inherit;
  opacity: 0.85;
  margin-bottom: var(--space-2);
}

.rv-figure {
  font-family: var(--font-heading);
  font-size: 54px;
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.01em;
  color: inherit;
}

.rv-stat-label {
  margin-top: var(--space-4);
  font-size: 15px;
  color: inherit;
}

.rv-stats-note {
  margin-top: 24px;
  font-size: 12px;
  line-height: 1.5;
  color: var(--color-text-muted);
}

/* -------- THE DISCLAIMER UNDER EVERY INSTALL BUTTON -------- */
/* Alignment is inherited rather than set: the hero centres its copy and the
   closing band left-aligns it, and the note should follow whichever it is in.
   The class is doubled because `.cta-band p` would otherwise out-specify it
   and paint the fine print the same weight as the paragraph above it. */
.cta-note,
.cta-note.cta-note {
  margin-top: 14px;
  font-size: 12px;
  line-height: 1.5;
  color: var(--color-text-muted);
}

/* on the hero it sits on the video, where the muted grey would disappear;
   dimmer than the lede above it so it still reads as fine print */
.lux-stage [data-lux="dark"] .cta-note {
  color: rgb(255 255 255 / 0.62);
}

/* =============================================
   PRICING GRID
============================================= */
.highlights {
  padding: var(--section-y) 0;
}

.pricing-cards {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: auto auto auto 1fr auto;
  gap: var(--space-6);
  padding: var(--space-8) 0;
}

.pricing-card {
  position: relative;
  display: grid;
  grid-row: 1 / -1;
  grid-template-rows: subgrid;
  row-gap: var(--space-5);
  background-color: var(--color-white);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-10) var(--space-6);
  text-align: center;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
  transition: transform var(--transition), border-color var(--transition),
              box-shadow var(--transition);
}

@supports not (grid-template-rows: subgrid) {
  .pricing-card {
    display: flex;
    flex-direction: column;
  }

  .pricing-desc {
    min-height: var(--space-10);
  }

  .pricing-features {
    flex: 1;
  }
}

.pricing-card:hover,
.pricing-card:focus-within {
  transform: scale(1.03);
  z-index: 2;
  border-color: rgb(var(--ring-rgb));
  box-shadow: 0 0 0 3px rgb(var(--ring-rgb) / 0.2);
}

.pricing-card-featured {
  border-color: var(--color-primary);
  box-shadow: 0 0 0 1px var(--color-primary),
              0 1px 2px rgba(0, 0, 0, 0.05);
  z-index: 1;
}

.pricing-badge {
  position: absolute;
  top: -16px;
  left: 50%;
  transform: translateX(-50%);
  background-color: var(--color-primary);
  color: var(--color-white);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.03em;
  padding: 8px 16px;
  border-radius: var(--radius-pill);
  white-space: nowrap;
}

.pricing-card h3 {
  font-family: var(--font-heading);
  font-size: 24px;
  font-weight: 700;
  line-height: 1.2;
  color: var(--color-text-primary);
  margin-bottom: var(--space-2);
}

.pricing-desc {
  font-size: 13px;
  line-height: 1.5;
  letter-spacing: -0.02em;
  color: var(--color-text-secondary);
}

.price {
  align-self: center;
}

.price .amount {
  font-family: var(--font-heading);
  font-size: 40px;
  font-weight: 800;
  line-height: 1;
  color: var(--color-text-primary);
}

.price .period {
  font-size: 13px;
  color: var(--color-text-muted);
  margin-left: 4px;
}

.pricing-features {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  text-align: left;
}

.pricing-features li {
  position: relative;
  padding-left: var(--space-6);
  font-size: 13px;
  line-height: 1.5;
  letter-spacing: -0.02em;
  color: var(--color-text-secondary);
}

.pricing-features li::before {
  content: "";
  position: absolute;
  left: 2px;
  top: 1px;
  width: 7px;
  height: 13px;
  border-right: 2.5px solid var(--color-success-green-ink);
  border-bottom: 2.5px solid var(--color-success-green-ink);
  transform: rotate(45deg);
}

.pricing-card .btn-outline {
  color: var(--color-success-green-ink);
  border-color: var(--color-success-green-ink);
}

.pricing-card .btn-outline:hover,
.pricing-card .btn-outline:focus-visible {
  background-color: var(--color-success-green);
  border-color: var(--color-success-green);
  color: var(--color-text-primary);
}

.pricing-more {
  display: flex;
  justify-content: center;
  margin-top: var(--space-4);
}

/* =============================================
   FONCTIONNALITÉS
============================================= */
.feature-grid {
  padding: var(--section-y) 0;
}

/* container-wide, not container: this block used to sit 80px inboard of the
   statistics panel above it and the closing band below it, which read as an
   indent rather than as a choice. It now opens on the same gutter as both.

   The intro track is 440px because that is the max-width .fg-intro already
   declares — the 360px track was the only thing keeping it from reaching it —
   and because it is the width at which the French heading settles on three
   lines without pushing the English one down to two. */
.fg-layout {
  display: grid;
  grid-template-columns: minmax(0, 440px) minmax(0, 1fr);
  gap: 72px;
  align-items: start;
}

.fg-intro {
  position: sticky;
  top: 120px;
  max-width: 440px;
  z-index: 4;
}

.fg-intro h2 {
  font-family: var(--font-heading);
  font-size: clamp(28px, 4.4vw, 40px);
  font-weight: 800;
  line-height: 1.18;
  letter-spacing: 0;
  margin-bottom: 16px;
  color: var(--color-text-primary);
}

.fg-intro p {
  font-size: 15px;
  color: var(--color-text-secondary);
  margin-bottom: 20px;
}

.fg-stack {
  display: flex;
  flex-direction: column;
  gap: 0;
}

.stack-card {
  position: sticky;
  top: 0;
  height: max(var(--card-scroll), 640px);
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding-top: 160px;
}

@media (max-height: 780px) {
  .stack-card {
    padding-top: 96px;
    height: max(var(--card-scroll), 576px);
  }
}

@media (max-height: 640px) {
  .stack-card {
    padding-top: 56px;
    height: max(var(--card-scroll), 536px);
  }
}

.stack-card-inner {
  --tint-1: #f3f2fe;
  --tint-2: #e5e2fd;
  --tint-3: #cfc9fb;
  --strand-color: rgba(124, 108, 232, 0.07);
  --strand: var(--strand-color);
  --wave-stroke: rgba(74, 60, 178, 0.22);

  position: relative;
  width: 100%;
  height: 480px;
  min-height: 480px;
  max-height: 480px;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.82fr);
  align-items: center;
  gap: 32px;
  padding: 40px 40px 0;
  border-radius: var(--radius-2xl);
  border: 1px solid rgba(65, 53, 230, 0.12);
  overflow: hidden;

  background:
    repeating-linear-gradient(
      var(--strand-angle),
      transparent 0 26px,
      var(--strand) 26px 27px,
      transparent 27px 63px
    ),
    radial-gradient(72% 58% at var(--warp-a), var(--tint-3) 0%, transparent 62%),
    radial-gradient(64% 62% at var(--warp-b), var(--tint-1) 0%, transparent 58%),
    radial-gradient(88% 72% at var(--warp-c), var(--tint-2) 0%, transparent 70%),
    linear-gradient(var(--base-angle), var(--tint-1) 0%, var(--tint-2) 52%, var(--tint-3) 100%);

  transform-origin: top center;
  will-change: transform;
}

.stack-card:nth-child(1) .stack-card-inner { --warp-a: 18% 12%;  --warp-b: 88% 76%; --warp-c: 46% 104%; --base-angle: 135deg; --strand-angle: 24deg; }
.stack-card:nth-child(2) .stack-card-inner { --warp-a: 82% 18%;  --warp-b: 12% 70%; --warp-c: 60% -8%;  --base-angle: 158deg; --strand-angle: 68deg; }
.stack-card:nth-child(3) .stack-card-inner { --warp-a: 50% 108%; --warp-b: 74% 8%;  --warp-c: 8% 44%;   --base-angle: 112deg; --strand-angle: 12deg; }
.stack-card:nth-child(4) .stack-card-inner { --warp-a: 6% 62%;   --warp-b: 62% 96%; --warp-c: 92% 22%;  --base-angle: 172deg; --strand-angle: 47deg; }
.stack-card:nth-child(5) .stack-card-inner { --warp-a: 92% 54%;  --warp-b: 28% 4%;  --warp-c: 54% 88%;  --base-angle: 124deg; --strand-angle: 80deg; }
.stack-card:nth-child(6) .stack-card-inner { --warp-a: 34% 92%;  --warp-b: 96% 40%; --warp-c: 14% 12%;  --base-angle: 146deg; --strand-angle: 33deg; }
.stack-card:nth-child(7) .stack-card-inner { --warp-a: 68% 6%;   --warp-b: 20% 88%; --warp-c: 100% 62%; --base-angle: 104deg; --strand-angle: 59deg; }
.stack-card:nth-child(8) .stack-card-inner { --warp-a: 10% 34%;  --warp-b: 78% 62%; --warp-c: 40% 2%;   --base-angle: 165deg; --strand-angle: 18deg; }

/* =============================================
   WAVE BACKGROUND
============================================= */

.stack-card-inner.has-waves {
  --strand: transparent;
}

.stack-card-waves {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}

.stack-card-waves svg {
  display: block;
  width: 100%;
  height: 100%;
  fill: none;
  stroke: var(--wave-stroke);
  stroke-width: 1;
}

.stack-card-copy,
.stack-card-visual {
  position: relative;
  z-index: 1;
}

@media (prefers-reduced-motion: reduce) {
  .stack-card-inner {
    transform: none !important;
  }

  .stack-card-waves {
    display: none;
  }

  .stack-card-inner.has-waves {
    --strand: var(--strand-color);
  }

  .cta-waves.has-waves ~ .cta-texture {
    --strand: var(--strand-color);
  }
}

.stack-card-copy h3 {
  font-family: var(--font-heading);
  font-size: 35px;
  font-weight: 800;
  line-height: 1.18;
  letter-spacing: 0;
  margin-bottom: 16px;
  color: var(--color-text-primary);
}

.stack-card-copy p {
  font-size: 15px;
  color: var(--color-text-secondary);
  margin-bottom: 24px;
  max-width: 52ch;
}

.stack-card-visual {
  display: flex;
  justify-content: center;
  align-self: stretch;
  align-items: flex-end;
}

.card-anim {
  display: block;
  /* a fixed width, never a percentage height: the grid row here is content
     sized, so a % height makes the row solve for the full column width and
     the card blows out to ~720px */
  width: min(256px, 100%);
  height: auto;
  aspect-ratio: 244 / 380;
  /* the phone in the clip already bleeds off its own bottom edge, so it
     meets the card's bottom the way the old mock panel did */
  object-fit: contain;
  object-position: bottom center;
}

/* =============================================
   FAQ
============================================= */
.faq {
  padding: var(--section-y) 0;
}

.faq-list {
  max-width: 800px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
}

/* Centred under the FAQ list, on the same 800px measure the questions use so
   it lines up with them rather than with the wider container. */
.faq-blog-cta {
  max-width: 800px;
  margin: var(--space-12) auto 0;
  display: flex;
  justify-content: center;
}

.faq-item {
  background-color: transparent;
  border: none;
  border-bottom: 1px solid var(--color-border);
  border-radius: 0;
  padding: 0;
}

.faq-item summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 16px 0;
  font-family: var(--font-heading);
  font-size: 19px;
  font-weight: 600;
  text-align: left;
  color: var(--color-text-primary);
  cursor: pointer;
  list-style: none;
  transition: opacity var(--transition);
}

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

.faq-item summary:hover .faq-q {
  text-decoration: underline;
  text-underline-offset: 3px;
}

.faq-chevron {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  color: var(--color-success-green-ink);
  transition: transform 0.2s ease-out;
}

.faq-item[open] .faq-chevron {
  transform: rotate(180deg);
}

.faq-answer {
  overflow: hidden;
}

.faq-answer.faq-animating {
  transition: height 0.2s ease-out;
}

.faq-answer-inner {
  padding: 0 0 16px;
  max-width: 68ch;
}

.faq-answer p {
  font-size: 15px;
  font-weight: 400;
  color: var(--color-text-secondary);
}

/* =============================================
   CTA BAND
============================================= */
.cta-band {
  --tint-1: var(--cta-tint);
  --tint-2: #e5e2fd;
  --tint-3: #cfc9fb;
  --strand-color: rgba(74, 60, 178, 0.22);
  --strand: var(--strand-color);
  --wave-stroke: var(--strand-color);
  --warp-a: 82% 18%;
  --warp-b: 12% 70%;
  --warp-c: 60% -8%;
  --base-angle: 158deg;
  --strand-angle: 68deg;

  position: relative;
  isolation: isolate;
  overflow: hidden;
  padding: clamp(72px, 9vw, 132px) 0;
}

/* The texture, sheen and wave layers below already fade in over the first
   180px, but the band's own base colour did not -- it started at full tint on
   row one, which is the hard line where the CTA meets the white section above.
   Fading the base over the same 180px puts every layer on the same ramp. */
main > section.cta-band {
  background-color: var(--color-white);
  background-image: linear-gradient(
    to bottom,
    var(--color-white) 0,
    var(--tint-1) 180px
  );
}

.cta-texture,
.cta-sheen,
.cta-waves {
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 180px);
  mask-image: linear-gradient(to bottom, transparent 0, #000 180px);
}

.cta-texture {
  position: absolute;
  inset: 0;
  z-index: -3;
  pointer-events: none;
  background:
    repeating-linear-gradient(
      var(--strand-angle),
      transparent 0 26px,
      var(--strand) 26px 27px,
      transparent 27px 63px
    ),
    radial-gradient(72% 58% at var(--warp-a), var(--tint-3) 0%, transparent 62%),
    radial-gradient(64% 62% at var(--warp-b), var(--tint-1) 0%, transparent 58%),
    radial-gradient(88% 72% at var(--warp-c), var(--tint-2) 0%, transparent 70%),
    linear-gradient(var(--base-angle), var(--tint-1) 0%, var(--tint-2) 52%, var(--tint-3) 100%);
}

.cta-sheen {
  position: absolute;
  inset: 0;
  z-index: -2;
  pointer-events: none;
  background: linear-gradient(
    to right,
    rgba(255, 255, 255, 0.62) 0%,
    rgba(255, 255, 255, 0.20) 46%,
    rgba(207, 201, 251, 0.30) 100%
  );
}

.cta-waves {
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
}

.cta-waves.has-waves ~ .cta-texture {
  --strand: transparent;
}

.faq {
  isolation: isolate;
}

.faq::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: clamp(160px, 24vh, 280px);
  z-index: -1;
  pointer-events: none;
  background: linear-gradient(to bottom, rgba(243, 242, 254, 0), var(--cta-tint));
}

.cta-inner {
  max-width: var(--container-wide);
  text-align: left;
}

.cta-copy {
  max-width: 760px;
}

.cta-band h2 {
  font-family: var(--font-heading);
  font-size: clamp(34px, 4.3vw, 54px);
  font-weight: 800;
  line-height: 1.08;
  letter-spacing: -0.015em;
  margin-bottom: 16px;
  color: var(--color-text-primary);
  text-wrap: balance;
}

.cta-band p {
  font-size: 16px;
  color: var(--color-text-secondary);
  max-width: 620px;
  margin-bottom: 40px;
}

.cta-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px;
}

.cta-btn {
  padding: 20px 40px;
  font-size: 15px;
}

/* =============================================
   FOOTER
============================================= */
.site-footer {
  background-color: var(--color-text-primary);
  padding: 60px 0 44px;
}

.footer-inner {
  max-width: calc(var(--container-width) + var(--edge-shift) * 2);
  display: grid;
  grid-template-columns: minmax(0, 480px) minmax(0, 1fr);
  align-items: start;
  column-gap: 48px;
  row-gap: 24px;
  padding-bottom: 4px;
}

.footer-learn {
  grid-column: 1;
  grid-row: 1;
}

.footer-cols {
  grid-column: 2;
  grid-row: 1;
  justify-self: end;
}

.footer-inner::after {
  content: "";
  grid-column: 1 / -1;
  grid-row: 2;
  align-self: start;
  height: 0;
  border-top: 1px solid rgba(255, 255, 255, 0.12);
}

.footer-logo {
  grid-column: 1;
  grid-row: 2;
  align-self: center;
  padding-top: 24px;
}

.footer-copyright {
  grid-column: 2;
  grid-row: 2;
  justify-self: end;
  align-self: center;
  padding-top: 24px;
  font-size: 12px;
  line-height: 1.5;
  color: var(--color-white);
  opacity: 0.6;
}

.footer-logo {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  justify-self: start;
}

.footer-logo-mark {
  height: 30px;
  width: auto;
}

.footer-logo-word-stack {
  position: relative;
  display: inline-flex;
  flex-shrink: 0;
}

.footer-logo-word {
  height: 17px;
  width: auto;
  position: relative;
  top: 1px;
}

.footer-logo-word-beam {
  position: absolute;
  inset: 0;
  height: 100%;
  clip-path: inset(0 44% 0 0);
  filter: brightness(0) invert(1);
  pointer-events: none;
}

.footer-links {
  display: flex;
  align-items: center;
  align-self: center;
  gap: 24px;
}

.footer-links a {
  color: var(--color-white);
  font-size: 13px;
  opacity: 0.75;
  transition: opacity var(--transition);
}

.footer-links a:hover {
  opacity: 1;
}

/* -------- APPRENDRE PLUS -------- */
.footer-learn {
  width: 100%;
}

.footer-learn h2 {
  font-family: var(--font-heading);
  font-size: 20px;
  line-height: 1.25;
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--color-white);
  margin-bottom: var(--space-1);
}

.footer-learn-sub {
  font-size: 13px;
  line-height: 1.4;
  color: var(--color-white);
  opacity: 0.62;
  margin-bottom: 12px;
}

.learn-form {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.lf-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}

.lf-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.lf-label {
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--color-white);
  opacity: 0.62;
}

.learn-form input,
.learn-form textarea {
  font-family: inherit;
  font-size: 13px;
  color: var(--color-white);
  background-color: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: var(--radius-sm);
  padding: 8px 8px;
  width: 100%;
  transition: border-color var(--transition), background-color var(--transition),
              box-shadow var(--transition);
}

.learn-form textarea {
  resize: vertical;
  min-height: 44px;
  line-height: 1.4;
}

.learn-form input::placeholder,
.learn-form textarea::placeholder {
  color: rgba(255, 255, 255, 0.4);
}

.learn-form input:hover,
.learn-form textarea:hover {
  border-color: rgba(255, 255, 255, 0.28);
}

.learn-form input:focus,
.learn-form textarea:focus {
  outline: none;
  background-color: rgba(255, 255, 255, 0.1);
  border-color: rgb(var(--ring-rgb));
  box-shadow: 0 0 0 3px rgb(var(--ring-rgb) / 0.35);
}

.lf-actions {
  --lf-action-h: 36px;
  display: flex;
  align-items: stretch;
  gap: 12px;
  margin-top: 4px;
  flex-wrap: wrap;
}

.shopify-badge {
  position: relative;
  flex: 0 0 auto;
  align-self: stretch;
  width: calc(var(--lf-action-h) * 830 / 220);
  border-radius: var(--radius-sm);
  overflow: hidden;
}

.shopify-badge-face {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.shopify-badge-light {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity var(--transition);
}

.shopify-badge:hover .shopify-badge-light,
.shopify-badge:focus-visible .shopify-badge-light {
  opacity: 1;
}

.lf-submit {
  margin-top: 0;
  align-self: stretch;
  background-color: transparent;
  color: var(--color-white);
  border-color: rgba(255, 255, 255, 0.32);
}

.lf-submit:hover,
.lf-submit:focus-visible {
  background-color: var(--color-white);
  border-color: var(--color-white);
  color: var(--color-text-primary);
}

/* -------- THE THREE LINK COLUMNS -------- */
/* Four columns, not three: the BeamCart list used to carry seven links against
   two and two, so it ran a full row deeper than its neighbours. Splitting it
   into BeamCart + Resources lets all four tops and bottoms sit level. */
.footer-cols {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, auto));
  align-items: start;
  gap: 20px 44px;
}

.footer-col-title {
  font-family: var(--font-heading);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--color-white);
  margin-bottom: 16px;
}

.footer-col ul {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.footer-col a {
  color: var(--color-white);
  font-size: 13px;
  opacity: 0.7;
  transition: opacity var(--transition);
}

.footer-col a:hover {
  opacity: 1;
}

/* =============================================
   SIMPLE INNER PAGE
============================================= */
/* =============================================
   SERVICES PAGE HEAD
============================================= */

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

.svc-head {
  padding: calc(var(--header-bottom) + var(--space-22)) 0 var(--section-y);
  text-align: center;
}

.svc-head .eyebrow {
  margin-bottom: 24px;
}

.svc-head h1 {
  font-family: var(--font-heading);
  font-size: clamp(34px, 4.6vw, 56px);
  font-weight: 800;
  line-height: 1.12;
  letter-spacing: -0.02em;
  color: var(--color-text-primary);
  max-width: 16ch;
  margin: 0 auto 20px;
}

.svc-lede {
  font-size: 15px;
  line-height: 1.65;
  color: var(--color-text-secondary);
  max-width: 62ch;
  margin: 0 auto;
}

/* =============================================
   SERVICES PAGE CAPABILITY ROWS
============================================= */
.svc-features {
  padding: var(--section-y) 0;
}

.svc-rows {
  display: flex;
  flex-direction: column;
  gap: 96px;
}

.svc-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: center;
  gap: 72px;
}

.svc-row[data-side="right"] .svc-row-copy  { grid-column: 1; grid-row: 1; }
.svc-row[data-side="right"] .svc-row-media { grid-column: 2; grid-row: 1; }
.svc-row[data-side="left"]  .svc-row-media { grid-column: 1; grid-row: 1; }
.svc-row[data-side="left"]  .svc-row-copy  { grid-column: 2; grid-row: 1; }

.svc-row-copy h2 {
  font-family: var(--font-heading);
  font-size: 34px;
  font-weight: 800;
  line-height: 1.18;
  letter-spacing: -0.01em;
  color: var(--color-text-primary);
  margin-bottom: 16px;
}

.svc-row-copy p {
  font-size: 15px;
  line-height: 1.65;
  color: var(--color-text-secondary);
  max-width: 52ch;
}

/* -------- THE POINT LIST -------- */
.svc-points {
  list-style: none;
  margin: 24px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 24px;
  max-width: 46ch;
}

.svc-point {
  display: grid;
  grid-template-columns: 40px minmax(0, 1fr);
  gap: 16px;
  align-items: start;
}

.svc-point-ico {
  width: 40px;
  height: 40px;
  border-radius: var(--radius);
  background-color: transparent;
  border: 1.5px solid var(--color-success-green);
  display: flex;
  align-items: center;
  justify-content: center;
}

.svc-point-ico svg {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: var(--color-success-green);
  stroke-width: 1.9;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.svc-point h3 {
  font-family: var(--font-heading);
  font-size: 15px;
  font-weight: 700;
  line-height: 1.35;
  letter-spacing: -0.005em;
  color: var(--color-text-primary);
  margin: 2px 0 4px;
}

.svc-point p {
  font-size: 14px;
  line-height: 1.6;
  color: var(--color-text-secondary);
  max-width: none;
  margin: 0;
}

.svc-row-media {
  aspect-ratio: 4 / 3;
  padding: 16px;
  border-radius: var(--radius-lg);
  background-color: var(--color-border);
}

/* The selector used to be `> img`, which missed the two shots that were later
   wrapped in <picture>: their height went unconstrained and the taller one
   pushed the box past 4/3, standing well above the rows beside it. The
   <picture> has to carry the full height itself, or the img's 100% has no
   definite height to resolve against and the box stretches to the content
   again. `scale-down` is `contain` that refuses to enlarge, so the one shot
   whose source is smaller than the frame is not blown up to fill it. */
.svc-row-media > picture {
  display: block;
  width: 100%;
  height: 100%;
}

.svc-row-media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: scale-down;
}

/* -------- THE CHART -------- */
.cmp {
  padding: var(--section-y) 0;
}

.cmp-scroll {
  position: relative;
  border-radius: var(--radius-lg);
}

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

.cmp-table {
  width: 100%;
  min-width: 760px;
  border-collapse: separate;
  border-spacing: 0;
  text-align: left;
}

/* -------- THE STICKY PLAN ROW -------- */
/* The rounding lives here, on all three plans, rather than only on the two
   tinted ones — Starter used to be the odd square-cornered block in the row. */
.cmp-table thead .cmp-plan {
  position: sticky;
  top: calc(var(--header-bottom) + var(--space-3));
  z-index: 3;
  background-color: var(--color-white);
  border-top-left-radius: var(--radius-lg);
  border-top-right-radius: var(--radius-lg);
  transition: top 0.3s ease;
}

/* Two stacked bars is one too many on a table read row by row. So the moment
   the plan row reaches the header, script.js sends the header away and adds
   this class: the row keeps going and parks at the top of the viewport
   instead, on the same 0.3s the header leaves on. It is handed back once the
   table is behind the reader. */
.cmp-pinned .cmp-table thead .cmp-plan {
  top: var(--space-3);
}

.cmp-table thead th {
  vertical-align: top;
  padding: var(--space-5) var(--space-4) var(--space-4);
  border-bottom: 1px solid var(--color-border);
}

.cmp-table thead .cmp-corner {
  background-color: transparent;
}

.cmp-plan {
  width: 20%;
  text-align: center;
}

.cmp-plan-name {
  display: block;
  font-family: var(--font-heading);
  font-size: 20px;
  font-weight: 700;
  line-height: 1.2;
  color: var(--color-text-primary);
}

.cmp-plan-price {
  display: block;
  margin: var(--space-3) 0 var(--space-4);
}

.cmp-amount {
  font-family: var(--font-heading);
  font-size: 30px;
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--color-text-primary);
}

.cmp-period {
  font-size: 12px;
  color: var(--color-text-muted);
  margin-left: 4px;
}

.cmp-blurb td {
  padding: var(--space-4);
  text-align: center;
  font-size: 12px;
  line-height: 1.5;
  letter-spacing: -0.02em;
  color: var(--color-text-secondary);
  border-bottom: 1px solid var(--color-border);
  vertical-align: top;
}

.cmp-blurb-cell.is-pro {
  background-color: var(--color-primary-softer);
}

.cmp-blurb-cell.is-featured {
  background-color: var(--color-primary-soft);
}

.cmp-blurb td span {
  display: inline-block;
  max-width: 28ch;
}

.cmp-cta {
  width: 100%;
  max-width: 192px;
}

.cmp-plan .btn-outline {
  color: var(--color-success-green-ink);
  border-color: var(--color-success-green-ink);
}

.cmp-plan .btn-outline:hover,
.cmp-plan .btn-outline:focus-visible {
  background-color: var(--color-success-green-ink);
  border-color: var(--color-success-green-ink);
  color: var(--color-white);
}

/* -------- THE FOUR NUMBERS THE PLANS ARE COMPARED ON -------- */
/* Commission, included hours, advisors and the top-up rate are what the page
   is read for, so they are set larger than the rest of the column — but in
   the column's own grey and weight, not as three different kinds of emphasis
   stacked on one number. Size carries it on its own.

   The vw term is what keeps the size honest: the binding case is not the
   1300px container but the 900px viewport where the cards take over, which
   leaves 136px of inner column for "40 h / month" — measured, not guessed,
   along with the 218px the column settles at once the container stops
   growing. Both ends stay well under the width that would start clipping,
   which is the margin the fallback font needs before Montserrat lands. */
.cmp-row-plan .cmp-val {
  font-size: clamp(15px, 1.75vw, 24px);
  line-height: 1.2;
  letter-spacing: -0.03em;
  white-space: nowrap;
}

/* -------- THE RECOMMENDED COLUMN -------- */
.cmp-val.is-pro {
  background-color: var(--color-primary-softer);
}

.cmp-val.is-featured {
  background-color: var(--color-primary-soft);
}

.cmp-table thead th.cmp-plan-pro {
  position: sticky;
  background-color: var(--color-primary-softer);
}

.cmp-table thead th.cmp-plan-featured {
  position: sticky;
  background-color: var(--color-primary-soft);
}

/* -------- GROUP ROWS -------- */
.cmp-group th {
  padding: 12px 16px;
  background-color: var(--color-bg-page);
  border-top: 1px solid var(--color-border);
  border-bottom: 1px solid var(--color-border);
  font-family: var(--font-heading);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.01em;
  color: var(--color-text-primary);
  position: sticky;
  left: 0;
}

/* -------- FEATURE ROWS -------- */
.cmp-row th,
.cmp-row td {
  border-bottom: 1px solid var(--color-border);
  font-size: 13px;
  line-height: 1.45;
  letter-spacing: -0.02em;
  color: var(--color-text-secondary);
  font-weight: 400;
}

.cmp-feature {
  position: sticky;
  left: 0;
  z-index: 2;
  width: 40%;
  background-color: var(--color-white);
  text-align: left;
}

.cmp-plain {
  display: block;
  padding: 16px 16px;
}

.cmp-label {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 16px 16px;
}

.cmp-label-text {
  min-width: 0;
}

.cmp-val {
  text-align: center;
  padding: 16px 16px;
  vertical-align: middle;
}

/* -------- THE INFO ICON AND THE BOX IT OPENS -------- */
.cmp-info-wrap {
  position: relative;
  display: inline-flex;
  flex-shrink: 0;
}

.cmp-info {
  display: grid;
  place-items: center;
  width: 18px;
  height: 18px;
  padding: 0;
  color: var(--color-primary);
  transition: color var(--transition), transform var(--transition);
}

.cmp-info-ico {
  width: 18px;
  height: 18px;
}

.cmp-info:hover,
.cmp-info:focus-visible,
.cmp-info.is-open {
  color: var(--color-primary-dark);
  transform: scale(1.08);
}

.cmp-tip {
  position: absolute;
  bottom: calc(100% + 9px);
  left: -8px;
  z-index: 20;
  width: max-content;
  max-width: min(300px, 60vw);
  padding: 8px 16px;
  border-radius: var(--radius);
  background-color: var(--color-text-primary);
  color: var(--color-white);
  font-size: 12px;
  line-height: 1.5;
  letter-spacing: -0.01em;
  text-align: left;
  white-space: normal;
  box-shadow: 0 8px 24px rgba(28, 32, 36, 0.28);

  opacity: 0;
  visibility: hidden;
  transform: translateY(4px);
  transition: opacity 0.16s ease, transform 0.16s ease, visibility 0.16s;
  pointer-events: none;
}

.cmp-info-wrap:hover .cmp-tip,
.cmp-info:focus-visible + .cmp-tip,
.cmp-info.is-open + .cmp-tip {
  opacity: 1;
  visibility: visible;
  transform: none;
}

.cmp-row th.cmp-feature:hover,
.cmp-row th.cmp-feature:focus-within {
  z-index: 6;
}

/* -------- INCLUDED / NOT INCLUDED -------- */
.cmp-tick {
  display: inline-grid;
  place-items: center;
  width: 22px;
  height: 22px;
  color: var(--color-success-green-ink);
}

.cmp-tick svg {
  width: 22px;
  height: 22px;
  stroke-width: 2.6;
}

.cmp-dash {
  display: inline-block;
  width: 13px;
  height: 2px;
  border-radius: 4px;
  background-color: var(--color-border);
  vertical-align: middle;
}

.cmp-note {
  margin-top: 24px;
  font-size: 12px;
  line-height: 1.6;
  letter-spacing: -0.02em;
  color: var(--color-text-muted);
  text-align: center;
}

/* -------- THE PLAN CAROUSEL -------- */
.cmp-cards {
  display: none;
}

.cmp-cards-track {
  position: relative;
  display: flex;
  gap: 16px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}

.cmp-cards-track::-webkit-scrollbar {
  display: none;
}

.cmp-cards-track:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 3px;
}

.cmp-card {
  position: relative;
  flex: 0 0 100%;
  scroll-snap-align: start;
  background-color: var(--color-white);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: 24px 16px 16px;
}

/* The same two tints the table paints its Pro and Enterprise columns with.
   A card is one whole column, so the whole card carries it. */
.cmp-card-pro {
  background-color: var(--color-primary-softer);
}

.cmp-card-featured {
  background-color: var(--color-primary-soft);
}

.cmp-card-head {
  text-align: center;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--color-border);
}

.cmp-card-blurb {
  max-width: 34ch;
  margin: 0 auto 16px;
  font-size: 12px;
  line-height: 1.5;
  letter-spacing: -0.02em;
  color: var(--color-text-secondary);
}

.cmp-card .cmp-cta {
  width: 100%;
  max-width: 100%;
}

.cmp-card .btn-outline {
  color: var(--color-success-green-ink);
  border-color: var(--color-success-green-ink);
}

.cmp-card .btn-outline:hover,
.cmp-card .btn-outline:focus-visible {
  background-color: var(--color-success-green-ink);
  border-color: var(--color-success-green-ink);
  color: var(--color-white);
}

.cmp-card-group {
  padding: 16px 0 8px;
  font-family: var(--font-heading);
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.01em;
  color: var(--color-text-primary);
}

.cmp-card-row {
  display: flex;
  align-items: center;
  gap: 12px;
  border-bottom: 1px solid var(--color-border);
}

.cmp-card-row .cmp-card-label {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1 1 auto;
  min-width: 0;
  width: auto;
  padding: 12px 0;
  font-size: 13px;
  line-height: 1.45;
  letter-spacing: -0.02em;
  color: var(--color-text-secondary);
  text-align: left;
}

.cmp-card-value {
  display: flex;
  align-items: center;
  flex: 0 0 auto;
  font-size: 13px;
  line-height: 1.45;
  letter-spacing: -0.02em;
  color: var(--color-text-secondary);
  text-align: right;
}

.cmp-card .cmp-tip {
  max-width: min(255px, calc(100vw - 90px));
}

.cmp-card-list > *:last-child {
  border-bottom: none;
}

/* -------- ARROWS AND DOTS -------- */
.cmp-cards-viewport {
  position: relative;
}

.cmp-cards-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  margin-top: 16px;
}

.cmp-arrow {
  position: absolute;
  top: 40px;
  z-index: 2;
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  flex-shrink: 0;
  border: 1px solid var(--color-primary);
  border-radius: 50%;
  background-color: var(--color-white);
  color: var(--color-primary);
  box-shadow: 0 2px 10px rgba(28, 32, 36, 0.14);
  transition: background-color var(--transition), border-color var(--transition),
              color var(--transition), opacity var(--transition);
}

.cmp-arrow-prev { left: 8px; }
.cmp-arrow-next { right: 8px; }

.cmp-arrow svg {
  width: 15px;
  height: 15px;
}

.cmp-arrow:hover:not(:disabled),
.cmp-arrow:focus-visible {
  background-color: var(--color-primary);
  border-color: var(--color-primary);
  color: var(--color-white);
}

.cmp-arrow:disabled {
  opacity: 0.32;
  cursor: default;
}

.cmp-dots {
  display: flex;
  align-items: center;
  gap: 8px;
}

.cmp-dot {
  position: relative;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background-color: var(--color-border);
  transition: background-color var(--transition), transform var(--transition);
}

.cmp-dot::before {
  content: "";
  position: absolute;
  inset: -13px -9px;
}

.cmp-dot.is-active {
  background-color: var(--color-primary);
  transform: scale(1.4);
}

@media (max-width: 900px) {
  .cmp-enhanced .cmp-scroll {
    display: none;
  }

  .cmp-enhanced .cmp-cards {
    display: block;
  }
}

@media (max-width: 900px) {
  .svc-head {
    padding: calc(var(--header-bottom) + var(--space-12)) 0 var(--section-y);
  }

  .svc-features {
    padding: 56px 0 72px;
  }

  .svc-rows {
    gap: 64px;
  }

  .svc-row {
    grid-template-columns: 1fr;
    gap: 28px;
  }

  .svc-row[data-side="right"] .svc-row-copy,
  .svc-row[data-side="left"]  .svc-row-copy {
    grid-column: 1;
    grid-row: 1;
  }

  .svc-row[data-side="right"] .svc-row-media,
  .svc-row[data-side="left"]  .svc-row-media {
    grid-column: 1;
    grid-row: 2;
  }

  .svc-row-copy h2 {
    font-size: 27px;
  }

  .cmp {
    padding-bottom: 64px;
  }

  .cmp-scroll {
    overflow-x: auto;
    overscroll-behavior-x: contain;
    border: 1px solid var(--color-border);
  }

  .cmp-table thead th {
    position: static;
  }

  .cmp-blurb {
    display: none;
  }

  .cmp-table {
    min-width: 680px;
  }

  .cmp-table thead th {
    padding: 16px 12px 16px;
  }

  .cmp-amount {
    font-size: 24px;
  }

  .cmp-label,
  .cmp-plain,
  .cmp-val {
    padding: 12px 16px;
  }

  .cmp-group th {
    padding: 12px 16px;
    font-size: 14px;
  }
}

@media (max-width: 600px) {
  .cmp-table {
    min-width: 600px;
  }

  .cmp-feature {
    width: 44%;
  }

  .cmp-plan-name {
    font-size: 17px;
  }

  .cmp-amount {
    font-size: 21px;
  }

  .cmp-cta {
    padding: 8px 8px;
    font-size: 13px;
  }
}

.page-simple {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100svh;
}

.page-simple main {
  flex: 1;
  background-color: var(--color-white);
}

.page-head {
  padding: calc(var(--header-bottom) + var(--space-22)) 0 var(--section-y);
}

.page-head h1 {
  font-family: var(--font-heading);
  font-size: 52px;
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: var(--color-text-primary);
}

@media (max-width: 600px) {
  .page-head {
    padding: calc(var(--header-bottom) + var(--space-12)) 0 var(--section-y);
  }

  .page-head h1 {
    font-size: 36px;
  }
}

/* =============================================
   PAGE 404
============================================= */
.page-center {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100svh;
}

.page-center main {
  flex: 1 0 auto;
  display: flex;
}

.notfound {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: calc(var(--header-height) + 40px) 0 56px;
}

.notfound-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 40px;
}

.notfound-code {
  font-family: var(--font-heading);
  font-size: clamp(110px, 25vw, 240px);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.03em;
  color: var(--color-primary);
}

.notfound-copy {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}

.notfound-title {
  font-family: var(--font-heading);
  font-size: 32px;
  font-weight: 800;
  line-height: 1.2;
  color: var(--color-text-primary);
}

.notfound-text {
  font-size: 15px;
  color: var(--color-text-secondary);
}

.notfound-ctas {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  flex-wrap: wrap;
}

.thanks-icon {
  display: grid;
  place-items: center;
  width: clamp(84px, 12vw, 132px);
  height: clamp(84px, 12vw, 132px);
  margin-bottom: 8px;
  border-radius: 50%;
  background-color: var(--color-success-green);
  color: var(--color-text-primary);
}

.thanks-icon svg {
  width: 42%;
  height: 42%;
}

/* =============================================
   CARD GRAIN
============================================= */
.pricing-card,
.stack-card-inner,
.store-card,
.blog-preview,
.blog-list-item {
  position: relative;
  isolation: isolate;
}

.pricing-card::after,
.stack-card-inner::after,
.store-card::after,
.blog-preview::after,
.blog-list-item::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  border-radius: inherit;
  background-repeat: repeat;
  mix-blend-mode: multiply;
  opacity: var(--grain-strength);
  background-image: var(--grain-1);
}

.pricing-card:nth-child(4n + 2)::after,
.stack-card:nth-child(4n + 2) .stack-card-inner::after,
.store-item:nth-child(4n + 2) .store-card::after {
  background-image: var(--grain-2);
}

.pricing-card:nth-child(4n + 3)::after,
.stack-card:nth-child(4n + 3) .stack-card-inner::after,
.store-item:nth-child(4n + 3) .store-card::after {
  background-image: var(--grain-3);
  opacity: calc(var(--grain-strength) * 0.75);
}

.pricing-card:nth-child(4n)::after,
.stack-card:nth-child(4n) .stack-card-inner::after,
.store-item:nth-child(4n) .store-card::after {
  background-image: var(--grain-4);
}

/* =============================================
   RESPONSIVE
============================================= */
@media (max-width: 1100px) {
  .fg-layout {
    grid-template-columns: 1fr;
    gap: 40px;
  }

  .fg-intro {
    position: static;
  }

  .hiw-block[data-side="left"] {
    grid-template-columns: minmax(0, 410px) minmax(0, 1fr);
  }

  .hiw-block[data-side="right"] {
    grid-template-columns: minmax(0, 1fr) minmax(0, 410px);
  }

  .hiw-block {
    gap: 48px;
  }

  .stack-card-inner {
    padding: 32px 32px 0;
  }

  .stack-card-copy h3 {
    font-size: 30px;
  }
}

@media (max-width: 900px) {
  :root {
    --section-y: var(--space-18);
    --section-gap: var(--space-16);

    /* 76vw is a fraction of a desktop window; on a phone it is a postage
       stamp. The reel takes the screen instead, and the band's top padding
       follows it from here. It is also short enough that the copy and its top
       half fit in one screen without help, so the hero's floor goes back to
       being the fold and nothing more. */
    --hero-reel-w: calc(100vw - 32px);
    --hero-floor: 100svh;
  }

  .main-nav {
    position: fixed;
    top: calc(var(--header-bottom) + 8px);
    left: 12px;
    right: 12px;
    border-radius: var(--radius-xl);
    background-color: rgb(var(--hd-bg) / 0.94);
    -webkit-backdrop-filter: blur(28px) saturate(165%);
    backdrop-filter: blur(28px) saturate(165%);
    border-bottom: 1px solid var(--hd-border);
    flex-direction: column;
    align-items: flex-start;
    padding: 24px;
    gap: 20px;
    transform: translateY(-150%);
    opacity: 0;
    visibility: hidden;
    transition: transform var(--transition), opacity var(--transition), visibility 0s linear 0.25s;
  }

  .main-nav.open {
    transform: translateY(0);
    opacity: 1;
    visibility: visible;
    transition-delay: 0s;
  }

  .header-actions .btn-sm {
    display: none;
  }

  .header-actions {
    margin-left: auto;
  }

  .header-inner {
    gap: 16px;
  }

  .mobile-menu-toggle {
    display: flex;
  }

  .hero {
    --hero-gap-top: 40px;
  }

  /* A phone crops the 16/9 frame down to the bright middle of the beam, so the
     scrim is stronger here for legibility. It still closes progressively, but
     now reaches the same true black used at the top of the band. */
  .hero-scrim {
    background: linear-gradient(
      to bottom,
      rgba(0, 0, 0, 0.56) 0%,
      rgba(0, 0, 0, 0.46) 40%,
      rgba(0, 0, 0, 0.50) 54%,
      rgba(0, 0, 0, 0.56) 64%,
      rgba(0, 0, 0, 0.64) 72%,
      rgba(0, 0, 0, 0.72) 79%,
      rgba(0, 0, 0, 0.80) 85%,
      rgba(0, 0, 0, 0.87) 90%,
      rgba(0, 0, 0, 0.94) 95%,
      rgba(0, 0, 0, 0.98) 98%,
      var(--lux-seam-black) 100%
    );
  }

  .hero-copy {
    max-width: 100%;
  }

  .hero h1 {
    font-size: clamp(32px, 9vw, 38px);
  }

  .hero-shot img {
    border-radius: var(--radius);
  }

  .hero-corner {
    border-radius: var(--radius);
    box-shadow: 0 16px 32px rgba(0, 0, 0, 0.44),
                0 3px 8px rgba(0, 0, 0, 0.28);
  }

  .lux-band {
    --corner-w: min(44vw, 240px);
    --corner-rise: 0.7;
  }

  /* It used to carry the reel and needed clearing underneath. It carries the
     progress markers now and the band's tail is all the room they want. */
  .hero-demo {
    margin-bottom: 0;
  }

  .hiw-blocks {
    gap: 64px;
  }

  .hiw-block,
  .hiw-block[data-side="left"],
  .hiw-block[data-side="right"] {
    grid-template-columns: 1fr;
    gap: 28px;
  }

  .hiw-block[data-side="left"] .hiw-frame,
  .hiw-block[data-side="right"] .hiw-frame {
    grid-column: 1;
    grid-row: 1;
  }

  .hiw-block[data-side="left"] .hiw-bubble,
  .hiw-block[data-side="right"] .hiw-bubble {
    grid-column: 1;
    grid-row: 2;
  }

  .hiw-frame {
    max-width: 460px;
    margin: 0 auto;
  }

  .hiw-num {
    top: -20px;
    width: 46px;
    height: 46px;
    font-size: 21px;
  }

  .hiw-block[data-side="left"]  .hiw-num { right: 6px; }
  .hiw-block[data-side="right"] .hiw-num { left: 6px; }

  .hiw-frame-button {
    padding: var(--space-6);
  }

  .section-heading h2 {
    line-height: 1.24;
  }

  .footer-inner {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: 32px;
    row-gap: 40px;
  }

  .footer-learn {
    grid-column: 1 / -1;
    grid-row: 1;
  }

  .footer-cols {
    display: contents;
  }

  .footer-col {
    grid-row: auto;
  }

  .footer-logo {
    grid-column: 2;
    grid-row: 3;
    justify-self: stretch;
    align-self: center;
    width: 100%;
    gap: 12px;
    padding-top: 0;
  }

  .footer-copyright {
    grid-column: 1 / -1;
    grid-row: 4;
    justify-self: end;
    padding-top: 20px;
  }

  .footer-inner::after {
    grid-row: 4;
  }

  /* The mark is wrapped in a <picture>, so the <picture> — not the <img> —
     is the flex item, and the width has to land on it. A percentage on the
     image resolves against that wrapper, which is itself sizing to its own
     content: 26% of a shrink-wrapped box left a 12px mark standing beside a
     96px wordmark.

     28.5% against the stack's 62% is not a round number, it is the one that
     reproduces the desktop proportion. The two files have different aspect
     ratios — the mark is 186x172, the wordmark 340x82 — so matching their
     rendered HEIGHTS, which is what `height: 30px` and `height: 17px` do up
     on desktop, means their widths cannot match. 30/17 of height works out
     to 0.4602 of width, and 0.4602 x 62% is 28.5%. The max-widths carry the
     same ratio: 0.4602 x 150px is 69px. Change one and change the other, or
     the icon drifts out of step with the word again. */
  .footer-logo > picture {
    display: block;
    width: 28.5%;
    max-width: 69px;
  }

  .footer-logo-mark {
    height: auto;
    width: 100%;
  }

  .footer-logo-word-stack {
    width: 62%;
    max-width: 150px;
  }

  .footer-logo-word {
    height: auto;
    width: 100%;
    top: 0;
  }

  .pricing-cards {
    grid-template-columns: 1fr;
    grid-template-rows: none;
    padding: 0;
  }

  .pricing-card {
    grid-row: auto;
    grid-template-rows: none;
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
  }

  .pricing-features {
    flex: 1;
  }

  .pricing-more {
    margin-top: var(--space-10);
  }

  .pricing-card:hover,
  .pricing-card:focus-within {
    transform: none;
  }

  /* iOS Safari does not honour background-attachment: fixed — it pins the
     image to the document and jumps on every scroll, so the shimmer the panel
     is built around simply stops on a phone. The texture therefore stops being
     a background here and becomes its own fixed layer, clipped by the panel:
     position: fixed is honoured everywhere, so the layer really does stand
     still while the panel travels over it, which is the same illusion the
     desktop gets from background-attachment.

     The layer is deliberately bigger than the screen on every side. A phone
     viewport is not a constant — it grows and shrinks as the address bar hides
     and returns — and an element sized exactly to it would show its edge every
     time that happens. Overhanging by a quarter of the viewport in each
     direction means the image covers past the screen at any address-bar state,
     so there is no edge to catch.

     The panel is cut back to shape with clip-path rather than with overflow:
     hidden. overflow does not clip a fixed descendant at all — only an
     ancestor that is a containing block for fixed positioning does, and making
     the panel one (a transform, a filter, will-change) is precisely what would
     re-anchor the layer to the panel and kill the effect. clip-path clips the
     subtree without establishing that containing block, so the layer stays
     viewport-anchored and still ends at the panel's rounded edge. The round
     value has to repeat --radius-xl because a clip path has no way to read the
     border radius it is imitating; change one and change the other.

     If a browser ever did treat clip-path as a containing block, the layer
     would fall back to being anchored to the panel and merely overhang it: the
     texture still covers, only the parallax is lost. */
  .rv-stats {
    grid-template-columns: 1fr;
    grid-template-rows: none;
    padding: clamp(28px, 5vw, 40px) clamp(24px, 5vw, 36px);
    position: relative;
    clip-path: inset(0 round var(--radius-xl));
    background-image: none;
  }

  /* position: fixed takes this out of the grid, so it never becomes a track. */
  .rv-stats::before {
    content: "";
    position: fixed;
    top: -25vh;
    right: -25vw;
    bottom: -25vh;
    left: -25vw;
    background-image: url("images/stat-texture-bg.webp");
    background-repeat: no-repeat;
    background-position: center center;
    background-size: cover;
    pointer-events: none;
    z-index: 0;
  }

  .rv-stat {
    grid-row: auto;
    grid-template-rows: none;
    display: flex;
    flex-direction: column;
    padding: clamp(24px, 4vw, 32px) 0;
    /* above the texture layer, which the panel would otherwise paint over */
    position: relative;
    z-index: 1;
  }

  /* stacked, so the same hairline runs the other way */
  .rv-stat + .rv-stat {
    border-left: 0;
    border-top: 1px solid rgb(255 255 255 / 0.2);
  }

  .rv-stat:first-child { padding-top: 0; }
  .rv-stat:last-child  { padding-bottom: 0; }

  .rv-figure {
    font-size: 46px;
  }
}

@media (max-width: 700px) {
  .stack-card-inner {
    grid-template-columns: 1fr;
    gap: 16px;
  }

  /* The clip gets whatever the copy leaves over, so a two-line heading used to
     hand its phone a shorter row than a one-line one and render it visibly
     smaller. script.js measures the tallest copy block in the stack and puts it
     in --copy-h, so every card reserves the same amount and all eight clips
     come out the same size. Without JS this falls back to auto, i.e. the old
     per-card behaviour. */
  .stack-card-inner {
    grid-template-rows: minmax(0, var(--copy-h, auto)) minmax(0, 1fr);
    align-items: start;
  }

  .stack-card-visual {
    grid-column: 1;
    grid-row: 2;
    justify-content: center;
    align-self: stretch;
    align-items: flex-end;
    min-height: 0;
  }

  .stack-card-copy {
    align-self: start;
  }

  /* the copy sits at the top, so the clip gets the whole row under it.
     1fr is definite here because the card has a fixed height. */
  .card-anim {
    width: 100%;
    height: 100%;
    max-width: none;
    object-fit: contain;
    object-position: bottom center;
  }
}

@media (max-width: 600px) {
  :root {
    --section-y: var(--space-14);
    --section-gap: var(--space-12);
  }

  .hero-ctas,
  .notfound-ctas {
    flex-direction: column;
    width: 100%;
  }

  .hero-ctas .btn,
  .notfound-ctas .btn {
    width: 100%;
  }

  .notfound-inner {
    gap: 32px;
  }

  .stack-card-inner {
    --card-h: clamp(320px, 104vw, 500px);
    height: var(--card-h);
    min-height: var(--card-h);
    max-height: var(--card-h);
    padding: 24px 24px 0;
    border-radius: var(--radius-xl);
    gap: 16px;
  }

  .stack-card {
    padding-top: 96px;
    height: max(var(--card-scroll), 440px);
  }

  .stack-card-copy h3 {
    font-size: 23px;
    margin-bottom: 12px;
  }

  .stack-card-copy p {
    font-size: 14px;
    line-height: 1.45;
    letter-spacing: -0.02em;
    margin-bottom: 0;
  }

  .faq-item summary {
    font-size: 17px;
  }

  .footer-inner {
    row-gap: 32px;
  }

  .lf-row {
    grid-template-columns: 1fr;
  }

  .lf-submit {
    width: auto;
    flex: 1 1 180px;
    align-self: stretch;
  }

  .cta-band h2 {
    font-size: 32px;
  }

  .cta-btn {
    width: 100%;
    white-space: normal;
    text-align: center;
  }

  .rv-figure {
    font-size: 40px;
  }

  .rv-stat-label {
    font-size: 14px;
  }
}

/* =============================================
   REDUCED MOTION
============================================= */
/* -------- THE NARROW END OF THE RANGE -------- */
@media (max-width: 360px) {
  .stack-card-inner {
    padding: 20px 16px 0;
    gap: 8px;
  }

  .stack-card-copy h3 {
    font-size: 20px;
    margin-bottom: 8px;
  }

  .stack-card-copy p {
    font-size: 13px;
  }
}

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

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }

  .hiw-block .hiw-bubble,
  .hiw-block .hiw-frame {
    opacity: 1;
    transform: none;
  }

  .btn-grow:hover,
  .btn-grow:active,
  .pricing-card:hover,
  .pricing-card:focus-within,
  .hiw-frame img,
  .hiw-frame:hover img,
  .hiw-frame-button:hover img {
    transform: none;
  }

  /* The statistics texture only reads as parallax because it refuses to move
     with the page, which is motion the reader did not ask for. Pinning it back
     to the panel keeps the texture and drops the effect — on desktop by
     handing the background back to the element, and on narrow screens by
     dropping the fixed layer to absolute, where it travels with the panel. */
  .rv-stats {
    background-attachment: scroll;
  }

  .rv-stats::before {
    position: absolute;
    inset: 0;
  }
}

.footer-address {
  font-style: normal;
  margin: 0;
}

/* =============================================
   LEARN PAGE  (what-is-live-shopping.html)
============================================= */
.lp-blocks {
  display: flex;
  flex-direction: column;
  gap: var(--space-12);
  max-width: 650px;
  margin: 0 auto;
}

.lp-block h2 {
  font-family: var(--font-heading);
  font-size: 30px;
  font-weight: 800;
  line-height: 1.2;
  letter-spacing: -0.01em;
  color: var(--color-text-primary);
  margin: 0 0 14px;
}

.lp-block p {
  font-size: 15px;
  line-height: 1.65;
  color: var(--color-text-secondary);
  margin: 0 0 14px;
}

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

.lp-block a {
  color: var(--color-primary);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.lp-block a:hover {
  color: var(--color-primary-dark);
}

.lp-block p.lp-answer {
  color: var(--color-text-primary);
  font-weight: 500;
  background: var(--color-primary-softer);
  border-left: 3px solid var(--color-primary);
  border-radius: 0 var(--radius) var(--radius) 0;
  padding: 14px 18px;
  margin-bottom: 18px;
}

.lp-steps {
  list-style: none;
  counter-reset: lp-step;
  margin: 18px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.lp-steps li {
  counter-increment: lp-step;
  display: grid;
  grid-template-columns: 34px minmax(0, 1fr);
  gap: 14px;
  align-items: start;
}

.lp-steps li::before {
  content: counter(lp-step);
  width: 34px;
  height: 34px;
  border-radius: var(--radius-pill);
  background: var(--color-primary-soft);
  color: var(--color-primary);
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: 14px;
  display: grid;
  place-items: center;
}

.lp-steps h3 {
  font-family: var(--font-heading);
  font-size: 16px;
  font-weight: 700;
  color: var(--color-text-primary);
  margin: 6px 0 4px;
}

.lp-steps p {
  margin: 0;
}

.lp-block .svc-points {
  margin-top: 20px;
}

@media (max-width: 700px) {
  .lp-blocks {
    gap: var(--space-10);
  }

  .lp-block h2 {
    font-size: 24px;
  }

  .lp-block p.lp-answer {
    padding: 12px 14px;
  }
}

/* =============================================
   HERO NOTE + VIDEO REEL
============================================= */
.hero-note {
  margin: 18px auto 0;
  max-width: 680px;
  font-size: 12px;
  line-height: 1.5;
  color: currentColor;
  opacity: 0.55;
}

/* =============================================
   BLOG (blog/index.html) + POST PAGES (blog/<slug>.html)
============================================= */

/* -------- Featured / newest post -------- */
/* The page head is svc-head, shared with /services and /pricing, so this is a
   body section like any other: plain --section-y, no header clearance. */
.blog-featured {
  padding: var(--section-y) 0;
}

/* Same 1fr 1fr split and the same gap as .blog-split below it, so the seam
   between the two columns runs straight down the page through both blocks. */
.blog-feature-card {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-12);
  align-items: center;
}

.blog-featured-media {
  display: block;
  aspect-ratio: 16 / 9;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  background-image: linear-gradient(135deg, var(--pastel-1), var(--pastel-2));
}

.blog-featured-media img,
.blog-preview-media img,
.blog-item-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: left top;
  display: block;
}

/* The divider itself (1px), its inset (--space-12 on .blog-list) and the row
   card's own padding (--space-4), so this copy starts on exactly the same
   left edge as the post thumbnails in the list below it. */
.blog-feature-copy {
  min-width: 0;
  padding-left: calc(1px + var(--space-12) + var(--space-4));
}

.blog-feature-title {
  font-family: var(--font-heading);
  font-size: clamp(26px, 3.2vw, 38px);
  font-weight: 800;
  line-height: 1.18;
  letter-spacing: -0.01em;
  margin: 0 0 12px;
}

.blog-feature-title a {
  color: var(--color-text-primary);
  text-decoration: none;
  transition: color var(--transition);
}

.blog-feature-title a:hover {
  color: var(--color-primary);
}

.blog-feature-excerpt {
  font-size: 15px;
  line-height: 1.65;
  color: var(--color-text-secondary);
  margin: 0 0 var(--space-6);
}

/* Shared meta line: date, separator, category. */
.blog-meta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  font-size: 13px;
  color: var(--color-text-muted);
  margin: 0 0 16px;
}

.blog-meta-sep {
  opacity: 0.55;
}

/* -------- The split: preview on the left, list on the right -------- */
/* Same --section-y as svc-features and every other body section. Without it
   this section is the one block on the site with no vertical padding. */
.blog-browse {
  padding: var(--section-y) 0;
}

/* -------- The phone pager -------- */
/* Two arrows either side of "All posts". They belong to the phone layout only:
   above 900px the dial already contains the list, so paging it as well would
   be two answers to one problem. Hidden here rather than only in the media
   query, so the markup's [hidden] is not the only thing keeping them off a
   desktop page. */
.blog-page-arrow {
  display: none;
}

.blog-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-12);
  align-items: start;
}

.blog-preview-col {
  min-width: 0;
}

/* The divider down the middle. It lives on the list's leading edge rather
   than a pseudo-element so that it disappears with the grid at 900px. */
.blog-list {
  list-style: none;
  margin: 0;
  padding: 0 0 0 var(--space-12);
  border-left: 1px solid var(--color-primary);
  min-width: 0;
}

/* The thin purple rule between posts. Top border only, so the first row has
   no line above it and the last none below. */
.blog-row + .blog-row {
  border-top: 1px solid var(--color-primary);
}

/* -------- The dial: what the list becomes past four posts -------- */
/* Past four rows the list would run far deeper than the preview panel beside
   it and stretch the page for no good reason. script.js adds .is-dial and pins
   the height to the first four rows, and the list scrolls inside itself.
   The lock comes free with native overflow: the wheel turns the dial while the
   pointer is over it, and hands scrolling back to the page at either end, or
   immediately if the pointer is off to the side of the list. */
.blog-list.is-dial {
  overflow-y: auto;
  overscroll-behavior-y: auto;
  perspective: 900px;
  perspective-origin: 50% 50%;
  scrollbar-width: none;
  -webkit-mask-image: linear-gradient(
    to bottom, transparent 0, #000 13%, #000 87%, transparent 100%);
  mask-image: linear-gradient(
    to bottom, transparent 0, #000 13%, #000 87%, transparent 100%);
}

.blog-list.is-dial::-webkit-scrollbar {
  width: 0;
  height: 0;
}

/* The per-row rotation is written inline by script.js, which is the only thing
   that knows where a row sits relative to the dial's centre. */
.blog-list.is-dial .blog-row {
  transform-origin: 50% 50%;
  backface-visibility: hidden;
}

@media (prefers-reduced-motion: reduce) {
  /* Still a contained, scrollable list -- just a flat one. */
  .blog-list.is-dial {
    perspective: none;
  }

  .blog-list.is-dial .blog-row {
    transform: none !important;
    opacity: 1 !important;
  }
}

.blog-list-card {
  position: relative;
  display: grid;
  grid-template-columns: 92px 1fr;
  gap: var(--space-5);
  align-items: start;
  width: 100%;
  padding: var(--space-6) var(--space-4);
  border-radius: var(--radius);
}

.blog-list-item {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  border: 0;
  border-left: 3px solid transparent;
  border-radius: inherit;
  background: none;
  font: inherit;
  color: inherit;
  cursor: pointer;
  transition: background-color var(--transition), border-color var(--transition);
}

.blog-list-item:hover {
  background: var(--color-primary-softer);
}

.blog-list-item[aria-current="true"] {
  background: var(--color-primary-soft);
  border-left-color: var(--color-primary);
}

.blog-list-item:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

.blog-item-thumb {
  position: relative;
  z-index: 1;
  pointer-events: none;
  display: block;
  aspect-ratio: 1 / 1;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  overflow: hidden;
  background-image: linear-gradient(135deg, var(--pastel-1), var(--pastel-2));
}

.blog-item-copy {
  position: relative;
  z-index: 1;
  pointer-events: none;
  display: block;
  min-width: 0;
}

/* The category is a word on the meta line beside the date, not a pill above
   the title. One accent per row is enough, and the bubbles were competing
   with the eyebrow treatment used elsewhere on the site. */
.blog-item-cat,
.blog-preview-cat {
  color: var(--color-primary);
  font-weight: 500;
}

.blog-list-link {
  position: relative;
  z-index: 2;
  pointer-events: auto;
  display: block;
  font-family: var(--font-heading);
  font-size: 16px;
  font-weight: 800;
  line-height: 1.3;
  color: var(--color-text-primary);
  text-decoration: none;
  margin-bottom: 6px;
  transition: color var(--transition);
}

.blog-list-link:hover {
  color: var(--color-primary);
}

.blog-list-link:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

.blog-list-card .blog-meta {
  margin: 0 0 6px;
}

/* One string, two jobs: clamped to a teaser here, shown in full in the
   preview panel. Keeping it single means one translation to maintain. */
.blog-item-excerpt {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  font-size: 13px;
  line-height: 1.55;
  color: var(--color-text-secondary);
}

/* -------- Preview panel -------- */
.blog-preview {
  position: sticky;
  top: calc(var(--header-bottom) + var(--space-6));
  background: var(--color-white);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: 0 14px 30px rgba(28, 32, 36, 0.06);
}

.blog-preview-media {
  aspect-ratio: 16 / 10;
  overflow: hidden;
  background-image: linear-gradient(135deg, var(--pastel-1), var(--pastel-2));
}

.blog-preview-copy {
  padding: var(--space-6);
}

.blog-preview-title {
  font-family: var(--font-heading);
  font-size: 22px;
  font-weight: 800;
  line-height: 1.22;
  letter-spacing: -0.01em;
  margin: 0 0 10px;
}

/* The excerpt is deliberately cut short and faded out: the panel is an
   invitation to open the post, not a substitute for it. */
.blog-preview-body {
  position: relative;
  max-height: 132px;
  overflow: hidden;
}

.blog-preview-body p {
  font-size: 14px;
  line-height: 1.65;
  color: var(--color-text-secondary);
  margin: 0;
}

.blog-preview-body::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 68px;
  background: linear-gradient(to bottom, rgba(255, 255, 255, 0), var(--color-white) 70%);
  pointer-events: none;
}

.blog-preview-more {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  margin-top: var(--space-4);
}

.blog-preview-invite {
  margin: 0;
  font-size: 13px;
  color: var(--color-text-muted);
}

.blog-arrow-btn {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border: 1.5px solid var(--color-primary);
  border-radius: var(--radius-pill);
  background: var(--color-white);
  color: var(--color-primary);
  transition: background-color var(--transition), color var(--transition);
}

.blog-arrow-btn:hover {
  background: var(--color-primary);
  color: var(--color-white);
}

/* Two arrows, one slot. On hover the purple one leaves to the right and the
   white one arrives from the left, so the button reads as a single arrow
   travelling through rather than a colour swap. overflow:hidden is what makes
   them disappear at the rim instead of outside it. */
.blog-arrow-btn {
  position: relative;
  overflow: hidden;
}

.blog-arrow-btn .arrow-swap {
  position: absolute;
  inset: 0;
}

.blog-arrow-btn .arrow-ico {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 15px;
  height: 18px;
  margin: -9px 0 0 -7.5px;
  transition: transform 0.34s var(--ease-out-soft);
}

.blog-arrow-btn .arrow-out {
  color: var(--color-primary);
  transform: translateX(0);
}

/* 260% of 15px clears the 36px button, so neither arrow is caught mid-rim. */
.blog-arrow-btn .arrow-in {
  color: var(--color-white);
  transform: translateX(-260%);
}

.blog-arrow-btn:hover .arrow-out,
.blog-arrow-btn:focus-visible .arrow-out {
  transform: translateX(260%);
}

.blog-arrow-btn:hover .arrow-in,
.blog-arrow-btn:focus-visible .arrow-in {
  transform: translateX(0);
}

/* The per-row panel is the mobile form of the preview; it has no job on
   desktop, where the sticky panel to the left is doing the work. */
.blog-item-panel {
  display: none;
}

/* -------- Post template -------- */
.post-article {
  padding: calc(var(--header-bottom) + var(--space-16)) 0 var(--section-y);
}

.post-head {
  text-align: center;
  margin-bottom: var(--space-14);
}

/* Block-level, so it takes its own line above the category pill -- as
   inline-flex the two shared a line and this margin-bottom did nothing.
   fit-content plus auto side margins keeps the hit area on the words. */
.post-back {
  display: flex;
  width: fit-content;
  align-items: center;
  gap: 8px;
  margin: 0 auto var(--space-8);
}

.post-back-arrow {
  width: 15px;
  height: 18px;
}

.post-back:hover .post-back-arrow {
  transform: translateX(-3px);
}

.post-head h1 {
  font-family: var(--font-heading);
  font-size: clamp(30px, 4.2vw, 48px);
  font-weight: 800;
  line-height: 1.14;
  letter-spacing: -0.02em;
  max-width: 20ch;
  margin: 0 auto 14px;
}

.post-meta {
  justify-content: center;
  margin: 0;
}

.post-hero {
  max-width: 650px;
  margin: 0 auto var(--space-16);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  background-image: linear-gradient(135deg, var(--pastel-1), var(--pastel-2));
}

.post-hero img {
  width: 100%;
  height: auto;
  display: block;
}

/* -------- Source note and related posts, at the foot of an article -------- */
/* Both sit inside .lp-blocks, so they inherit the 650px prose measure. */
.post-source {
  border-top: 1px solid var(--color-border);
  padding-top: var(--space-6);
}

.post-source p {
  font-size: 13px;
  color: var(--color-text-muted);
}

.post-source h2,
.post-related h2 {
  font-size: 20px;
}

.post-related-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
}

.post-related-list li + li {
  border-top: 1px solid var(--color-border);
}

/* The whole row is the target, not just the headline. With a thumbnail beside
   the title the row is tall enough that a text-width hit area would leave most
   of it dead, which reads as broken on touch. The negative margin lets the
   hover tint bleed past the prose measure so the padding is not a visible
   inset on either side. */
/* Qualified by the list so it outweighs `.lp-block a`, which underlines every
   link in the prose. text-decoration propagates to inline descendants and a
   child cannot switch it back off, so it has to be beaten on the anchor. */
.post-related-list .post-related-link {
  text-decoration: none;
}

.post-related-link {
  display: grid;
  grid-template-columns: 72px minmax(0, 1fr) auto;
  align-items: center;
  column-gap: var(--space-4);
  row-gap: var(--space-1);
  padding: var(--space-4) var(--space-3);
  margin: 0 calc(var(--space-3) * -1);
  border-radius: var(--radius);
  transition: background-color var(--transition);
}

.post-related-link:hover {
  background: var(--color-primary-softer);
}

.post-related-link:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

.post-related-thumb {
  display: block;
  aspect-ratio: 1 / 1;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  overflow: hidden;
  background-image: linear-gradient(135deg, var(--pastel-1), var(--pastel-2));
}

.post-related-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.post-related-title {
  font-family: var(--font-heading);
  font-size: 15px;
  font-weight: 800;
  line-height: 1.35;
  color: var(--color-text-primary);
  transition: color var(--transition);
}

.post-related-link:hover .post-related-title {
  color: var(--color-primary);
}

.post-related-cat {
  flex: none;
  font-size: 12px;
  font-weight: 500;
  color: var(--color-primary);
}

@media (max-width: 560px) {
  /* The category label sits under the title rather than squeezing it, in the
     column the title already occupies so it stays clear of the thumbnail. */
  .post-related-link {
    grid-template-columns: 64px minmax(0, 1fr);
  }

  /* Both rows, so the thumbnail stays centred against the whole stack rather
     than against the title line alone. */
  .post-related-thumb {
    grid-row: 1 / span 2;
  }

  .post-related-cat {
    grid-column: 2;
  }
}

/* -------- Responsive: the split collapses at the nav breakpoint -------- */
@media (max-width: 900px) {
  /* The heading becomes a three-slot row: arrow, title, arrow. The title keeps
     the centred alignment it has everywhere else, so with both arrows the same
     width it still reads as centred on the column. */
  .blog-posts-heading {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    /* Turning a page scrolls back to here, and the header is fixed over it. */
    scroll-margin-top: calc(var(--header-bottom) + 16px);
  }

  .blog-posts-heading h2 {
    flex: 1 1 auto;
    min-width: 0;
    margin-bottom: 0;
  }

  .blog-page-arrow {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border: 1.5px solid var(--color-primary);
    border-radius: var(--radius-pill);
    background: var(--color-white);
    color: var(--color-primary);
    transition: background-color var(--transition), color var(--transition),
                opacity var(--transition);
  }

  /* script.js keeps the pair [hidden] while the list fits on one page, and the
     class rule above is specific enough to beat the UA's [hidden] on its own. */
  .blog-page-arrow[hidden] {
    display: none;
  }

  .blog-page-arrow .arrow-ico {
    width: 16px;
    height: 19px;
  }

  /* Faded, not removed: the pair has to stay in place or the heading shifts
     sideways every time the reader reaches an end. */
  .blog-page-arrow:disabled {
    opacity: 0.3;
  }

  .blog-page-arrow:not(:disabled):hover,
  .blog-page-arrow:not(:disabled):active {
    background: var(--color-primary);
    color: var(--color-white);
  }

  .blog-page-arrow:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
  }

  /* A row off the current page. Nothing else gives .blog-row a display value,
     so this is belt and braces against a future rule that does. */
  .blog-row[hidden] {
    display: none;
  }

  /* The divider between rows is drawn by an adjacent-sibling rule, and that
     still matches across a hidden row -- which would put a line above the
     first row of every page after the first. */
  .blog-row[hidden] + .blog-row {
    border-top: 0;
  }

  .blog-feature-card {
    grid-template-columns: 1fr;
    gap: var(--space-8);
  }

  /* No divider to align to once the grid is one column. */
  .blog-feature-copy {
    padding-left: 0;
  }

  .blog-split {
    grid-template-columns: 1fr;
    gap: var(--space-8);
  }

  /* Below this width the preview moves inside the row that was tapped. */
  .blog-preview-col {
    display: none;
  }

  .blog-list {
    border-left: 0;
    padding-left: 0;
  }

  /* No dial on a phone: the rows expand in place here, and a nested scroller
     inside the page scroll is a fight the page always loses on touch. */
  .blog-list.is-dial {
    max-height: none;
    overflow: visible;
    perspective: none;
    -webkit-mask-image: none;
    mask-image: none;
  }

  .blog-list.is-dial .blog-row {
    transform: none;
    opacity: 1;
  }

  /* Slow and even on purpose. This panel is ~600px tall on a phone, so every
     millisecond of its travel moves the rest of the list; script.js reads this
     duration back off the element rather than repeating the number. */
  .blog-item-panel:not([hidden]) {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows 0.52s var(--ease-in-out-soft);
  }

  .blog-item-panel.is-open {
    grid-template-rows: 1fr;
  }

  .blog-item-panel-inner {
    min-height: 0;
    overflow: hidden;
  }

  .blog-item-panel-inner > .blog-preview {
    position: static;
    margin: 0 var(--space-4) var(--space-6);
    box-shadow: none;
  }
}

@media (max-width: 560px) {
  .blog-list-card {
    grid-template-columns: 68px 1fr;
    gap: var(--space-4);
    padding: var(--space-5) var(--space-2);
  }

  .blog-list-link {
    font-size: 15px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .blog-item-panel:not([hidden]) {
    transition: none;
  }
}

/* =============================================
   SELF-HOSTED WEBFONTS
============================================= */
@font-face {
  font-family: 'DM Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('fonts/dm-mono-400-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'DM Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('fonts/dm-mono-400-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'DM Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('fonts/dm-mono-500-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'DM Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('fonts/dm-mono-500-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Montserrat';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('fonts/montserrat-var-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
