/* ==========================================================================
   Anthēs — website
   Built from the Figma wireframes:
   https://www.figma.com/design/xp3obswESWvPL1qPzJWe7U
   Tokens follow 10-wiki/clients/anthēs/brand-os/07-design-system/code/Code.md
   ========================================================================== */

/* --------------------------------------------------------------------------
   0. Typeface — DM Sans, served from anthes.ca itself (2026-10-15)
   No call to Google Fonts: visitors' IP addresses go to no outside service
   (Law 25). The two variable files (from Google Fonts, DM Sans v17, SIL Open
   Font License) carry every weight and the optical-size axis; latin-ext holds
   the macron of Anthēs. Replaces the Google Fonts <link> on every page.
   -------------------------------------------------------------------------- */
@font-face {
  font-family: 'DM Sans';
  font-style: normal;
  font-weight: 100 1000;
  font-display: swap;
  src: url('../fonts/dm-sans-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-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'DM Sans';
  font-style: normal;
  font-weight: 100 1000;
  font-display: swap;
  src: url('../fonts/dm-sans-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;
}

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */
:root {
  /* System */
  --ink:            #231f20;
  --paper:          #ffffff;
  --shell-bg:       #fbfaf6;

  /* Bloom palette — Tier 1 only */
  --sun-yellow:     #e8d52b;  /* Clarity   / Foundation  */
  --marigold:       #f4a31f;  /* Strategy  / Essential   */
  --coral-pink:     #cf447a;  /* Launch    / Growth      */
  --crimson:        #e83c37;  /* Momentum  / Accelerator */
  --lime:           #a0cc3a;
  --sage-green:     #53a262;
  --sky:            #3392cf;
  --iris-purple:    #766db1;

  /* Editorial greys */
  --ink-100:        #231f20;
  --ink-70:         #5e5b5c;
  --ink-40:         #a8a6a7;
  --ink-15:         #dbdada;

  /* The Anthēs CTA gradient (Figma style: "GRADIENT ANTHES") */
  --gradient-anthes: linear-gradient(90deg, #f4a31f 0%, #db3072 100%);

  /* Type */
  --font:           "DM Sans", system-ui, -apple-system, sans-serif;
  --w-regular:      400;
  --w-bold:         700;
  --lh-body:        1.6;
  --lh-hero:        1.1;

  /* Layout — the Figma page frame is 1280 with a 1144 content column */
  --frame:          1280px;
  --content:        1144px;
  --gutter:         clamp(20px, 5vw, 68px);

  /* Shape */
  --radius-pill:    9999px;

  /* Motion */
  --transition:     color 180ms ease, background-color 180ms ease,
                    border-color 180ms ease, opacity 180ms ease;
}

/* Package / pillar colour mapping — never swapped */
[data-package="foundation"]  { --package: var(--sun-yellow); --on-package: var(--ink); }
[data-package="essential"]   { --package: var(--marigold);   --on-package: #fff; }
[data-package="growth"]      { --package: var(--coral-pink); --on-package: #fff; }
[data-package="accelerator"] { --package: var(--crimson);    --on-package: #fff; }

/* --------------------------------------------------------------------------
   2. Reset
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font);
  font-weight: var(--w-regular);
  font-size: 16px;
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;

  /* Every text node in the Figma file pins DM Sans's optical-size axis to 14.
     Without this the browser auto-tracks opsz to the font size, which makes
     display type noticeably narrower and changes every headline's wrap. */
  font-optical-sizing: none;
  font-variation-settings: "opsz" 14;
}

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

a { color: inherit; text-decoration: none; transition: var(--transition); }

h1, h2, h3, h4, h5, h6, p, figure, blockquote { margin: 0; }

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

button, input, textarea, select { font: inherit; color: inherit; }

:focus-visible {
  outline: 2px solid var(--package, var(--ink));
  outline-offset: 2px;
}

/* Accessibility helpers */
.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip-link {
  position: absolute; left: 8px; top: -60px; z-index: 100;
  background: var(--ink); color: var(--paper);
  padding: 10px 16px; border-radius: var(--radius-pill);
  font-size: 14px; font-weight: var(--w-bold);
}
.skip-link:focus { top: 8px; }

/* --------------------------------------------------------------------------
   3. Layout primitives
   -------------------------------------------------------------------------- */
.shell {
  width: min(var(--content), 100% - (2 * var(--gutter)));
  margin-inline: auto;
}

.shell--wide {
  width: min(1196px, 100% - (2 * var(--gutter)));
  margin-inline: auto;
}

section { position: relative; }

/* The warm-gradient divider — left to right, always, stops in package order */
.rainbow-divider {
  height: 6px;
  width: 100%;
  border: 0;
  margin: 0;
  background: linear-gradient(
    90deg,
    var(--sun-yellow) 0%,
    var(--marigold)   33%,
    var(--coral-pink) 66%,
    var(--crimson)    100%
  );
}

/* Gradient-filled words inside a heading (Figma style "GRADIENT ANTHES").
   Falls back to solid marigold where background-clip:text is unsupported. */
.grad {
  color: var(--marigold);
  background: var(--gradient-anthes);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}
@supports not ((background-clip: text) or (-webkit-background-clip: text)) {
  .grad { background: none; -webkit-text-fill-color: currentColor; color: var(--coral-pink); }
}
.grad--bold { font-weight: var(--w-bold); }

/* --- The section header pattern, repeated on every page -------------------
   Eyebrow at 12/1.68 uppercase, a 52/61 heading with one bold coloured
   emphasis, and an optional 16/27 standfirst. */
.section-eyebrow {
  font-size: 12px;
  line-height: normal;   /* Figma leaves this on auto, not the body's 1.6 */
  font-weight: var(--w-bold);
  letter-spacing: 1.68px;
  text-transform: uppercase;
  color: var(--marigold);
}

.section-title {
  font-size: 52px;
  font-weight: var(--w-regular);
  line-height: 61px;
  letter-spacing: -0.62px;
  color: var(--ink);
}
.section-title strong { font-weight: var(--w-bold); }

.section-sub {
  font-size: 16px;
  line-height: 27px;
  color: var(--ink-70);
}

/* Emphasis colours, named so a section can pick its accent explicitly */
.is-marigold { color: var(--marigold); }
.is-coral    { color: var(--coral-pink); }
.is-crimson  { color: var(--crimson); }
.is-sun      { color: var(--sun-yellow); }
.is-sage     { color: var(--sage-green); }
.is-iris     { color: var(--iris-purple); }

/* On the dark sections the same pattern flips to white */
.on-dark .section-title { color: #fff; }
.on-dark .section-sub   { color: #a4a4a4; }

/* Small uppercase section label */
.eyebrow {
  font-size: 13px;
  font-weight: var(--w-bold);
  letter-spacing: 1.54px;
  text-transform: uppercase;
  line-height: 18px;
  color: var(--ink);
}

/* --------------------------------------------------------------------------
   4. Buttons
   -------------------------------------------------------------------------- */
.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-pill);
  font-weight: var(--w-bold);
  line-height: normal;        /* Figma uses the font default, not body 1.6 */
  transition: var(--transition);
  cursor: pointer;
  text-align: center;
}

/* The design system requires a 44px minimum touch target, but the Figma draws
   the small buttons at ~35px. Rather than inflate the button — which pushed
   the header to 72px instead of 63 — the hit area is extended invisibly, so
   the drawn height is kept and the target still clears 44px. */
.btn::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  height: max(100%, 44px);
}

.btn--gradient {
  background: var(--gradient-anthes);
  color: #fff;
  border: 0;
  padding: 9px 18px;
  font-size: 13px;
}
.btn--gradient:hover { filter: brightness(0.94); }

.btn--primary {
  background: var(--package, var(--marigold));
  color: var(--on-package, #fff);
  border: 0;
  padding: 13px 26px;
  font-size: 14px;
}
.btn--primary:hover { filter: brightness(0.9); }

.btn--outline {
  background: transparent;
  border: 1.5px solid var(--ink);
  color: var(--ink);
  padding: 13px 26px;
  font-size: 14px;
}
.btn--outline:hover { background: var(--ink); color: var(--paper); }

.btn--link {
  background: none; border: 0; padding: 0;
  min-height: 0;
  color: var(--ink);
  font-weight: var(--w-regular);
  text-decoration: underline;
}
.btn--link:hover { color: var(--package, var(--marigold)); }

/* --------------------------------------------------------------------------
   5. Site header / nav
   -------------------------------------------------------------------------- */
.site-header {
  background: var(--paper);
  position: sticky;
  top: 0;
  z-index: 50;
}

/* Full width — the logo sits against the left edge and the nav against the
   right, at the page gutter. At 1280 this is identical to the Figma frame. */
.site-header__inner {
  padding: 14px var(--gutter);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
}

/* Dark variant — used on the case-study page, whose whole frame is black.
   Pairs with the -light logo file, same as the dark footer. */
.site-header--dark { background: #000; }
.site-header--dark .site-nav a:not(.btn) { color: #fff; }
.site-header--dark .site-nav a:not(.btn):hover { color: var(--marigold); }
.site-header--dark .nav-toggle span,
.site-header--dark .nav-toggle span::before,
.site-header--dark .nav-toggle span::after { background: #fff; }
.site-header--dark .nav-toggle[aria-expanded="true"] span { background: transparent; }

@media (max-width: 860px) {
  .site-header--dark .site-nav {
    background: #000;
    border-color: rgba(255, 255, 255, 0.18);
  }
}

.site-header__logo img { width: 139px; height: 35px; }

.site-nav { display: flex; align-items: center; gap: 32px; }

/* :not(.btn) so the nav link scale doesn't override the button's own type,
   which was inflating the header from 63px to 68px */
.site-nav a:not(.btn) {
  font-size: 14px;
  line-height: 22px;
  color: var(--ink);
  white-space: nowrap;
}
.site-nav a:not(.btn):hover { color: var(--marigold); }
.site-nav a[aria-current="page"] { font-weight: var(--w-bold); }
/* FR/EN switch, added to every page's menu by tools/i18n/build.py */
.site-nav a.site-nav__lang {
  font-size: 12px;
  font-weight: var(--w-bold);
  letter-spacing: 1.2px;
  margin-left: -12px;   /* sits closer to the button than the other links */
}

/* Mobile nav toggle — not in the Figma (desktop-only file); derived. */
.nav-toggle {
  display: none;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  width: 44px; height: 44px;
  align-items: center;
  justify-content: center;
}
.nav-toggle span,
.nav-toggle span::before,
.nav-toggle span::after {
  display: block;
  width: 22px; height: 1.5px;
  background: var(--ink);
  content: "";
  transition: transform 180ms ease, opacity 180ms ease;
}
.nav-toggle span::before { transform: translateY(-7px); }
.nav-toggle span::after  { transform: translateY(5.5px); }
.nav-toggle[aria-expanded="true"] span { background: transparent; }
.nav-toggle[aria-expanded="true"] span::before { transform: rotate(45deg); }
.nav-toggle[aria-expanded="true"] span::after  { transform: rotate(-45deg) translateY(0); }

/* --------------------------------------------------------------------------
   6. Site footer
   -------------------------------------------------------------------------- */
.site-footer {
  background: var(--shell-bg);
  border-top: 1px solid var(--ink-15);
}

.site-footer__inner {
  max-width: var(--frame);
  margin-inline: auto;
  padding: 48px var(--gutter) 32px;
  display: flex;
  flex-direction: column;
  gap: 48px;
}

.site-footer__columns {
  display: flex;
  gap: 32px;
  align-items: flex-start;
}

.site-footer__col {
  width: 275px;
  flex: 0 1 275px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.site-footer__col > * { margin: 0; }

.site-footer__brand { display: flex; flex-direction: column; gap: 25px; }
.site-footer__brand img { width: 167px; height: 42px; }
.site-footer__brand p {
  font-size: 13px;
  line-height: 21px;
  color: var(--ink-70);
  max-width: 247px;
}

.site-footer__heading {
  font-size: 11px;
  font-weight: var(--w-bold);
  letter-spacing: 1.54px;
  line-height: 18px;
  text-transform: uppercase;
  color: var(--ink);
  /* the 16px below the heading is the column's own gap */
}

.site-footer__links { display: flex; flex-direction: column; gap: 10px; }
/* The line box has to be pinned on the li too, or the list inherits body 1.6 */
.site-footer__links li,
.site-footer__links a { font-size: 14px; line-height: 18px; }
.site-footer__links a:hover { color: var(--marigold); }

/* The framework column carries the four locked pillar colours */
.site-footer__links--framework a { font-weight: var(--w-bold); }
.site-footer__links--framework .is-clarity  { color: var(--sun-yellow); }
.site-footer__links--framework .is-strategy { color: var(--marigold); }
.site-footer__links--framework .is-launch   { color: var(--coral-pink); }
.site-footer__links--framework .is-momentum { color: var(--crimson); }

/* Dark variant — used on Packages, where the footer follows a black CTA */
.site-footer--dark { background: #000; border-top-color: rgba(255, 255, 255, 0.18); }
.site-footer--dark .site-footer__heading { color: #fff; }
.site-footer--dark .site-footer__links a { color: #fff; }
.site-footer--dark .site-footer__brand p,
.site-footer--dark .site-footer__legal { color: rgba(255, 255, 255, 0.62); }
.site-footer--dark .site-footer__legal { border-top-color: rgba(255, 255, 255, 0.18); }
.site-footer--dark .site-footer__links--framework .is-clarity  { color: var(--sun-yellow); }
.site-footer--dark .site-footer__links--framework .is-strategy { color: var(--marigold); }
.site-footer--dark .site-footer__links--framework .is-launch   { color: var(--coral-pink); }
.site-footer--dark .site-footer__links--framework .is-momentum { color: var(--crimson); }

.site-footer__legal {
  border-top: 1px solid var(--ink-15);
  padding-top: 24px;
  display: flex;
  justify-content: space-between;
  gap: 16px;
  font-size: 12px;
  line-height: 19px;
  color: var(--ink-70);
}

/* --------------------------------------------------------------------------
   7. Shared sections that repeat across pages
   -------------------------------------------------------------------------- */

/* --- "What they say" — Figma 596:2112 (also on Packages and About) ---------
   Two rows of quote cards, deliberately offset in opposite directions so they
   bleed past the content column on both sides. */
.says {
  background: #000;
  position: relative;
  overflow: hidden;
  padding: 113px 0 128px;
}

/* Heading sits in the centred content column; the quote rows are offset from
   that same column, so the stagger stays put as the viewport grows. */
.says__head {
  width: min(var(--content), 100% - (2 * var(--gutter)));
  margin-inline: auto;
}

.says__eyebrow {
  font-size: 12px;
  font-weight: var(--w-bold);
  letter-spacing: 1.68px;
  text-transform: uppercase;
  color: var(--crimson);
}

.says__title {
  margin: 22px 0 0;
  max-width: 669px;
  font-size: 52px;
  font-weight: var(--w-regular);
  line-height: 56px;
  letter-spacing: -0.62px;
  color: #fff;
}
.says__title strong { font-weight: var(--w-bold); color: var(--crimson); }

.says__stage {
  position: relative;
  width: min(var(--content), 100% - (2 * var(--gutter)));
  margin: 87px auto 0;
}

.says__row { display: flex; align-items: stretch; gap: 20px; width: 1132px; }
.says__row--a { margin-left: 57px; }                     /* offset right */
.says__row--b { margin-left: -99px; margin-top: 23px; }  /* offset left  */

.quote {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 3px;
  padding: 40px 30px;
  border: 1px solid currentColor;
  border-radius: 15px;
}
.quote--fixed { flex: 0 0 526px; width: 526px; }

.quote--iris    { color: var(--iris-purple); }
.quote--marigold{ color: var(--marigold); }
.quote--lime    { color: #a4ce44; }
.quote--sky     { color: var(--sky); }
.quote--crimson { color: var(--crimson); }

.quote img { flex: 0 0 46px; width: 46px; height: 46px; border-radius: 50%; }

.quote p {
  flex: 1 1 0;
  min-width: 0;
  padding-inline: 15px;
  font-size: 20.8px;
  line-height: 29px;
  letter-spacing: -0.1px;
  color: #fff;
}

/* --- "What they say" as a marquee (motion.js adds .is-marquee) ------------
   Full-width stage, edges faded with a mask so it works on black, beige and
   white bands alike. Cards keep a fixed width and use margin, not gap, so
   the two halves of the track are exactly equal and -50% loops cleanly. */
.says.is-marquee .says__stage {
  width: 100%;
  margin-inline: 0;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 14%, #000 86%, transparent 100%);
          mask-image: linear-gradient(90deg, transparent 0, #000 14%, #000 86%, transparent 100%);
}
.says.is-marquee .says__row {
  width: max-content;
  margin-left: 0;
  flex-direction: row;
  gap: 0;
  animation: says-left var(--says-dur, 45s) linear infinite;
}
.says.is-marquee .says__row--b {
  animation-name: says-right;
  animation-delay: -9s;            /* keeps the two rows visibly staggered */
}
.says.is-marquee .says__stage:hover .says__row { animation-play-state: paused; }
.says.is-marquee .quote,
.says.is-marquee .quote--fixed { flex: 0 0 auto; width: min(526px, 78vw); margin-right: 20px; }

@keyframes says-left  { from { transform: translateX(0); }    to { transform: translateX(-50%); } }
@keyframes says-right { from { transform: translateX(-50%); } to { transform: translateX(0); } }

/* --- Next step CTA — Figma 594:1304 (repeats on most pages) ---------------- */
/* Fixed-height frame in Figma (798). Content starts at the top and the wave
   runs off the bottom edge, where the frame clips it. The height now follows
   the wave (see .nextstep__wave) so the clip scales on wide screens; at 1280
   it still measures 798. */
.nextstep {
  background: #000;
  overflow: hidden;
  padding: 128px 48px 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
}

.nextstep__copy {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  margin-bottom: -18px;
  position: relative;
  z-index: 1;
}

.nextstep__eyebrow {
  font-size: 12px;
  font-weight: var(--w-bold);
  letter-spacing: 1.68px;
  text-transform: uppercase;
  text-align: center;
  color: var(--marigold);
}

.nextstep__title {
  /* Figma box is 720px; widened so the heading stays two lines in Chrome. */
  max-width: 790px;
  font-size: 52px;
  font-weight: var(--w-regular);
  line-height: 61px;
  letter-spacing: -0.62px;
  text-align: center;
  color: #fff;
}
.nextstep__title strong { font-weight: var(--w-bold); color: var(--sun-yellow); }

.nextstep__sub {
  max-width: 549px;
  font-size: 16px;
  line-height: 25.6px;
  text-align: center;
  color: rgba(255, 255, 255, 0.78);
}

.btn--ghost-light {
  background: transparent;
  border: 1px solid #fff;
  color: #fff;
  padding: 14px 26px;
  font-size: 15px;
}
.btn--ghost-light:hover { background: #fff; color: #000; }

/* The wave always spans the full section width, edge to edge. The SVG's
   viewBox is trimmed to the coloured fill (x 21–1323 of Figma's 1356), so
   there is no empty margin left inside the file. Below 1302 it stays at its
   drawn size and bleeds past both edges; above, it scales up with the screen.
   The negative margin is Figma's clip: 198.5 of 595.66px hidden, i.e. 15.243%
   of the wave's width. */
.nextstep__wave {
  --wave-w: max(1302px, calc(100% + 96px));
  width: var(--wave-w);
  max-width: none;
  height: auto;
  flex: 0 0 auto;
  margin-bottom: calc(var(--wave-w) * -0.15243);
}

/* --------------------------------------------------------------------------
   8. Responsive — derived, no mobile artboards exist in the Figma
   -------------------------------------------------------------------------- */
@media (max-width: 1279px) {
  .says { padding: 96px 0 104px; }
  .says__title { font-size: clamp(34px, 4.2vw, 52px); line-height: 1.12; }
  .says__stage { margin-top: 56px; }
  .says__row { width: 100%; }
  .says__row--a { margin-left: 0; }
  .says__row--b { margin-left: 0; }
  .quote--fixed { flex: 1 1 0; width: auto; }

  .nextstep { height: auto; padding: 96px var(--gutter) 0; }
  .nextstep__title { font-size: clamp(32px, 4.2vw, 52px); line-height: 1.17; }
  /* The Figma frame clips the bottom third of the wave (199 of 596px). Keep
     that clip here: the wave is 140% wide, so its height is ~64% of the
     content width and a third of it is ~21.3%. Without this the whole wave
     showed, plus 96px of padding — a tall empty band before the footer. */
  .nextstep__wave { width: 140%; height: auto; margin-bottom: -21.3%; }
}

@media (max-width: 860px) {
  .says__row { flex-direction: column; }
  .quote p { font-size: 18px; line-height: 26px; }
}
@media (max-width: 1024px) {
  .site-footer__columns { flex-wrap: wrap; }
  .site-footer__col { flex: 0 1 calc(50% - 16px); width: auto; }
}

@media (max-width: 860px) {
  .site-header__inner { position: relative; }

  .nav-toggle { display: inline-flex; }

  .site-nav {
    display: none;
    position: absolute;
    inset: 100% 0 auto 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    background: var(--paper);
    border-top: 1px solid var(--ink-15);
    border-bottom: 1px solid var(--ink-15);
    padding: 8px var(--gutter) 20px;
  }
  .site-nav.is-open { display: flex; }
  .site-nav a { padding: 12px 0; line-height: 24px; }
  /* the link padding above zeroed the button's sides: give them back */
  .site-nav .btn { margin-top: 12px; align-self: flex-start; padding: 12px 22px; }
  .site-nav a.site-nav__lang { margin-left: 0; margin-top: 8px; }
}

@media (max-width: 640px) {
  .site-footer__columns { flex-direction: column; gap: 32px; }
  .site-footer__col { flex: 1 1 auto; }
  .site-footer__legal { flex-direction: column; gap: 8px; }
}

/* --------------------------------------------------------------------------
   9. Motion
   The design system forbids parallax, counting numbers and entrance animation
   on every element; David approved overriding those (see build-notes.md).
   All of it is scoped to html.js so a no-JS page renders in its final state,
   and all of it is switched off under prefers-reduced-motion.
   -------------------------------------------------------------------------- */
:root {
  --ease-out: cubic-bezier(0.22, 0.61, 0.36, 1);
  --reveal-rise: 18px;
}

.js [data-reveal],
.js [data-stagger] > * {
  opacity: 0;
  transform: translateY(var(--reveal-rise));
}

.js [data-reveal] {
  transition: opacity 700ms var(--ease-out), transform 700ms var(--ease-out);
}

.js [data-stagger] > * {
  transition:
    opacity 620ms var(--ease-out) var(--d, 0ms),
    transform 620ms var(--ease-out) var(--d, 0ms);
}

.js [data-reveal].is-in,
.js [data-stagger].is-in > * {
  opacity: 1;
  transform: none;
}

/* Parallax layers are positioned by script; the hint is dropped once settled */
.js [data-parallax] { will-change: transform; }

/* Counting figures hold their width so the digits don't jitter the line */
.stat__value,
.results__card p { font-variant-numeric: tabular-nums; }

/* Card lift on hover — the one approved exception to "hover changes colour
   only". Applies to the cards that behave like links. */
.pcard,
.acard {
  transition:
    transform 220ms var(--ease-out),
    box-shadow 220ms var(--ease-out),
    border-color 180ms ease;
}
.pcard:hover,
.acard:hover,
.acard:focus-within {
  transform: translateY(-3px);
  box-shadow: 0 10px 28px rgba(35, 31, 32, 0.10);
  border-color: var(--ink-40);
}

/* The arrow in a CTA leads the eye without moving the button */
.btn span[aria-hidden],
.hero__link span[aria-hidden],
.cstudy__link span[aria-hidden] {
  display: inline-block;
  transition: transform 200ms var(--ease-out);
}
.btn:hover span[aria-hidden],
.hero__link:hover span[aria-hidden],
.cstudy__link:hover span[aria-hidden] { transform: translateX(3px); }

html { scroll-behavior: smooth; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  /* Nothing hides, nothing moves, nothing parallaxes. */
  .js [data-reveal],
  .js [data-stagger] > * { opacity: 1 !important; transform: none !important; }

  .js [data-parallax] { transform: none !important; will-change: auto; }

  .pcard:hover,
  .acard:hover,
  .acard:focus-within { transform: none; box-shadow: none; }

  .btn:hover span[aria-hidden],
  .hero__link:hover span[aria-hidden],
  .cstudy__link:hover span[aria-hidden] { transform: none; }
}

/* The hidden attribute always wins over a section's own display (e.g. the
   homepage "Trusted by" strip, parked until there are more client logos). */
[hidden] { display: none !important; }

/* --------------------------------------------------------------------------
   Motion helpers (motion.js; only when motion is allowed and JS runs)
   -------------------------------------------------------------------------- */
/* Lazy images: hidden until fully loaded, then fade in to their own opacity */
html.js.fade-imgs img[loading="lazy"]:not([data-loaded]) { opacity: 0; }
html.js.fade-imgs img[data-loaded="fresh"] { animation: img-in 0.6s var(--ease-out, ease-out); }
@keyframes img-in { from { opacity: 0; } }

/* Lenis smooth scrolling (its recommended base styles) */
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }
.lenis.lenis-smooth [data-lenis-prevent] { overscroll-behavior: contain; }
.lenis.lenis-stopped { overflow: hidden; }

/* Spam trap (assets/js/antispam.js): off-screen, never shown, never focused */
.hp-trap { position: absolute; left: -10000px; top: auto; width: 1px; height: 1px; overflow: hidden; }
