/*
  Cartesian Property Group website
  Copyright (c) 2026 Cartesian Property Group Pty Ltd. All rights reserved.
  Design and code by Hugo Manning (learnaiwithhugo.com) for Cartesian Property Group.
  Not to be copied, reproduced or reused for any other business or website
  without written permission.
*/
/* ============================================================
   Cartesian Property Group: one-page site
   Palette (locked, 20 Aug feedback): Formal Green + cool grey +
   white. Nothing else. Type: Instrument Sans only.
   Rhythm: every section shares --section-y; every section head
   shares the same gap; one h2 size, one h3 size, one eyebrow.
   Motion: Lenis smooth scroll, fade-rise reveals, clip image
   reveals, scroll-spy nav, journey line draw. All motion
   collapses under prefers-reduced-motion.
   ============================================================ */

/* ---------- Fonts ---------- */
@font-face {
  font-family: "Instrument Sans";
  src: url("../fonts/InstrumentSans-Variable.woff2") format("woff2");
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Instrument Sans";
  src: url("../fonts/InstrumentSans-Italic-Variable.woff2") format("woff2");
  font-weight: 400 700;
  font-style: italic;
  font-display: swap;
}

/* ---------- Tokens ---------- */
:root {
  /* the whole palette: two greens, one grey, white */
  --green-deep: #0b241c;  /* footer, hero overlay base */
  --green: #0f3228;       /* primary dark band */
  --green-panel: #164534; /* raised panel on green */

  --grey: #eceeec;        /* cool grey band */
  --white: #ffffff;       /* panels on grey / white band */

  /* text on light */
  --ink: #10221b;
  --text: #3f4d47;
  /* text on dark */
  --light: #f3f2ef;
  --light-soft: rgba(240, 243, 240, 0.78);

  /* hairlines */
  --line-on-light: rgba(16, 34, 27, 0.14);
  --line-on-dark: rgba(240, 243, 240, 0.18);

  --font: "Instrument Sans", "Helvetica Neue", Arial, sans-serif;
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --container: 1240px;

  /* one vertical rhythm for every section */
  --section-y: clamp(4.5rem, 9vw, 7.5rem);
  --head-gap: clamp(2.75rem, 5vw, 4rem);   /* section head -> content */
  --grid-gap: clamp(1.25rem, 2.5vw, 2rem); /* every card grid */
  --card-pad: 2rem;                        /* every card */
}

/* ---------- Reset ---------- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html { scroll-behavior: smooth; }
html.lenis { height: auto; scroll-behavior: auto; }
.lenis.lenis-smooth { scroll-behavior: auto; }

html, body { overflow-x: clip; }

body {
  font-family: var(--font);
  font-size: 1.0625rem;
  line-height: 1.65;
  color: var(--text);
  background: var(--grey);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
ul { list-style: none; }

::selection { background: var(--green); color: var(--light); }

/* ---------- Type scale (one size per level, everywhere) ---------- */
h1, h2, h3, h4 {
  font-weight: 600;
  line-height: 1.12;
  letter-spacing: -0.02em;
  color: var(--ink);
  text-wrap: balance;
}
.display {
  font-size: clamp(2.6rem, 5.4vw, 4.4rem);
  font-weight: 600;
}
h2, .h2 { font-size: clamp(2rem, 3.4vw, 2.8rem); }
h3, .h3 { font-size: 1.25rem; line-height: 1.3; }

.lead {
  font-size: clamp(1.1rem, 1.5vw, 1.25rem);
  line-height: 1.55;
  color: var(--text);
  max-width: 36em;
}
p { max-width: 62ch; }

.eyebrow {
  display: block;
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  margin-bottom: 1.1rem;
  color: var(--green);
}

/* ---------- Section shells ---------- */
.container { width: min(var(--container), 100% - 3rem); margin-inline: auto; }

section { padding-block: var(--section-y); }

.section-head { max-width: 720px; margin-bottom: var(--head-gap); }
.section-head p { margin-top: 1.1rem; }

/* band variants: the entire page is built from these three */
.band-grey  { background: var(--grey);  color: var(--text); }
.band-white { background: var(--white); color: var(--text); }
.band-green { background: var(--green); color: var(--light-soft); }

.band-green h1, .band-green h2, .band-green h3, .band-green h4 { color: var(--light); }
.band-green p, .band-green .lead { color: var(--light-soft); }
.band-green .eyebrow { color: var(--light-soft); }

/* panels sit one step lighter/darker than their band */
.band-grey .panel  { background: var(--white); }
.band-white .panel { background: var(--grey); }
.band-green .panel { background: var(--green-panel); }

/* ---------- Header ---------- */
.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 50;
  color: var(--light);
  transition: background 0.4s var(--ease), box-shadow 0.4s var(--ease);
}
.site-header .container {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  height: 80px;
  gap: 1.5rem;
}
.site-header .logo { justify-self: start; }
.site-header .nav { justify-self: center; }
.site-header .header-cta { justify-self: end; }
.site-header.is-solid {
  background: rgba(11, 36, 28, 0.97);
  box-shadow: 0 1px 0 rgba(240, 243, 240, 0.08);
}
.logo img { height: 36px; width: auto; display: block; }

.nav {
  display: flex;
  align-items: center;
  gap: 1.9rem;
  font-weight: 500;
  font-size: 0.95rem;
}
.nav a {
  position: relative;
  padding-block: 0.3rem;
  transition: opacity 0.3s var(--ease);
}
.nav a::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  height: 1.5px;
  width: 100%;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 0.35s var(--ease);
}
.nav a:hover::after,
.nav a.is-active::after {
  transform: scaleX(1);
  transform-origin: left;
}

/* boxed label + arrow button (header) */
.header-cta {
  display: inline-flex;
  align-items: stretch;
  border: 1.5px solid rgba(240, 243, 240, 0.85);
  color: var(--light);
  font-weight: 500;
  font-size: 0.95rem;
  line-height: 1;
  white-space: nowrap;
  transition: background 0.3s var(--ease), color 0.3s var(--ease),
    border-color 0.3s var(--ease);
}
.header-cta .label { display: inline-flex; align-items: center; padding: 0.85rem 1.3rem; }
.header-cta .arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.85rem 0.95rem;
  border-left: 1.5px solid rgba(240, 243, 240, 0.45);
}
.header-cta .arrow svg { width: 15px; height: 15px; transition: transform 0.3s var(--ease); }
.header-cta:hover { background: var(--light); border-color: var(--light); color: var(--green); }
.header-cta:hover .arrow svg { transform: translateX(3px); }

/* mobile nav */
.nav-toggle {
  display: none;
  background: none;
  border: 0;
  cursor: pointer;
  width: 44px;
  height: 44px;
  position: relative;
  color: inherit;
}
.nav-toggle span {
  position: absolute;
  left: 10px;
  right: 10px;
  height: 2px;
  background: currentColor;
  transition: transform 0.3s var(--ease), opacity 0.3s var(--ease);
}
.nav-toggle span:nth-child(1) { top: 16px; }
.nav-toggle span:nth-child(2) { top: 22px; }
.nav-toggle span:nth-child(3) { top: 28px; }

@media (max-width: 980px) {
  .site-header .container { display: flex; justify-content: space-between; }
  .nav-toggle { display: block; }
  .site-header .header-cta { display: none; }
  /* the desktop rule .site-header .nav { justify-self: center } also applies to
     an out-of-flow box in Chrome/Safari, which shrink-wrapped this overlay into
     a narrow strip floating mid-screen. Reset it so inset:0 actually fills. */
  .site-header .nav { justify-self: stretch; align-self: stretch; }
  .nav {
    position: fixed;
    inset: 0;
    width: 100%;
    height: 100%;
    background: var(--green);
    color: var(--light);
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1.6rem;
    font-size: 1.4rem;
    padding: 6rem 1.5rem 3rem;
    opacity: 0;
    visibility: hidden;
    transform: translateY(-8px);
    pointer-events: none;
    overscroll-behavior: contain;
    transition: opacity 0.32s var(--ease), transform 0.32s var(--ease),
      visibility 0s linear 0.32s;
  }
  .nav a { font-size: inherit; }
  body.nav-open .nav {
    opacity: 1;
    visibility: visible;
    transform: none;
    pointer-events: auto;
    transition: opacity 0.32s var(--ease), transform 0.32s var(--ease),
      visibility 0s linear 0s;
  }
  body.nav-open { overflow: hidden; }
  body.nav-open .logo { z-index: 60; position: relative; }
  body.nav-open .nav-toggle { color: var(--light); z-index: 60; position: relative; }
  body.nav-open .nav-toggle span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
  body.nav-open .nav-toggle span:nth-child(2) { opacity: 0; }
  body.nav-open .nav-toggle span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }
}

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.95rem 1.9rem;
  font-weight: 500;
  font-size: 0.98rem;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  border: 1.5px solid transparent;
  transition: background 0.3s var(--ease), color 0.3s var(--ease),
    border-color 0.3s var(--ease), transform 0.3s var(--ease);
}
.btn:active { transform: translateY(1px) scale(0.99); }

.btn-primary { background: var(--green); color: var(--light); }
.btn-primary:hover { background: var(--green-deep); }
.band-green .btn-primary { background: var(--light); color: var(--green); }
.band-green .btn-primary:hover { background: var(--white); }

.btn-ghost { border-color: rgba(16, 34, 27, 0.35); color: var(--ink); }
.btn-ghost:hover { border-color: var(--green); background: rgba(16, 34, 27, 0.05); }
.band-green .btn-ghost { border-color: rgba(240, 243, 240, 0.4); color: var(--light); }
.band-green .btn-ghost:hover { border-color: var(--light); background: rgba(240, 243, 240, 0.08); }

.text-link {
  font-weight: 500;
  border-bottom: 1.5px solid var(--green);
  padding-bottom: 2px;
  transition: border-color 0.3s var(--ease);
  color: var(--ink);
}
.text-link:hover { border-color: var(--ink); }
.band-green .text-link { color: var(--light); border-bottom-color: rgba(240, 243, 240, 0.5); }
.band-green .text-link:hover { border-bottom-color: var(--light); }

/* ---------- Hero ---------- */
.hero {
  position: relative;
  min-height: 100dvh;
  display: flex;
  align-items: flex-end;
  color: var(--light);
  overflow: hidden;
  padding-block: 0;
}
.hero-media { position: absolute; inset: 0; z-index: -2; overflow: hidden; }
.hero-media video {
  width: 100%;
  height: 112%;
  object-fit: cover;
  display: block;
  will-change: transform;
  filter: saturate(0.55) contrast(1.02) brightness(0.92);
}
.hero-media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(15, 50, 40, 0.42);
  pointer-events: none;
}
.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(
    to top,
    rgba(11, 36, 28, 0.94) 0%,
    rgba(11, 36, 28, 0.55) 45%,
    rgba(11, 36, 28, 0.3) 100%
  );
}
.hero-inner { padding-block: clamp(5rem, 10vh, 7.5rem); }
.hero h1 { color: var(--light); max-width: 21ch; }
.hero .lead { color: var(--light-soft); margin-top: 1.4rem; }
.hero-actions { display: flex; flex-wrap: wrap; gap: 0.9rem; margin-top: 2.2rem; }
.hero .btn-ghost {
  border-color: rgba(240, 243, 240, 0.85);
  color: var(--light);
  background: rgba(15, 50, 40, 0.25);
}
.hero .btn-ghost:hover { border-color: var(--white); background: rgba(240, 243, 240, 0.16); }

/* hero headline text effects. Two saved variants, picked by a class
   on the h1: .fx-slide (chars slide in from the right, staggered)
   or .fx-blur (words focus in from heavy blur, one at a time). */
.hero h1 .line { display: block; }
.hero h1 .word { display: inline-block; white-space: nowrap; }
@media (prefers-reduced-motion: no-preference) {
  .hero h1.fx-slide .ch {
    display: inline-block;
    transform: translateX(0.65em);
    opacity: 0;
    filter: blur(6px);
    transition: transform 0.7s var(--ease), opacity 0.55s ease-out,
      filter 0.7s var(--ease);
    transition-delay: var(--chd, 0ms);
  }
  .hero.is-loaded h1.fx-slide .ch {
    transform: none;
    opacity: 1;
    filter: none;
  }
  .hero h1.fx-blur .word {
    opacity: 0;
    filter: blur(16px);
    transform: translateY(0.28em);
    transition: opacity 0.7s ease-out, filter 0.9s var(--ease),
      transform 0.9s var(--ease);
    transition-delay: var(--wd, 0ms);
  }
  .hero.is-loaded h1.fx-blur .word {
    opacity: 1;
    filter: none;
    transform: none;
  }
}

/* ---------- Blur-in words (reusable) ----------
   The same word-focus effect saved on the hero, but triggered by
   scrolling into view instead of page load. JS splits the text
   into .word spans and adds .is-in. Used on the client quote. */
.fx-blur-in .word { display: inline-block; white-space: nowrap; }
@media (prefers-reduced-motion: no-preference) {
  .fx-blur-in .word {
    opacity: 0;
    filter: blur(14px);
    transform: translateY(0.24em);
    transition: opacity 0.7s ease-out, filter 0.9s var(--ease),
      transform 0.9s var(--ease);
    transition-delay: var(--wd, 0ms);
  }
  .fx-blur-in.is-in .word {
    opacity: 1;
    filter: none;
    transform: none;
  }
  /* testimonial quotes: same effect, roughly twice the pace */
  .quote-slide .fx-blur-in .word { transition-duration: 0.4s, 0.5s, 0.5s; }
  /* whole-passage variant: the block focuses in as one */
  .fx-blur-in[data-blur-block] {
    opacity: 0;
    filter: blur(14px);
    transform: translateY(0.24em);
    transition: opacity 0.6s ease-out, filter 0.8s var(--ease), transform 0.8s var(--ease);
  }
  .fx-blur-in[data-blur-block].is-in { opacity: 1; filter: none; transform: none; }
}

/* ---------- Split (copy + media) ---------- */
.split {
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
  gap: clamp(2.5rem, 5vw, 5rem);
  align-items: center;
}
.split.flip > .split-media { order: -1; }
@media (max-width: 900px) {
  .split, .split.flip { grid-template-columns: 1fr; }
  .split.flip > .split-media { order: 0; }
}
.split-copy h2 { margin-bottom: 1.1rem; }
.split-copy p + p { margin-top: 0.9rem; }
.split-copy .btn, .split-copy .text-link { margin-top: 1.7rem; display: inline-flex; }

.split-media { overflow: hidden; position: relative; }
.split-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  aspect-ratio: 4 / 3.2;
}

/* checklist */
.checks {
  margin-top: 1.4rem;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.55rem 1.6rem;
  font-size: 0.95rem;
}
@media (max-width: 560px) { .checks { grid-template-columns: 1fr; } }
.checks li { position: relative; padding-left: 1.7rem; }
.checks li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.42em;
  width: 0.85em;
  height: 0.45em;
  border-left: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(-45deg);
  opacity: 0.75;
}

/* ---------- Sub-heads ----------
   Labels a block inside a section (the two core drivers, the five research
   criteria) without competing with the section's own h2. Deliberately the
   same size, weight and tracking as .eyebrow: these are the same kind of
   thing, just further down the page. */
.sub-head {
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--green);
  margin-bottom: 1.4rem;
}
.band-green .sub-head { color: var(--light-soft); }

/* ---------- Card grids ---------- */
.grid-2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--grid-gap); }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--grid-gap); }
@media (max-width: 900px) { .grid-2, .grid-3 { grid-template-columns: 1fr; } }

.card {
  background: var(--white);
  border: 1px solid var(--line-on-light);
  padding: var(--card-pad);
  display: flex;
  flex-direction: column;
  transition: transform 0.3s var(--ease), box-shadow 0.3s var(--ease);
}
.card:hover {
  transform: translateY(-4px);
  box-shadow: 0 18px 40px -18px rgba(15, 50, 40, 0.25);
}
.card h3 { margin-bottom: 0.7rem; }
.card p { font-size: 0.99rem; }

/* image-topped card: one image size everywhere it appears */
.card.has-img { padding: 0; }
.card.has-img .card-img { overflow: hidden; }
.card.has-img img {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  transform: scale(1.001);
  transition: transform 0.7s var(--ease);
}
.card.has-img:hover img { transform: scale(1.045); }
.card.has-img .card-body {
  padding: 1.6rem var(--card-pad) var(--card-pad);
  display: flex;
  flex-direction: column;
  flex: 1;
}
.card.has-img .card-body p { flex: 1; }

.card .crit-num,
.pillar .crit-num {
  font-size: 0.85rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--green);
  margin-bottom: 0.6rem;
}

/* ---------- Why rows (numbered editorial list) ---------- */
.num-list { border-top: 1px solid var(--line-on-light); }
.num-row {
  display: grid;
  /* first column widened from 5.5rem: these are spot illustrations rather
     than glyphs, and they stop reading below about 96px */
  grid-template-columns: 7rem 1fr 1.6fr;
  gap: 2rem;
  align-items: start;
  padding: 2.1rem 0;
  border-bottom: 1px solid var(--line-on-light);
  transition: background 0.3s var(--ease), padding-left 0.3s var(--ease);
}
.num-row:hover { background: rgba(255, 255, 255, 0.6); padding-left: 0.75rem; }
.num-row .num-icon {
  display: block;
  width: 100%;
  height: auto;
  max-width: 7rem;
  /* the artwork carries its own margin, so it sits optically level with the
     heading without a nudge */
}
.num-row h3 { color: var(--ink); }
.num-row p { font-size: 0.99rem; max-width: none; }
/* dark-band variant */
.band-green .num-list { border-top-color: var(--line-on-dark); }
.band-green .num-row { border-bottom-color: var(--line-on-dark); }
.band-green .num-row:hover { background: rgba(240, 243, 240, 0.05); }
.band-green .num-row h3 { color: var(--light); }
@media (max-width: 800px) {
  /* 80px, not the 56px the numbers used: the illustrations lose their
     detail below about 5rem and there is no room for more than that */
  .num-row { grid-template-columns: 5rem 1fr; gap: 1rem; }
  .num-row p { grid-column: 2; }
}

/* ---------- Journey (3 phase columns x 2 steps, on green) ---------- */
.journey {
  position: relative;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1.5rem, 3vw, 2.5rem);
}
@media (max-width: 900px) { .journey { grid-template-columns: 1fr; } }

/* the thread: a single line that starts at step 01 and loops through
   every step as the section scrolls. Base = faint full path;
   draw = bright copy revealed by scroll-driven dashoffset. */
.journey-line {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
  z-index: 0;
}
.journey-line .jl-base {
  stroke: rgba(240, 243, 240, 0.12);
  stroke-width: 1.5;
}
.journey-line .jl-draw {
  stroke: rgba(240, 243, 240, 0.65);
  stroke-width: 1.5;
  stroke-linecap: round;
}
.journey-step { position: relative; z-index: 1; }
/* serpentine reading order: 01 02 03 across the top,
   then back through 04 05 06 on the row below */
.journey { row-gap: clamp(4rem, 7vw, 6rem); }
@media (min-width: 901px) {
  .journey-step:nth-of-type(4) { grid-column: 3; grid-row: 2; }
  .journey-step:nth-of-type(5) { grid-column: 2; grid-row: 2; }
  .journey-step:nth-of-type(6) { grid-column: 1; grid-row: 2; }
}
/* square station badge the thread travels through */
.journey-step .step-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.2rem;
  height: 2.2rem;
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  color: rgba(240, 243, 240, 0.6);
  border: 1px solid var(--line-on-dark);
  background: var(--green);
  transition: background 0.4s var(--ease), color 0.4s var(--ease),
    border-color 0.4s var(--ease);
}
.journey-step.is-lit .step-num {
  background: var(--light);
  color: var(--green);
  border-color: var(--light);
}

/* card body "pulls up" as the line arrives at its badge */
.journey-step .step-body { margin-top: 1.4rem; }
@media (prefers-reduced-motion: no-preference) {
  .journey-step .step-body {
    transform: translateY(18px);
    opacity: 0.35;
    transition: transform 0.6s var(--ease), opacity 0.6s var(--ease);
  }
  .journey-step.is-lit .step-body { transform: none; opacity: 1; }
}
.journey-step .step-phase {
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(240, 243, 240, 0.55);
  margin-bottom: 0.9rem;
}
.journey-step img {
  height: 40px;
  width: auto;
  opacity: 0.85;
  margin-bottom: 1rem;
}
.journey-step h3 { color: var(--light); margin-bottom: 0.7rem; }
.journey-step p { font-size: 0.95rem; }

/* ---------- Research criteria: two pillars ----------
   The two core drivers. Deliberately identical: same column
   width, same 16:9 image, same padding. Nothing to go ragged. */
.pillars {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--grid-gap);
  margin-bottom: clamp(3.5rem, 7vw, 6rem);
}
.pillar {
  background: var(--white);
  border: 1px solid var(--line-on-light);
  padding: 0 0 var(--card-pad);
  transition: transform 0.3s var(--ease), box-shadow 0.3s var(--ease);
}
.pillar:hover {
  transform: translateY(-4px);
  box-shadow: 0 18px 40px -18px rgba(15, 50, 40, 0.25);
}
.pillar-img { overflow: hidden; margin-bottom: 1.7rem; }
.pillar-img img {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  transform: scale(1.001);
  transition: transform 0.8s var(--ease);
}
.pillar:hover .pillar-img img { transform: scale(1.04); }
.pillar .crit-num,
.pillar h3,
.pillar > p { padding-inline: var(--card-pad); }
.pillar h3 { margin-bottom: 0.7rem; }
.pillar > p:last-child { font-size: 0.99rem; }

@media (max-width: 760px) { .pillars { grid-template-columns: 1fr; } }

/* ---------- Scroll-scrubbed sprite media ----------
   Replaces the plain <img> inside a .card-img or a .pillar-img with a
   photo + canvas stack. The box carries the same 16/9 the two static image
   rules give their <img>, so card and pillar geometry is byte-identical
   whether a slot is animated or not, and the height is reserved before the
   sheet arrives. Selectors are written at the specificity of the rules they
   override, so none of this depends on source order and none of it needs
   !important. */
.build-media {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--grey);
}

/* both layers, stacked and cropped identically */
.card.has-img .build-media > img,
.card.has-img .build-media > canvas,
.pillar .build-media > img,
.pillar .build-media > canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  aspect-ratio: auto; /* kills the 16/9 the static image rules set */
  object-fit: cover;  /* on the canvas too: the DPR cap can leave the
                         backing store a hair off the box's ratio */
  transform: none;
}

/* The photo is the floor: painted from the first byte, never hidden, and the
   thing you are left looking at if anything at all goes wrong. The canvas
   only appears once it has actually drawn a frame, and steps back out at the
   end so the card settles as the ordinary static image. */
.build-media > canvas {
  opacity: 0;
  transition: opacity 0.35s var(--ease);
}
.build-media.is-armed > canvas { opacity: 1; }
.build-media.is-armed.is-complete > canvas { opacity: 0; }

/* The hover zoom the static cards get, applied to BOTH layers together so
   they cannot drift apart. It stays off .build-media itself on purpose: the
   scrub measures that box, and a transform on it would poison the maths
   every time the pointer crossed a card. */
.card.has-img .build-media > img,
.card.has-img .build-media > canvas {
  transition: transform 0.7s var(--ease), opacity 0.35s var(--ease);
}
.pillar .build-media > img,
.pillar .build-media > canvas {
  transition: transform 0.8s var(--ease), opacity 0.35s var(--ease);
}
.card.has-img:hover .build-media > img,
.card.has-img:hover .build-media > canvas { transform: scale(1.045); }
.pillar:hover .build-media > img,
.pillar:hover .build-media > canvas { transform: scale(1.04); }

/* progress hairline: opt-in, only rendered on the comparison page */
.build-progress {
  position: absolute;
  left: 0;
  bottom: 0;
  height: 2px;
  width: 100%;
  transform: scaleX(0);
  transform-origin: left;
  background: var(--light);
  mix-blend-mode: difference;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .build-media > canvas { display: none; }
}

/* ---------- Research criteria: the index ----------
   Five criteria as a numbered list against ONE sticky image
   frame. Because there is a single frame, every image is the
   same size by construction. The frame crossfades to whichever
   row is nearest the middle of the screen, or is hovered. */
.idx {
  display: grid;
  grid-template-columns: 0.9fr 1.1fr;
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: start;
}
.idx-media { position: sticky; top: 118px; } /* clears the 80px fixed header */
.idx-frame {
  position: relative;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  background: var(--white);
  border: 1px solid var(--line-on-light);
}
.idx-frame img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transform: scale(1.06);
  transition: opacity 0.7s var(--ease), transform 1.1s var(--ease);
}
.idx-frame img.is-on { opacity: 1; transform: scale(1); }

.idx-list { list-style: none; border-top: 1px solid var(--line-on-light); }
.idx-row {
  position: relative;
  display: grid;
  grid-template-columns: 3.4rem 1fr;
  gap: 1.25rem;
  padding: clamp(1.5rem, 2.6vw, 2.1rem) 0;
  border-bottom: 1px solid var(--line-on-light);
  transition: padding-left 0.45s var(--ease);
}
/* the green marker that slides down the list */
.idx-row::before {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  width: 2px;
  height: 0;
  background: var(--green);
  transform: translateY(-50%);
  transition: height 0.55s var(--ease);
}
.idx-num {
  font-size: 0.85rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  line-height: 2.2;
  color: var(--green);
  opacity: 0.45;
  transition: opacity 0.45s var(--ease);
}
.idx-copy h3 { margin-bottom: 0.55rem; }
.idx-copy p {
  font-size: 0.99rem;
  color: var(--text);
  opacity: 0.72;
  transition: opacity 0.45s var(--ease);
}
.idx-row.is-active { padding-left: 0.9rem; }
.idx-row.is-active::before { height: calc(100% - 2.4rem); }
.idx-row.is-active .idx-num { opacity: 1; }
.idx-row.is-active .idx-copy p { opacity: 1; }

@media (max-width: 900px) {
  .idx { grid-template-columns: 1fr; gap: 2rem; }
  .idx-media { position: static; }
  .idx-frame { aspect-ratio: 16 / 10; }
}
@media (max-width: 560px) {
  /* reclaim the number gutter on small phones */
  .idx-row { grid-template-columns: 2.2rem 1fr; gap: 0.85rem; }
}
@media (prefers-reduced-motion: reduce) {
  .idx-frame img { transition: opacity 0.2s linear; transform: none; }
}

/* ---------- Compare table (brand new vs established) ---------- */
.compare { border: 1px solid var(--line-on-light); background: var(--white); }
.compare-head,
.compare-row {
  display: grid;
  grid-template-columns: 0.7fr 1.15fr 1.15fr;
  gap: clamp(1rem, 2vw, 2rem);
  align-items: center;
  padding: 1.1rem clamp(1.25rem, 2.5vw, 2rem);
}
.compare-head {
  background: var(--green);
  color: var(--light);
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.compare-row { border-top: 1px solid var(--line-on-light); }
.compare-row:first-of-type { border-top: 0; }
.compare-row h3 { font-size: 1.05rem; }
.compare-row p { font-size: 0.96rem; max-width: none; }
.compare-row .is-new { color: var(--ink); font-weight: 500; }
@media (max-width: 700px) {
  .compare-head { display: none; }
  .compare-row { grid-template-columns: 1fr; gap: 0.35rem; padding-block: 1.25rem; }
  .compare-row .is-new::before { content: "Brand new: "; font-weight: 600; color: var(--green); }
  .compare-row p:last-child::before { content: "Established: "; font-weight: 600; color: var(--text); }
}

/* ---------- Quote ---------- */
.quote blockquote {
  font-size: clamp(1.4rem, 2.6vw, 2rem);
  line-height: 1.35;
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--ink);
  max-width: 24em;
}
.band-green .quote blockquote { color: var(--light); }
.quote figcaption { margin-top: 1.6rem; font-size: 0.98rem; }
.quote figcaption strong { display: block; color: var(--ink); font-weight: 600; }
.band-green .quote figcaption strong { color: var(--light); }

/* ---------- Testimonials slider ----------
   One quote at a time between "Our Approach" and the team. Slides
   share a single grid cell so the band keeps the height of the
   tallest quote and nothing below it jumps when you page through. */
.quote-slider { max-width: 60rem; margin-inline: auto; text-align: center; }
/* slides share one grid cell, so the band keeps the height of the
   tallest quote and never resizes when you page through; shorter
   quotes sit centred in that space */
.quote-track { list-style: none; margin: 0; padding: 0; display: grid; align-items: center; }
.quote-slide {
  grid-area: 1 / 1;
  opacity: 0;
  visibility: hidden;
  transform: translateY(10px);
  transition: opacity 0.5s var(--ease), transform 0.5s var(--ease), visibility 0s linear 0.5s;
}
.quote-slide.is-active {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity 0.5s var(--ease) 0.08s, transform 0.5s var(--ease) 0.08s, visibility 0s;
}
.quote-slide .quote { display: flex; flex-direction: column; align-items: center; }
.quote-slide .quote blockquote {
  max-width: 30em;
  margin-inline: auto;
  text-wrap: balance;
  font-size: clamp(1.15rem, 1.8vw, 1.5rem);
}
/* shorter than a full section so it reads as a pause, not a chapter */
.testimonials { padding-block: clamp(3.25rem, 6vw, 5rem); }
.testimonials .section-head { margin-bottom: clamp(1.75rem, 3.5vw, 2.5rem); }
.stars { display: inline-flex; gap: 0.2rem; margin-bottom: 1rem; color: var(--green); }
.stars svg { width: 18px; height: 18px; fill: currentColor; }
.quote-slide .quote figcaption {
  margin-top: 1.5rem;
  padding-top: 1.3rem;
  position: relative;
  color: var(--text);
}
.quote-slide .quote figcaption::before {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 48px;
  height: 1px;
  background: var(--line-on-light);
}
.placeholder-tag {
  display: block;
  width: fit-content;
  margin: 0.9rem auto 0;
  padding: 0.35rem 0.75rem;
  border: 1px dashed var(--green);
  color: var(--green);
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.quote-controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1.4rem;
  margin-top: 1.8rem;
}
.quote-arrow {
  width: 44px;
  height: 44px;
  border: 1px solid var(--line-on-light);
  border-radius: 50%;
  background: transparent;
  color: var(--ink);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: background 0.3s var(--ease), border-color 0.3s var(--ease), color 0.3s var(--ease);
}
.quote-arrow svg { width: 16px; height: 16px; }
.quote-arrow:hover, .quote-arrow:focus-visible { background: var(--green); border-color: var(--green); color: var(--light); outline: none; }
.quote-count { font-size: 0.92rem; font-weight: 500; color: var(--text); font-variant-numeric: tabular-nums; min-width: 3.2em; }
.quote-count .sep { margin-inline: 0.35em; opacity: 0.5; }
@media (prefers-reduced-motion: reduce) {
  .quote-slide, .quote-slide.is-active { transition: none; }
}
@media (max-width: 700px) {
  .quote-slide .quote blockquote { font-size: 1.08rem; line-height: 1.5; text-wrap: pretty; }
  .stars svg { width: 16px; height: 16px; }
  .quote-slide .quote figcaption { margin-top: 1.2rem; padding-top: 1.1rem; font-size: 0.92rem; }
  .quote-controls { margin-top: 1.6rem; gap: 2.25rem; }
  .quote-arrow { width: 52px; height: 52px; }
  .quote-arrow svg { width: 18px; height: 18px; }
  .quote-arrow:hover { background: transparent; border-color: var(--line-on-light); color: var(--ink); }
  .quote-arrow:active { background: var(--green); border-color: var(--green); color: var(--light); }
}

/* ---------- Team ---------- */
.team-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--grid-gap);
}
@media (max-width: 1000px) { .team-grid { grid-template-columns: repeat(2, 1fr); } }
.team-card {
  background: var(--white);
  border: 1px solid var(--line-on-light);
  overflow: hidden;
  transition: transform 0.3s var(--ease), box-shadow 0.3s var(--ease);
}
.team-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 18px 40px -18px rgba(15, 50, 40, 0.25);
}
.team-photo {
  background: var(--grey);
  aspect-ratio: 1 / 0.92;
  overflow: hidden;
  position: relative;
}
/* The photo is pinned to the box with absolute insets rather than a
   percentage max-height: iOS Safari resolves a percentage height
   against an aspect-ratio box as "none", so tall headshots overflowed
   and lost their heads. Absolute insets always resolve. */
.team-photo img {
  position: absolute;
  inset: 4% 9% 0;
  width: 82%;
  height: 96%;
  object-fit: contain;
  object-position: bottom center;
  filter: grayscale(1);
}
.team-meta { padding: 1.4rem 1.6rem 1.6rem; }
.team-meta h3 { font-size: 1.15rem; }
.team-meta .role { font-size: 0.92rem; margin-top: 0.35rem; }
.team-meta .bio { margin-top: 0.8rem; font-size: 0.95rem; }
.team-meta .text-link { margin-top: 1rem; display: inline-block; font-size: 0.9rem; }

/* Phones: keep two members side by side and shrink the card so the
   section scrolls in a few flicks instead of one card per screen. */
@media (max-width: 640px) {
  .team-grid { grid-template-columns: repeat(2, 1fr); gap: 0.9rem; }
  .team-photo { aspect-ratio: 1 / 1; }
  .team-photo img { inset: 4% 5% 0; width: 90%; }
  .team-meta { padding: 0.9rem 0.9rem 1.1rem; }
  .team-meta h3 { font-size: 0.95rem; line-height: 1.25; }
  .team-meta .role { font-size: 0.78rem; margin-top: 0.25rem; }
  .team-meta .bio { margin-top: 0.55rem; font-size: 0.78rem; line-height: 1.5; }
  .team-meta .text-link { margin-top: 0.7rem; font-size: 0.78rem; }
}

/* ---------- Partner logo marquee ---------- */
.logo-marquee {
  overflow: hidden;
  padding-block: 1rem;
  -webkit-mask-image: linear-gradient(to right, transparent, black 8%, black 92%, transparent);
  mask-image: linear-gradient(to right, transparent, black 8%, black 92%, transparent);
}
.logo-track {
  display: flex;
  align-items: center;
  gap: clamp(3rem, 6vw, 5.5rem);
  width: max-content;
  padding-right: clamp(3rem, 6vw, 5.5rem);
}
.logo-track img {
  height: auto;
  width: auto;
  max-height: 64px;
  max-width: 170px;
  filter: grayscale(1);
  opacity: 0.65;
  transition: opacity 0.3s var(--ease);
}
.logo-track img:hover { opacity: 1; }
@media (prefers-reduced-motion: no-preference) {
  .logo-marquee .logo-track { animation: marquee 45s linear infinite; }
  .logo-marquee:hover .logo-track { animation-play-state: paused; }
  @keyframes marquee { to { transform: translateX(-50%); } }
}
@media (max-width: 700px) {
  .logo-track img { max-height: 50px; max-width: 130px; }
}

/* ---------- Page hero (contact subpage) ---------- */
.page-hero {
  background: linear-gradient(160deg, var(--green) 0%, var(--green-deep) 100%);
  color: var(--light-soft);
  padding-top: clamp(9rem, 16vh, 12rem);
  padding-bottom: clamp(3.5rem, 7vw, 6rem);
}
.page-hero h1 {
  color: var(--light);
  font-size: clamp(2.4rem, 4.6vw, 3.8rem);
  max-width: 16ch;
}
.page-hero .lead { margin-top: 1.2rem; color: var(--light-soft); }

/* ---------- Contact page ---------- */
.contact-grid {
  display: grid;
  grid-template-columns: 0.9fr 1.1fr;
  gap: clamp(2.5rem, 5vw, 5rem);
  align-items: start;
}
@media (max-width: 900px) { .contact-grid { grid-template-columns: 1fr; } }
.contact-copy address {
  font-style: normal;
  line-height: 1.8;
  margin-top: 1.6rem;
}
.contact-copy .contact-img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  margin-top: 2.2rem;
}

.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1.3rem; }
@media (max-width: 700px) { .form-grid { grid-template-columns: 1fr; } }
.field { display: flex; flex-direction: column; gap: 0.45rem; }
.field.full { grid-column: 1 / -1; }
.field label { font-weight: 500; font-size: 0.94rem; color: var(--ink); }
.field input,
.field textarea {
  font: inherit;
  color: var(--ink);
  padding: 0.85rem 1rem;
  border: 1.5px solid rgba(16, 34, 27, 0.24);
  background: var(--white);
  transition: border-color 0.3s var(--ease), box-shadow 0.3s var(--ease);
}
.field input::placeholder, .field textarea::placeholder { color: rgba(16, 34, 27, 0.4); }
.field input:focus, .field textarea:focus {
  outline: none;
  border-color: var(--green);
  box-shadow: 0 0 0 3px rgba(15, 50, 40, 0.12);
}
.form-success { margin-top: 1rem; color: var(--green); font-weight: 500; }
.form-error { margin-top: 1rem; color: #8a2f2f; font-weight: 500; }
.form-error a { text-decoration: underline; }
.form-hp { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }

/* ---------- Map band (closing CTA: green copy panel + map) ---------- */
.map-band { padding-block: 0; }
.map-band .map-split { display: grid; grid-template-columns: 0.9fr 1.1fr; min-height: 440px; }
.map-band .map-copy {
  background: var(--green);
  color: var(--light-soft);
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 1.1rem;
  padding: clamp(2.5rem, 5vw, 4.5rem) clamp(1.5rem, 5vw, 4.5rem);
  /* text starts on the same left edge as every .container above it */
  padding-inline-start: max(clamp(1.5rem, 5vw, 4.5rem), calc((100vw - var(--container)) / 2));
}
.map-band .map-copy h2 { color: var(--light); }
.map-band .map-copy .eyebrow { color: var(--light-soft); }
.map-band .map-copy address { font-style: normal; line-height: 1.8; }
.map-band .map-copy .btn-primary { background: var(--light); color: var(--green); align-self: flex-start; margin-top: 0.6rem; }
.map-band .map-copy .btn-primary:hover { background: var(--white); }
.map-band .map-frame { position: relative; min-height: 420px; background: var(--grey); }
.map-band .map-frame iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
  filter: grayscale(1) contrast(1.02);
}
@media (max-width: 900px) {
  .map-band .map-split { grid-template-columns: 1fr; }
  .map-band .map-frame { min-height: 340px; }
}

/* ---------- Footer ---------- */
.site-footer {
  background: var(--green-deep);
  color: rgba(240, 243, 240, 0.75);
  font-size: 0.95rem;
}
.site-footer .top {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr 1.2fr;
  gap: clamp(2rem, 4vw, 4rem);
  padding-block: clamp(3rem, 6vw, 4.5rem) 2.5rem;
  border-bottom: 1px solid rgba(240, 243, 240, 0.14);
}
@media (max-width: 900px) { .site-footer .top { grid-template-columns: 1fr 1fr; } }
@media (max-width: 560px) { .site-footer .top { grid-template-columns: 1fr; } }
.site-footer .logo img { height: 30px; }
.site-footer .blurb { margin-top: 1.3rem; max-width: 300px; }
.site-footer h4 { color: var(--light); font-size: 1rem; font-weight: 600; margin-bottom: 1.1rem; }
.site-footer nav { display: grid; gap: 0.65rem; }
.site-footer a { transition: color 0.3s var(--ease); }
.site-footer a:hover { color: var(--white); }
.site-footer address { font-style: normal; line-height: 1.8; }
.site-footer .linkedin { display: inline-flex; margin-top: 0.9rem; }
.site-footer .linkedin svg { width: 20px; height: 20px; fill: currentColor; }
.site-footer .bottom {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  justify-content: center;
  padding-block: 1.6rem;
  font-size: 0.88rem;
  color: rgba(240, 243, 240, 0.5);
}

/* ---------- Reveal animations ---------- */
@media (prefers-reduced-motion: no-preference) {
  .reveal {
    opacity: 0;
    transform: translateY(44px);
    transition: opacity 0.8s var(--ease), transform 0.8s var(--ease);
    transition-delay: var(--d, 0ms);
  }
  .reveal.r-left { transform: translateX(-56px); }
  .reveal.r-right { transform: translateX(56px); }
  .reveal.r-fade { transform: none; }
  /* clip reveal for images: frame wipes up, image settles from a zoom */
  .reveal.r-clip {
    transform: none;
    clip-path: inset(12% 0 12% 0);
    transition: opacity 0.7s var(--ease), clip-path 1s var(--ease);
    transition-delay: var(--d, 0ms);
  }
  .reveal.r-clip img { transform: scale(1.1); transition: transform 1.2s var(--ease); transition-delay: var(--d, 0ms); }
  .reveal.r-clip.is-in { clip-path: inset(0 0 0 0); }
  .reveal.r-clip.is-in img { transform: scale(1); }
  /* blur focus: the card resolves out of a gaussian blur while it
     eases up and settles to full size. Used on the team grid. */
  .reveal.r-blur {
    transform: translateY(22px) scale(0.94);
    filter: blur(13px);
    transition: opacity 0.85s var(--ease), transform 0.95s var(--ease),
      filter 0.95s var(--ease);
    transition-delay: var(--d, 0ms);
  }
  .reveal.r-blur.is-in { filter: blur(0); }
  .reveal.is-in { opacity: 1; transform: none; }
}

/* Hover transforms have to outrank `.reveal.is-in { transform: none }`,
   which sits later in this file and would otherwise cancel them.
   .card-float is excluded: it has its own, larger lift above. */
.card.reveal.is-in:hover:not(.card-float),
.pillar.reveal.is-in:hover,
.team-card.reveal.is-in:hover { transform: translateY(-4px); }
/* team cards inherit the slow 0.95s reveal timing, which is sluggish
   for a hover; give the lift its own quick curve on the way in. */
.team-card.reveal.is-in:hover {
  transition: transform 0.3s var(--ease), box-shadow 0.3s var(--ease);
}


/* ---------- Sweep lift page transition ----------
   Leaving: the page lifts and fades back while a green panel
   sweeps up from the bottom. Arriving: the panel sweeps up and
   off the top while the new page settles down into place. */
.page-sweep {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: var(--green);
  clip-path: inset(100% 0 0 0);
  pointer-events: none;
  will-change: clip-path;
}
/* NOTE: no will-change here. A will-change/transform on this wrapper
   creates a containing block, which would break the fixed header.
   It is only promoted while a transition is actually running. */
body.is-leaving .page-shift,
body.is-arriving .page-shift { will-change: transform, opacity; }

@media (prefers-reduced-motion: no-preference) {
  .page-sweep { transition: clip-path 0.62s cubic-bezier(0.76, 0, 0.24, 1); }
  .page-shift {
    transition: transform 0.62s cubic-bezier(0.76, 0, 0.24, 1),
      opacity 0.5s ease-out;
  }
  /* leaving */
  body.is-leaving .page-sweep { clip-path: inset(0 0 0 0); }
  body.is-leaving .page-shift {
    transform: translateY(-42px) scale(0.97);
    opacity: 0.45;
  }
  /* arriving: panel covers, then lifts away off the top */
  body.is-arriving .page-sweep { clip-path: inset(0 0 0 0); transition: none; }
  body.is-arriving .page-shift {
    transform: translateY(46px) scale(0.99);
    opacity: 0.5;
    transition: none;
  }
  body.is-arriving.is-revealed .page-sweep {
    clip-path: inset(0 0 100% 0);
    transition: clip-path 0.72s cubic-bezier(0.76, 0, 0.24, 1);
  }
  body.is-arriving.is-revealed .page-shift {
    transform: none;
    opacity: 1;
    transition: transform 0.72s cubic-bezier(0.76, 0, 0.24, 1),
      opacity 0.55s ease-out 0.08s;
  }
}


/* ---------- Lift cards (mission / vision) ----------
   At rest they sit flat with a soft shadow. On hover they glide up
   and scale slightly in one smooth move. No idle animation.
   Selectors are .card.card-float so they outrank .reveal.is-in,
   whose transform would otherwise cancel the lift. */
.card.card-float {
  box-shadow: 0 22px 44px -26px rgba(15, 50, 40, 0.34);
  transition: transform 0.55s cubic-bezier(0.16, 1, 0.3, 1),
    box-shadow 0.55s cubic-bezier(0.16, 1, 0.3, 1);
}
.card.card-float:hover {
  transform: translateY(-14px) scale(1.025);
  box-shadow: 0 44px 76px -30px rgba(15, 50, 40, 0.5);
}
@media (prefers-reduced-motion: reduce) {
  .card.card-float:hover { transform: none; }
}

/* ---------- EDM signup band ---------- */
.edm-band { scroll-margin-top: 80px; }
.edm-split { display: grid; grid-template-columns: 0.9fr 1.1fr; gap: clamp(2rem, 5vw, 5rem); align-items: center; }
.edm-copy p { margin-top: 1.1rem; max-width: 480px; }
.edm-fields { display: grid; grid-template-columns: 1fr 1.4fr auto; gap: 0.9rem; align-items: end; }
.edm-fields .edm-submit { align-self: stretch; justify-content: flex-end; }
.edm-submit .btn { width: 100%; white-space: nowrap; min-height: 3.4rem; padding-block: 0; justify-content: center; }
@media (min-width: 901px) { .edm-fields .edm-submit .btn { height: calc(1.0625rem * 1.65 + 1.7rem + 3px); } }
.edm-form .field input { background: var(--white); }
.band-white .edm-form .field input { background: var(--grey); }
.edm-note { margin-top: 0.8rem; font-size: 0.86rem; color: rgba(16, 34, 27, 0.72); }
.edm-hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
@media (max-width: 900px) {
  .edm-split { grid-template-columns: 1fr; }
  .edm-fields { grid-template-columns: 1fr; }
}

/* ---------- EDM popup ---------- */
.edm-popup { position: fixed; inset: 0; z-index: 200; display: flex; align-items: center; justify-content: center; padding: 1.25rem; }
.edm-popup[hidden] { display: none; }
.edm-popup-backdrop { position: absolute; inset: 0; background: rgba(11, 36, 28, 0.55); backdrop-filter: blur(3px); }
.edm-popup-card {
  position: relative;
  width: min(560px, 100%);
  background: var(--white);
  color: var(--text);
  padding: clamp(1.75rem, 4vw, 2.75rem);
  padding-top: 3rem;
  border-radius: 6px;
  outline: none;
  max-height: calc(100dvh - 2.5rem);
  overflow-y: auto;
  box-shadow: 0 30px 80px rgba(11, 36, 28, 0.35);
  animation: edm-pop-in 420ms cubic-bezier(0.2, 0.8, 0.2, 1) both;
}
.edm-popup-card h3 { font-size: clamp(1.5rem, 3vw, 2rem); color: var(--green); margin-top: 0.6rem; }
.edm-popup-card > p { margin-top: 0.8rem; margin-bottom: 1.4rem; }
.edm-popup-card .edm-fields { grid-template-columns: 1fr; }
.edm-popup-close {
  position: absolute; top: 1rem; right: 1rem;
  width: 44px; height: 44px; border: 0; background: transparent; cursor: pointer;
  font-size: 1.75rem; line-height: 1; color: var(--ink); opacity: 0.6;
}
.edm-popup-close:hover { opacity: 1; }
@keyframes edm-pop-in { from { opacity: 0; transform: translateY(14px) scale(0.98); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .edm-popup-card { animation: none; } }
.edm-popup-open body { overflow: hidden; }
