/* ==========================================================================
   Valeris Group — front-end design system
   Everything is scoped under .valeris-page so it can be dropped into a
   WordPress shortcode / plugin without touching the active theme, Elementor
   or the WP admin bar. There is no global reset on purpose.
   ========================================================================== */

.valeris-page {
  /* --- Brand colours (carried over from the existing Elementor globals) --- */
  --v-navy: #132750;          /* e-global-color-primary   */
  --v-accent: #003a6a;        /* e-global-color-accent    */
  --v-copper: #cd9483;        /* e-global-color-secondary */
  /* Same hue and saturation as the brand copper, darkened until small text
     clears WCAG AA on white (5.02:1) and on the soft grey (4.68:1).
     #cd9483 itself only reaches 2.57:1, so it is used for rules, icons and
     other decoration — never for running text on a light surface. */
  --v-copper-ink: #a75a43;
  --v-text: #282726;          /* e-global-color-text      */
  --v-ink: #111111;

  /* Derived tones (tints/shades of the brand navy — no new hues) */
  --v-navy-deep: #0d1c3a;
  --v-navy-soft: #1b3260;
  --v-navy-06: rgba(19, 39, 80, 0.06);
  --v-navy-12: rgba(19, 39, 80, 0.12);
  --v-copper-14: rgba(205, 148, 131, 0.14);

  /* Light blue accent — new, not one of the original Elementor globals (that
     slot is --v-accent above, a dark navy-blue, rarely used). Added as a
     third rotating colour alongside navy/copper wherever those two already
     repeat across a row of items (stats, strip icons, mission/vision,
     affiliates) rather than replacing either of them. 3.45:1 on white (clears
     WCAG AA for the large/bold stat numbers it's used on) and 4.24:1 on navy. */
  --v-sky: #4f8fc7;
  /* Same hue, darkened just enough that white text on a *solid* fill of it
     clears WCAG AA at small sizes (4.61:1). --v-sky itself only reaches
     3.45:1, so it stays for tints, borders and icons — never a solid
     background behind small white text. */
  --v-sky-deep: #4079ad;
  /* Opaque equivalent of the sky tint the three strip cards render as
     (rgba(79,143,199,0.18) composited over the navy panel). Used wherever a
     card needs that same light-blue face but must NOT let a photograph show
     through it. Text on it: white 11.4:1, 85% white 8.7:1, copper 4.4:1. */
  --v-sky-card: #1e3a65;
  --v-sky-card-hover: #244471;
  /* The pale icon-badge fill, shared by every icon badge on the page (strip,
     services, mission/vision) so they read as one component. Solid rather
     than a tint: as a tint it would compose differently on the white section
     vs the navy panel vs a photograph. This is the exact colour the original
     mission/vision tint rendered as over white. --v-sky-deep is the matching
     glyph colour on it (4.1:1); plain --v-sky only reaches 3.05:1. */
  --v-sky-soft: #eaf2f8;

  --v-white: #ffffff;
  --v-surface: #ffffff;
  --v-surface-soft: #f6f7f9;
  --v-surface-tint: #eef0f4;
  --v-line: #e4e7ec;
  --v-line-dark: rgba(255, 255, 255, 0.14);
  --v-muted: #6b7280;
  --v-muted-dark: #d8d8d8;

  /* --- Typography (unchanged families + sizes from the live site) --- */
  --v-font-head: "Montserrat", "Helvetica Neue", Arial, sans-serif;
  --v-font-body: "Inter", "Helvetica Neue", Arial, sans-serif;

  --v-fs-h1: clamp(28px, 4.4vw, 40px);   /* live H1 = 40px  */
  --v-fs-h2: clamp(21px, 2.9vw, 27px);   /* live H2 = 27px  */
  --v-fs-h3: clamp(19px, 2.2vw, 22px);   /* live H3 = 22px  */
  --v-fs-h4: 18px;
  --v-fs-card: 16px;                     /* live card title */
  --v-fs-body: 15px;                     /* live body       */
  --v-fs-sm: 13px;                       /* live button     */
  --v-fs-xs: 11px;
  --v-fs-stat: clamp(26px, 3.4vw, 34px); /* live counter    */
  --v-fs-rating: clamp(30px, 4vw, 40px);

  --v-lh-tight: 1.2;
  --v-lh-head: 1.4;
  --v-lh-body: 1.7;

  /* --- Rhythm --- */
  --v-container: 1340px;
  --v-gutter: 0px;
  --v-section: clamp(56px, 7vw, 96px);
  --v-radius: 8px;
  --v-radius-lg: 8px;
  --v-radius-pill: 300px;

  --v-shadow-sm: 0 2px 10px rgba(19, 39, 80, 0.06);
  --v-shadow-md: 0 14px 40px rgba(19, 39, 80, 0.10);
  --v-shadow-lg: 0 28px 70px rgba(13, 28, 58, 0.18);

  --v-ease: cubic-bezier(0.22, 0.61, 0.36, 1);

  color: var(--v-text);
  font-family: var(--v-font-body);
  font-size: var(--v-fs-body);
  line-height: var(--v-lh-body);
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}

/* --------------------------------------------------------------------------
   Scoped element normalisation (only inside the wrapper)
   -------------------------------------------------------------------------- */
.valeris-page *,
.valeris-page *::before,
.valeris-page *::after { box-sizing: border-box; }

.valeris-page h1,
.valeris-page h2,
.valeris-page h3,
.valeris-page h4,
.valeris-page h5,
.valeris-page h6 {
  font-family: var(--v-font-head);
  font-weight: 600;
  color: var(--v-navy);
  margin: 0;
  line-height: var(--v-lh-tight);
  text-wrap: balance;
}

.valeris-page h1 { font-size: var(--v-fs-h1); }
.valeris-page h2 { font-size: var(--v-fs-h2); }
.valeris-page h3 { font-size: var(--v-fs-h3); line-height: var(--v-lh-head); }
.valeris-page h4 { font-size: var(--v-fs-h4); line-height: var(--v-lh-head); }

.valeris-page p { margin: 0; }
.valeris-page p + p { margin-top: 14px; }
.valeris-page ul { margin: 0; padding: 0; list-style: none; }
/* figure/blockquote carry a 40px UA margin that silently breaks flex tracks */
.valeris-page figure,
.valeris-page blockquote,
.valeris-page figcaption { margin: 0; }
.valeris-page button { font: inherit; }
.valeris-page img { max-width: 100%; height: auto; display: block; }
.valeris-page a { color: inherit; text-decoration: none; }

.valeris-page :focus-visible {
  outline: 2px solid var(--v-copper);
  outline-offset: 3px;
  border-radius: 4px;
}
.valeris-page .v-on-dark :focus-visible { outline-color: #f0c9bd; }


/* --------------------------------------------------------------------------
   Layout primitives
   -------------------------------------------------------------------------- */
.valeris-page .v-container {
  width: 100%;
  max-width: var(--v-container);
  margin-inline: auto;
  padding-inline: var(--v-gutter);
}

.valeris-page .v-section { padding-block: var(--v-section); }
.valeris-page .v-section--soft { background: var(--v-surface-soft); }
.valeris-page .v-section--tight { padding-block: clamp(40px, 5vw, 68px); }

.valeris-page .v-on-dark,
.valeris-page .v-on-dark h1,
.valeris-page .v-on-dark h2,
.valeris-page .v-on-dark h3,
.valeris-page .v-on-dark h4 { color: #fff; }
.valeris-page .v-on-dark p { color: rgba(255, 255, 255, 0.78); }

/* Eyebrow: small uppercase label with a short copper rule (editorial, not a pill) */
.valeris-page .v-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--v-font-head);
  font-size: var(--v-fs-xs);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--v-copper-ink);
  margin-bottom: 16px;
}
.valeris-page .v-eyebrow::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--v-copper);
  flex: none;
}
/* The hero is not tagged .v-on-dark (its copy uses its own scale), but its
   eyebrow still sits on the dark scrim and needs the light copper. */
.valeris-page .v-on-dark .v-eyebrow,
.valeris-page .v-hero .v-eyebrow { color: #e2b8a9; }
.valeris-page .v-on-dark .v-eyebrow::before,
.valeris-page .v-hero .v-eyebrow::before { background: #e2b8a9; }

/* Pill variant — the bordered capsule label used in the reference banner.
   Same type scale and copper dot as the editorial eyebrow; only the chrome
   around it changes, so the two stay recognisably one component. */
.valeris-page .v-lede {
  color: var(--v-muted);
  max-width: 62ch;
}
.valeris-page .v-on-dark .v-lede { color: rgba(255, 255, 255, 0.75); }

/* --------------------------------------------------------------------------
   Buttons — existing pill style preserved (Montserrat 13px / radius 300px)
   -------------------------------------------------------------------------- */
.valeris-page .v-btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--v-font-head);
  font-size: var(--v-fs-sm);
  font-weight: 500;
  line-height: 1.3;
  padding: 13px 26px;
  border-radius: var(--v-radius-pill);
  border: 1px solid transparent;
  cursor: pointer;
  transition: background-color 0.25s var(--v-ease), color 0.25s var(--v-ease),
              border-color 0.25s var(--v-ease), transform 0.25s var(--v-ease);
  white-space: nowrap;
}
.valeris-page .v-btn i { font-size: 1.05em; line-height: 1; }
.valeris-page .v-btn:hover { transform: translateY(-2px); }

.valeris-page .v-btn--primary { background: var(--v-navy); color: #fff; }
.valeris-page .v-btn--primary:hover { background: var(--v-accent); }

.valeris-page .v-btn--light { background: #fff; color: var(--v-navy); }
.valeris-page .v-btn--light:hover { background: var(--v-surface-tint); }

/* Light-blue accent button. Uses --v-sky-deep, not --v-sky: this is a solid
   fill behind small white label text, so it needs the AA-passing tone. */
.valeris-page .v-btn--sky { background: var(--v-sky-deep); color: #fff; }
.valeris-page .v-btn--sky:hover { background: var(--v-sky); }

/* Inline text link with arrow */
.valeris-page .v-link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--v-font-head);
  font-size: var(--v-fs-sm);
  font-weight: 600;
  color: var(--v-navy);
}
.valeris-page .v-link i { transition: transform 0.25s var(--v-ease); }
.valeris-page .v-link:hover i { transform: translateX(4px); }
.valeris-page .v-on-dark .v-link { color: #fff; }

/* ==========================================================================
   HERO — the one and only hero. Existing Valeris banner, improved.
   The theme's own header sits above this block, so there is no negative
   offset here: the hero simply starts where the theme header ends.
   ========================================================================== */
.valeris-page .v-hero {
  position: relative;
  isolation: isolate;
  /* Fixed px rather than a vh clamp, so the banner is the same height on every
     machine instead of shrinking on short laptop windows and stretching on tall
     ones. 860px is where the old clamp topped out, and it is below the height
     the content itself demands at every breakpoint we render (932px at
     1280×720, taller as the columns stack), so this is a floor that never
     introduces dead space — it only stops the box collapsing if the copy is
     ever shortened. */
  min-height: 860px;
  display: flex;
  align-items: center;
  padding-top: clamp(140px, 14vw, 190px);
  /* Deliberately larger than the fade band below, so the copy always ends
     above the gradient. A percentage-based fade could not guarantee this —
     the copy column is much taller on narrow screens, and white text would
     have ended up sitting on the lightened part of the fade. */
  padding-bottom: clamp(150px, 18vw, 250px);
  background: var(--v-navy-deep);
  overflow: hidden;
}

/* The hero dissolves into the light band underneath instead of ending on a
   hard horizontal edge. Anchored to the bottom in px (not %) so the band is
   the same height at every breakpoint, and sized under the hero's own
   padding-bottom so it never reaches the copy. Sits above .v-hero__scrim
   (later in paint order at the same z-index) but below the content.

   Resolves to --v-surface-tint, NOT white: `.v-strip` continues the same
   gradient from that tint down to white, so the two read as one fade. */
.valeris-page .v-hero::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: -1;
  height: clamp(130px, 15vw, 210px);
  pointer-events: none;
  background: linear-gradient(180deg,
    rgba(238, 240, 244, 0) 0%,
    rgba(238, 240, 244, 0.06) 30%,
    rgba(238, 240, 244, 0.22) 52%,
    rgba(238, 240, 244, 0.55) 74%,
    rgba(238, 240, 244, 0.85) 90%,
    var(--v-surface-tint) 100%);
}

.valeris-page .v-hero__media { position: absolute; inset: 0; z-index: -2; }
.valeris-page .v-hero__slide {
  position: absolute;
  inset: 0;
  background-size: cover;
  /* 25% across, not `center`. The banner is 16:9 but the hero box never is —
     it runs from ~0.35 aspect on a phone to ~2.4 on an ultrawide — so `cover`
     crops hard and *which* part survives decides whether the copy is readable.
     Centred, a phone keeps only the middle ~20% of the frame, which is the lit
     tower core (pixels up to 255,254,235) directly under the body copy: about
     1.7:1 against white, and no amount of scrim fixes it without turning the
     whole banner to mud. 25% slides that window onto the artwork's dark
     left-hand side instead. Verified across every real layout this page
     produces — 375px, 900px, 1100px and desktop aspects 1.35 through 2.4 —
     with the worst glyph in each at 5.4:1 or better. */
  background-position: 25% center;
  opacity: 0;
  transition: opacity 1.4s var(--v-ease);
}
.valeris-page .v-hero__slide.is-active { opacity: 1; }

/* The two banner URLs, each behind a media query so only the one in use is ever
   downloaded. The queries are complementary, so exactly one always applies.

   Paths are relative to this stylesheet (`assets/css/`), which is why they climb
   one level. That resolves correctly both for the static build and inside the
   WordPress plugin, where the CSS sits at the same depth — no rewriting needed,
   unlike the `assets/`-prefixed URLs in the template. */
@media (min-width: 769px) {
  .valeris-page .v-hero__slide { background-image: url('../img/hero-banner.webp'); }
}
@media (max-width: 768px) {
  .valeris-page .v-hero__portrait { background-image: url('../img/mobile-ver-hero-banner.webp'); }
}

/* Portrait banner, swapped in below 768px (see the breakpoint at the foot of this
   file). Hidden rather than absent so the landscape crop stays the default and
   this is purely additive.

   `center` is correct here where the landscape crop needed 25%: this artwork is a
   full-frame composition with no dark side to aim at, so every horizontal position
   measures the same. That is also why it needs the overlay the landscape one does
   not — see the breakpoint rule. */
.valeris-page .v-hero__portrait {
  display: none;
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
}

/* No overlay by default. The landscape banner is shown at its own colour and
   contrast.

   This is only safe because of what that artwork is: its left half is near-black
   by design (mean RGB around 12,20,35), so the headline, body copy and rating
   block measure 10:1 to 18:1 against the bare image — the scrim they used to sit
   under was adding nothing they needed.

   The element is kept rather than deleted because the portrait banner below 768px
   genuinely does need it, and because a future lighter banner would too. */
.valeris-page .v-hero__scrim {
  position: absolute;
  inset: 0;
  z-index: -1;
}

/* The ticked list was removed outright. What is left — the team avatars and
   the counter, grouped in .v-hero__side — needs to clear the copy column
   entirely rather than sit beside the rating as one cluttered cluster, so
   .v-hero__side is a flex sibling of .v-hero__inner, pushed to the far right
   of the hero rather than the right edge of the 660px text measure.
   align-items: flex-end keeps it near the rating/dots at the foot of the
   column instead of centering against the much taller copy block above. */
.valeris-page .v-hero__grid {
  position: relative;
  width: 100%;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: clamp(24px, 4vw, 56px);
}

.valeris-page .v-hero__inner { position: relative; max-width: 660px; }

/* --------------------------------------------------------------------------
   Hero scroll effect — the photograph softens and the copy drifts upward as
   the hero leaves the viewport.

   Driven by a scroll-driven animation rather than a scroll listener: the
   timeline is handled by the compositor, so there is no scroll handler, no
   layout thrash and no JavaScript involved at all. Browsers without
   `animation-timeline` simply render the hero as a normal static banner —
   nothing is hidden and nothing needs a fallback.

   The timeline is *named* rather than an anonymous `view()`. An anonymous one
   resolves against the nearest ancestor scroll container, and `.v-hero` has
   `overflow: hidden` — which counts as one — so descendants would measure
   themselves against a box that never scrolls. Naming it on `.v-hero` itself
   measures the hero against the page, which is what we want.

   The `exit` range runs from "hero top meets viewport top" (scroll position 0,
   since the hero opens the page) to "hero bottom meets viewport top". The blur
   is mapped to the first part of that range and the text lift starts slightly
   later, so the background softens first and the copy follows.
   -------------------------------------------------------------------------- */
@keyframes v-hero-soften {
  from { filter: blur(0px);  transform: scale(1); }
  to   { filter: blur(14px); transform: scale(1.08); }
}

@keyframes v-hero-lift {
  from { transform: translateY(0);     opacity: 1; }
  to   { transform: translateY(-64px); opacity: 0; }
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .valeris-page .v-hero {
      view-timeline-name: --v-hero-view;
      view-timeline-axis: block;
    }

    /* Longhands on purpose: the `animation` shorthand resets duration to 0s,
       and a scroll-driven animation needs `auto` for the timeline to drive it. */
    .valeris-page .v-hero__media {
      /* The scale keeps the blurred edges outside the hero's clip box, so the
         softening never reveals a translucent seam at the sides. */
      animation-name: v-hero-soften;
      animation-duration: auto;
      animation-timing-function: linear;
      animation-fill-mode: both;
      animation-timeline: --v-hero-view;
      animation-range: exit 0% exit 42%;
    }

    /* Only the grid is listed. Anything inside it must NOT be given its own
       lift as well — it would inherit the parent's and add its own on top,
       moving at double speed. */
    .valeris-page .v-hero__grid {
      animation-name: v-hero-lift;
      animation-duration: auto;
      animation-timing-function: linear;
      animation-fill-mode: both;
      animation-timeline: --v-hero-view;
      animation-range: exit 10% exit 62%;
    }
  }
}
/* Scoped override, not a change to the shared --v-fs-h1 token: at that token's
   40px ceiling, "Empowering Real Estate Agencies" (36px measured) does not fit
   the 660px column and wraps to a 3rd line on its own, ahead of the deliberate
   <br> before "to Grow, Perform & Lead" — so the copy renders as three lines
   instead of the intended two. 36px is the largest size where the longer first
   line still fits with margin (636px measured, ~24px to spare); other headings
   using --v-fs-h1 are unaffected. */
.valeris-page .v-hero h1 {
  color: #fff;
  margin-bottom: 18px;
  text-shadow: 0 2px 24px rgba(13, 28, 58, 0.35);
  font-size: clamp(26px, 3.9vw, 36px);
}
.valeris-page .v-hero__text {
  color: rgba(255, 255, 255, 0.86);
  max-width: 52ch;
  margin-bottom: 30px;
}
.valeris-page .v-hero__actions { display: flex; flex-wrap: wrap; gap: 12px; }

/* Rating block — stars + scale on the first line, score + label beneath. */
.valeris-page .v-hero__rating {
  margin-top: clamp(30px, 4vw, 48px);
  padding-top: 24px;
  border-top: 1px solid rgba(255, 255, 255, 0.18);
  max-width: 430px;
}
.valeris-page .v-hero__ratinghead {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 8px;
}
.valeris-page .v-hero__ratingscale {
  font-family: var(--v-font-head);
  font-size: var(--v-fs-xs);
  font-weight: 500;
  color: rgba(255, 255, 255, 0.7);
}
.valeris-page .v-hero__ratingmain {
  display: flex;
  align-items: center;
  gap: 16px;
}
.valeris-page .v-hero__score {
  font-family: var(--v-font-head);
  font-size: var(--v-fs-rating);
  font-weight: 600;
  color: #fff;
  line-height: 1;
  /* Reserve width so the count-up cannot shift the layout */
  min-width: 2.6ch;
  font-variant-numeric: tabular-nums;
}
/* No bottom margin: the wrapping .v-hero__ratinghead owns that spacing now. */
.valeris-page .v-hero__stars { display: flex; gap: 4px; color: var(--v-copper); font-size: 13px; }
.valeris-page .v-hero__ratinglabel {
  font-family: var(--v-font-head);
  font-size: var(--v-fs-sm);
  font-weight: 500;
  color: rgba(255, 255, 255, 0.82);
  line-height: 1.45;
}

/* Team avatars + counter card, clustered together and pushed to the far
   right of the hero as one group (see .v-hero__grid's space-between). */
.valeris-page .v-hero__side {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: clamp(20px, 3vw, 36px);
}

.valeris-page .v-hero__team {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
}
/* The one label that cannot rely on the banner behind it. Every other piece of
   hero copy sits over the artwork's dark left side; this one sits out over the lit
   towers, where the pixels run to 255,254,207 — 1.0:1 against white, and the exact
   colour changes with every crop, so no fixed local scrim reliably catches it.
   Full white plus a tight shadow rather than a patch of navy over the image, which
   is what the rest of this hero is deliberately no longer doing. Note this is a
   legibility fix, not a measured contrast ratio: a shadow does not count towards
   WCAG the way a solid backing would. */
.valeris-page .v-hero__teamlabel {
  font-family: var(--v-font-head);
  font-size: var(--v-fs-sm);
  font-weight: 600;
  color: #fff;
  text-shadow: 0 1px 3px rgba(13, 28, 58, 0.95), 0 0 14px rgba(13, 28, 58, 0.8);
}
.valeris-page .v-hero__avatars { display: flex; align-items: center; }
/* Overlapping circles: a solid white ring separates each photo from the one
   behind it, since the photos themselves have no consistent edge colour to
   rely on. */
.valeris-page .v-hero__avatar {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  object-fit: cover;
  border: 2px solid #fff;
  margin-left: -12px;
}
.valeris-page .v-hero__avatar:first-child { margin-left: 0; }
.valeris-page .v-hero__avatar--more {
  display: grid;
  place-items: center;
  background: var(--v-copper);
  color: var(--v-navy);
  font-size: 13px;
}

/* Glass counter card — sits directly on the hero photo (no longer inside its
   own column), so a solid fill would compete with what's beside it. Same
   treatment as the contact-CTA cards (.v-cta__contact): navy-tinted glass,
   not white, so it reads as one "glass chip" family used across the page. */
.valeris-page .v-hero__stat {
  padding: clamp(14px, 1.8vw, 20px) clamp(20px, 2.4vw, 30px);
  border-radius: var(--v-radius-lg);
  /* Same blue as the "Contact Us" button beside it, so the two read as one
     accent. Opaque, so no backdrop-filter is needed. Borderless like the
     button; the shadow alone lifts it off the photograph. */
  background: var(--v-sky-deep);
  box-shadow: 0 14px 40px rgba(13, 28, 58, 0.18);
  text-align: center;
  min-width: 190px;
}
/* White, not copper. Copper on this blue is 1.79:1 — the number was
   effectively unreadable on it. White matches the button's own white-on-blue
   treatment and clears 4.6:1. */
.valeris-page .v-hero__statvalue {
  display: block;
  font-family: var(--v-font-head);
  font-size: var(--v-fs-stat);
  font-weight: 600;
  line-height: 1.1;
  color: #fff;
}
/* Full white rather than 85%: at 85% this 13px label drops to 3.8:1 on the
   blue, under the 4.5:1 floor for small text. */
.valeris-page .v-hero__statlabel {
  display: block;
  margin-top: 4px;
  font-family: var(--v-font-head);
  font-size: var(--v-fs-sm);
  font-weight: 500;
  line-height: 1.4;
  color: #fff;
}

/* The slide indicators are gone with the rotation — the banner is a single
   fixed image, so a dot row would be three controls that do nothing. The JS
   still queries them and simply finds none, which is why heroSlides() bails on
   `slides.length < 2` rather than needing to be removed. */

/* ==========================================================================
   SECTION 1 — Floating services / support strip
   ========================================================================== */
/* No white card, no inset: the strip runs full-bleed and its cards sit straight
   on the page, so the hero's fade can continue behind them. It is pulled up by
   --v-strip-overlap so the cards rise into the bottom of that fade instead of
   starting cleanly below it.

   The gradient is a two-part continuation of `.v-hero::after`: the hero fades
   from its photograph down to --v-surface-tint at its own bottom edge, and this
   block picks that exact tint up and resolves it to white. Both halves must
   end/start on the same colour or a visible band appears at the seam — which is
   why the overlapping strip is held fully transparent for exactly the overlap
   distance, then switches to the tint at the hero's own bottom edge. Filling
   that region with the tint instead would lay opaque colour over a fade that is
   still part-transparent there, cutting a hard horizontal line across the
   photograph. As written, the overlap shows the hero's fade untouched.

   Sits above the hero without a z-index: it is the later sibling, and
   `.v-hero::after`'s -1 is scoped inside the hero's own stacking context. */
.valeris-page .v-strip {
  --v-strip-overlap: clamp(80px, 9.7vw, 140px);
  position: relative;
  margin: calc(-1 * var(--v-strip-overlap)) 0 0;
  background: linear-gradient(180deg,
    rgba(238, 240, 244, 0) 0,
    rgba(238, 240, 244, 0) var(--v-strip-overlap),
    var(--v-surface-tint) var(--v-strip-overlap),
    #fff 82%);
  padding: clamp(30px, 4vw, 56px) 0 clamp(30px, 4vw, 52px);
}

.valeris-page .v-strip__grid {
  display: grid;
  grid-template-columns: minmax(0, 0.82fr) minmax(0, 2fr);
  gap: 18px;
  align-items: stretch;
}

.valeris-page .v-strip__figure {
  position: relative;
  border-radius: var(--v-radius-lg);
  overflow: hidden;
  min-height: 250px;
  box-shadow: var(--v-shadow-md);
}
.valeris-page .v-strip__figure img { width: 100%; height: 100%; object-fit: cover; position: absolute; inset: 0; }
.valeris-page .v-strip__figcap {
  position: relative;
  z-index: 1;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 8px;
  padding: 24px;
  background: linear-gradient(180deg, rgba(13, 28, 58, 0) 40%, rgba(13, 28, 58, 0.86) 100%);
  color: #fff;
}
.valeris-page .v-strip__figcap h2 { color: #fff; font-size: var(--v-fs-card); }
.valeris-page .v-strip__figcap .v-link { color: #fff; }
.valeris-page .v-strip__figure:hover .v-link i { transform: translateX(4px); }

.valeris-page .v-strip__panel {
  background: var(--v-navy);
  border-radius: var(--v-radius-lg);
  padding: clamp(26px, 3vw, 40px);
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(20px, 2.6vw, 38px);
  box-shadow: var(--v-shadow-lg);
}
/* Each item is now its own light-blue card sitting on the navy panel. The
   panel's own navy is untouched — only the three cards inside it are tinted.
   A translucent tint rather than a solid fill: the copy inside is white and
   70%-white, which needs a dark ground to stay legible (white clears 11:1 on
   this composite; a solid light blue would drop it to ~3.4:1).
   The vertical divider that used to sit in the grid gap is gone — the cards
   have their own edges now, so a rule between them would read as clutter. */
.valeris-page .v-strip__item {
  position: relative;
  padding: clamp(20px, 2.2vw, 26px);
  border-radius: var(--v-radius);
  background: rgba(79, 143, 199, 0.18);
  border: 1px solid rgba(79, 143, 199, 0.28);
}
/* Icon glyph stays copper on all three, unchanged — only the badge behind it
   picks up the new light-blue accent, on all three alike (no rotation). */
.valeris-page .v-strip__icon {
  width: 46px;
  height: 46px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--v-sky-soft);
  color: var(--v-sky-deep);
  font-size: 20px;
  margin-bottom: 16px;
}
.valeris-page .v-strip__item h3 { color: #fff; font-size: var(--v-fs-card); margin-bottom: 8px; }
/* Reserve two title lines in the 3-up layout so the descriptions below
   share a baseline even when one title wraps and another doesn't. */
@media (min-width: 769px) {
  .valeris-page .v-strip__item h3 { min-height: calc(2 * var(--v-lh-head) * 1em); }
}
.valeris-page .v-strip__item p { color: rgba(255, 255, 255, 0.7); font-size: 14px; line-height: 1.6; }

/* ==========================================================================
   SECTION 2 — About (editorial two-column)
   ========================================================================== */
.valeris-page .v-about__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.12fr);
  gap: clamp(32px, 5vw, 68px);
  align-items: center;
}
.valeris-page .v-about__media { position: relative; }
.valeris-page .v-about__media img {
  width: 100%;
  border-radius: var(--v-radius-lg);
  aspect-ratio: 4 / 5;
  object-fit: cover;
  box-shadow: var(--v-shadow-md);
}

/* Two-column layout: the photo takes its height from the text column rather
   than a fixed aspect ratio, so the two sides always end level. Taking the
   image out of flow leaves the text as the only in-flow content, so it alone
   sets the row height; the stretched media column then fills it. A fixed
   ratio can't do this — it would need re-tuning every time the copy changes. */
@media (min-width: 993px) {
  .valeris-page .v-about__grid { align-items: stretch; }
  /* Floor for short copy, so the photo can never collapse to a thin band. */
  .valeris-page .v-about__media { min-height: 420px; }
  .valeris-page .v-about__media img {
    position: absolute;
    inset: 0;
    height: 100%;
    aspect-ratio: auto;
  }
}
/* Small credential card, inset in the photo's top-left corner. Insets are
   positive on purpose: it used to sit bottom-right with a negative `right`,
   which pushed it outside the photo column and over the text beside it. */
.valeris-page .v-about__badge {
  position: absolute;
  top: clamp(16px, 2vw, 28px);
  left: clamp(16px, 2vw, 28px);
  background: #fff;
  border: 1px solid var(--v-line);
  border-radius: var(--v-radius);
  box-shadow: var(--v-shadow-md);
  padding: 18px 22px;
  max-width: 232px;
}
.valeris-page .v-about__badge strong {
  display: block;
  font-family: var(--v-font-head);
  font-size: var(--v-fs-card);
  color: var(--v-navy);
  margin-bottom: 4px;
}
.valeris-page .v-about__badge span { font-size: 13px; color: var(--v-muted); line-height: 1.5; display: block; }

/* Sits directly under the h2 now, so it carries its own top margin. */
.valeris-page .v-about__body { color: var(--v-muted); margin: 16px 0 30px; }

.valeris-page .v-mv { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 22px; margin-bottom: 30px; }
.valeris-page .v-mv__item { padding-top: 20px; border-top: 2px solid var(--v-navy-12); }
/* Circular pale badge — the shared icon-badge treatment (see --v-sky-soft).
   Unchanged visually: the tint this used to carry rendered as exactly that
   colour over the white section; it now names the shared token instead so
   all three badge groups stay in step. */
.valeris-page .v-mv__item i {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--v-sky-soft);
  color: var(--v-sky-deep);
  font-size: 20px;
  margin-bottom: 12px;
}
.valeris-page .v-mv__item h3 { font-size: var(--v-fs-card); margin-bottom: 8px; }
.valeris-page .v-mv__item p { color: var(--v-muted); font-size: 14px; line-height: 1.65; }

/* Highlight CTA panel */
.valeris-page .v-highlight {
  display: flex;
  align-items: center;
  gap: 20px;
  flex-wrap: wrap;
  justify-content: space-between;
  background: var(--v-navy);
  border-radius: var(--v-radius-pill);
  padding: 14px 14px 14px 28px;
}
.valeris-page .v-highlight p { color: rgba(255, 255, 255, 0.88); font-size: 14px; max-width: 46ch; }
.valeris-page .v-highlight i { color: var(--v-copper); margin-right: 8px; }

/* ==========================================================================
   SECTION 3 — Statistics row
   ========================================================================== */
.valeris-page .v-stats { background: var(--v-surface-soft); }
.valeris-page .v-stats__grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(22px, 3vw, 44px);
}
/* Each column is its own solid colour — navy, copper, navy, copper — rather
   than mixing both hues inside a single number. The top rule already
   alternated this way; the number itself now follows it instead of always
   being navy with a copper suffix, so the colour reads as "this stat" rather
   than "this stat has two colours". */
.valeris-page .v-stat { padding-top: 22px; border-top: 2px solid var(--v-navy); }
.valeris-page .v-stat:nth-child(even) { border-top-color: var(--v-copper); }
.valeris-page .v-stat__value {
  font-family: var(--v-font-head);
  font-size: var(--v-fs-stat);
  font-weight: 600;
  color: var(--v-navy);
  line-height: 1.05;
  margin-bottom: 10px;
  font-variant-numeric: tabular-nums;
  /* Value is rendered server-side in the HTML, so there is no reflow on count-up */
}
.valeris-page .v-stat:nth-child(even) .v-stat__value { color: var(--v-copper-ink); }
.valeris-page .v-stat__value .v-stat__suffix { color: inherit; }
.valeris-page .v-stat h3 { font-size: var(--v-fs-card); margin-bottom: 6px; }
.valeris-page .v-stat p { font-size: 13px; color: var(--v-muted); line-height: 1.6; }

/* ==========================================================================
   SECTION 4 — Services introduction
   ========================================================================== */
.valeris-page .v-intro {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  gap: clamp(28px, 5vw, 72px);
  align-items: start;
  margin-bottom: clamp(34px, 4vw, 54px);
}
.valeris-page .v-intro__aside { display: flex; flex-direction: column; align-items: flex-start; gap: 22px; }
.valeris-page .v-intro__aside p { color: var(--v-muted); }

/* ==========================================================================
   SECTION 5 — Services grid
   ========================================================================== */
/* Ported from the client's CardFlip component: same 500ms
   cubic-bezier(0.77,0,0.175,1) rotateY flip, the Repeat2 hint icon with a
   pulsing glow, the copy lift on hover, the staggered feature reveal, and the
   bordered CTA row with a sliding arrow. Recoloured from the reference's
   orange/zinc to the Valeris navy + copper, and kept on the page's 8px radius
   rather than the reference's 16px. */
.valeris-page .v-svc {
  --v-flip-ease: cubic-bezier(0.77, 0, 0.175, 1);
  position: relative;
}

.valeris-page .v-svc__inner {
  position: relative;
  height: 100%;
  border-radius: var(--v-radius);
  overflow: hidden;
}

/* ---- front ------------------------------------------------------------ */
.valeris-page .v-svc__front {
  position: relative;
  isolation: isolate;
  min-height: clamp(430px, 33vw, 480px);
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: 24px;
  color: #fff;
}
.valeris-page .v-svc__front img {
  position: absolute;
  inset: 0;
  z-index: -2;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.valeris-page .v-svc__front::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(180deg, rgba(13, 28, 58, 0.1) 0%, rgba(13, 28, 58, 0.5) 42%, rgba(13, 28, 58, 0.93) 100%);
}

.valeris-page .v-svc__icon {
  position: absolute;
  top: 24px;
  left: 24px;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  /* Same pale circular badge as the mission/vision and strip icons. Opaque,
     so the glyph has one predictable ground on all nine photographs.
     The shadow is not decoration: this badge is pale, and against the lighter
     images in the set it only has ~1.4:1 of its own, so without an edge it
     dissolves into them. The other two badges sit on flat surfaces and need
     no such treatment. */
  background: var(--v-sky-soft);
  box-shadow: 0 2px 12px rgba(13, 28, 58, 0.35);
  color: var(--v-sky-deep);
  font-size: 18px;
}
.valeris-page .v-svc__icon i { line-height: 1; }

.valeris-page .v-svc__frontbar {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 14px;
}
.valeris-page .v-svc__frontcopy { display: grid; gap: 6px; min-width: 0; }
.valeris-page .v-svc__front h3 { color: #fff; font-size: var(--v-fs-card); }
/* line-clamp-2, as in the reference */
.valeris-page .v-svc__subtitle {
  font-size: 14px;
  line-height: 1.55;
  color: rgba(255, 255, 255, 0.78);
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
}

/* Repeat2 hint + the reference's pulsing glow, rebuilt as three staggered
   rings. Infinite, but it sits on the affordance itself rather than being
   loose decoration — it is what tells you the card turns. */
.valeris-page .v-svc__hint {
  position: relative;
  flex: none;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: rgba(13, 28, 58, 0.5);
  border: 1px solid rgba(226, 184, 169, 0.45);
  color: #e2b8a9;
  font-size: 15px;
  transition: transform 0.3s var(--v-ease), background-color 0.3s var(--v-ease);
}
.valeris-page .v-svc__hint i { position: relative; z-index: 1; line-height: 1; }
.valeris-page .v-svc__hint > span {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  opacity: 0;
  box-shadow: 0 0 22px rgba(205, 148, 131, 0.5);
}

@keyframes v-svc-pulse {
  0%   { transform: scale(1.9);              opacity: 0;    box-shadow: 0 0 24px rgba(205, 148, 131, 0.5); }
  50%  { transform: translateY(-3px) scale(1); opacity: 0.8; box-shadow: 0 6px 16px rgba(205, 148, 131, 0.45); }
  100% { transform: translateY(3px) scale(0.2); opacity: 0;  box-shadow: 0 8px 16px rgba(205, 148, 131, 0); }
}

/* ---- back ------------------------------------------------------------- */
.valeris-page .v-svc__back {
  display: flex;
  flex-direction: column;
  padding: 26px 24px;
  /* tonal, single-hue — the brand equivalent of the reference's zinc ramp */
  background: linear-gradient(180deg, var(--v-navy) 0%, var(--v-navy-deep) 100%);
}
/* The reference's flex-1 block. Centred rather than top-aligned: these cards
   are taller than the reference's 320px, and top-aligning left a dead gap
   between the feature list and the footer. */
.valeris-page .v-svc__body {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 22px;
}
.valeris-page .v-svc__backhead { display: grid; gap: 8px; }
.valeris-page .v-svc__backtitle {
  font-family: var(--v-font-head);
  font-weight: 600;
  font-size: var(--v-fs-card);
  line-height: var(--v-lh-head);
  color: #fff;
}
.valeris-page .v-svc__backdesc {
  font-size: 14px;
  line-height: 1.55;
  color: rgba(255, 255, 255, 0.7);
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
}

.valeris-page .v-svc__list { display: grid; gap: 10px; }
.valeris-page .v-svc__list li {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  font-size: 14px;
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.82);
}
.valeris-page .v-svc__list i {
  color: var(--v-copper);
  font-size: 12px;
  line-height: 1;
  margin-top: 5px;
  flex: none;
}

/* the reference's border-top footer with its -m-3 p-3 hover panel */
.valeris-page .v-svc__foot {
  margin-top: auto;
  padding-top: 18px;
  border-top: 1px solid var(--v-line-dark);
}
.valeris-page .v-svc__cta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 0 -12px;
  padding: 10px 12px;
  border-radius: var(--v-radius);
  transition: background-color 0.3s var(--v-ease), transform 0.3s var(--v-ease);
}
.valeris-page .v-svc__cta span {
  font-family: var(--v-font-head);
  font-size: var(--v-fs-sm);
  font-weight: 500;
  color: #fff;
  transition: color 0.3s var(--v-ease);
}
.valeris-page .v-svc__cta i {
  color: var(--v-copper);
  font-size: 15px;
  line-height: 1;
  transition: transform 0.3s var(--v-ease);
}
.valeris-page .v-svc__cta:hover { background: rgba(255, 255, 255, 0.08); }
.valeris-page .v-svc__cta:hover span { color: #f0d3c8; }
.valeris-page .v-svc__cta:hover i { transform: translateX(3px); }
.valeris-page .v-svc__cta:active { transform: scale(0.985); }

/* ---- the flip ---------------------------------------------------------
   Only where there is a real pointer to hover with, and only when motion is
   welcome. Everywhere else the two faces stack into one tall panel, so no
   content sits behind an interaction the device or the user cannot perform.
   ---------------------------------------------------------------------- */
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  .valeris-page .v-svc { perspective: 2000px; }

  .valeris-page .v-svc__inner {
    min-height: clamp(430px, 33vw, 480px);
    border-radius: 0;
    overflow: visible;
    transform-style: preserve-3d;
    transition: transform 0.5s var(--v-flip-ease);
  }
  /* focus-within as well as hover: tabbing to the back's Read More link has
     to bring that face into view. */
  .valeris-page .v-svc:hover .v-svc__inner,
  .valeris-page .v-svc:focus-within .v-svc__inner { transform: rotateY(180deg); }

  .valeris-page .v-svc__front,
  .valeris-page .v-svc__back {
    position: absolute;
    inset: 0;
    border-radius: var(--v-radius);
    overflow: hidden;
    backface-visibility: hidden;
  }
  .valeris-page .v-svc__front { min-height: 0; }
  .valeris-page .v-svc__back { transform: rotateY(180deg); }

  /* copy lift, staggered — reference: -4px front, -2px back */
  .valeris-page .v-svc__front h3,
  .valeris-page .v-svc__subtitle,
  .valeris-page .v-svc__backtitle,
  .valeris-page .v-svc__backdesc { transition: transform 0.5s var(--v-flip-ease); }
  .valeris-page .v-svc__subtitle { transition-delay: 50ms; }
  .valeris-page .v-svc:hover .v-svc__front h3,
  .valeris-page .v-svc:hover .v-svc__subtitle { transform: translateY(-4px); }
  .valeris-page .v-svc:hover .v-svc__backtitle,
  .valeris-page .v-svc:hover .v-svc__backdesc { transform: translateY(-2px); }

  /* features slide in one after another once the card has turned */
  .valeris-page .v-svc__list li {
    opacity: 0;
    transform: translateX(-10px);
    transition: opacity 0.3s cubic-bezier(0.23, 1, 0.32, 1), transform 0.3s cubic-bezier(0.23, 1, 0.32, 1);
  }
  .valeris-page .v-svc:hover .v-svc__list li,
  .valeris-page .v-svc:focus-within .v-svc__list li { opacity: 1; transform: none; }
  .valeris-page .v-svc__list li:nth-child(1) { transition-delay: 150ms; }
  .valeris-page .v-svc__list li:nth-child(2) { transition-delay: 200ms; }
  .valeris-page .v-svc__list li:nth-child(3) { transition-delay: 250ms; }
  .valeris-page .v-svc__list li:nth-child(4) { transition-delay: 300ms; }

  .valeris-page .v-svc__hint > span { animation: v-svc-pulse 3s linear infinite; }
  .valeris-page .v-svc__hint > span:nth-child(2) { animation-delay: 1s; }
  .valeris-page .v-svc__hint > span:nth-child(3) { animation-delay: 2s; }
  .valeris-page .v-svc:hover .v-svc__hint {
    background: rgba(205, 148, 131, 0.42);
    transform: rotate(-12deg) scale(1.1);
  }
  .valeris-page .v-svc:hover .v-svc__hint > span { animation-duration: 1.8s; }
}

/* Where the card does not flip, the hint would be a lie. */
@media not all and (hover: hover) and (pointer: fine) {
  .valeris-page .v-svc__hint { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .valeris-page .v-svc__hint { display: none; }
}

/* ==========================================================================
   Carousel — shared by the services cards and the testimonials
   ========================================================================== */
.valeris-page .v-carousel { --v-carousel-gap: 20px; --v-carousel-per: 3; position: relative; }
.valeris-page .v-quotes { --v-carousel-per: 2; }

.valeris-page .v-carousel__viewport {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: calc((100% - (var(--v-carousel-per) - 1) * var(--v-carousel-gap)) / var(--v-carousel-per));
  gap: var(--v-carousel-gap);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  /* An overflow container clips in both axes, so leave room for card shadows
     and focus rings rather than letting them get sheared off. */
  padding: 6px 0 18px;
  scrollbar-width: none;
}
.valeris-page .v-carousel__viewport::-webkit-scrollbar { display: none; }
.valeris-page .v-carousel__viewport > * { scroll-snap-align: start; }

.valeris-page .v-carousel__nav { display: flex; gap: 10px; margin-top: 8px; }
.valeris-page .v-carousel__btn {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 1px solid var(--v-line);
  background: #fff;
  color: var(--v-navy);
  font-size: 15px;
  cursor: pointer;
  transition: background-color 0.22s var(--v-ease), color 0.22s var(--v-ease), border-color 0.22s var(--v-ease);
}
.valeris-page .v-carousel__btn:hover:not(:disabled) { background: var(--v-navy); color: #fff; border-color: var(--v-navy); }
.valeris-page .v-carousel__btn:disabled { opacity: 0.35; cursor: default; }

/* ==========================================================================
   CEO / leadership
   ========================================================================== */
/* Centred leadership composition with a desktop title anchored top-left. */
.valeris-page .v-lead {
  background: var(--v-navy-deep);
  overflow: hidden;
  /* No bottom padding: the cutout stands flush on the section's lower edge. */
  padding-bottom: 0;
}

.valeris-page .v-lead__grid {
  display: grid;
  gap: clamp(28px, 4vw, 68px);
  align-items: center;
}

/* --- content column ---------------------------------------------------- */
.valeris-page .v-lead__ident {
  margin-bottom: clamp(18px, 2vw, 24px);
  padding-bottom: clamp(16px, 1.8vw, 22px);
  border-bottom: 1px solid var(--v-line-dark);
}
/* h3-sized before — but the section's real <h2> is screen-reader-only (see
   the leadership-section note in index.html), so visually this name is the
   section's title. Sized to match every other section's h2 rather than one
   size down from them. */
.valeris-page .v-lead__name {
  font-family: var(--v-font-head);
  font-size: var(--v-fs-h2);
  font-weight: 600;
  line-height: var(--v-lh-head);
  color: #fff;
}
.valeris-page .v-lead__role {
  margin-top: 2px;
  font-size: 13px;
  letter-spacing: 0.02em;
  /* Lighter copper: the base #cd9483 is fine on this dark ground, but this
     tone matches the eyebrow already used on dark surfaces (9.37:1). */
  color: #e2b8a9;
}

.valeris-page .v-lead__prose p + p { margin-top: 14px; }

.valeris-page .v-lead__facts {
  display: grid;
  gap: 16px;
  margin-top: clamp(24px, 3vw, 34px);
}

/* --- fact cards -------------------------------------------------------- */
.valeris-page .v-lead__card {
  display: flex;
  flex-direction: column;
  gap: 12px;
  /* Width comes from the grid track now, not a clamp — these sit inside the
     content column rather than floating over the portrait. */
  padding: 20px 22px;
  border-radius: var(--v-radius);
  /* Same opaque light-blue face as the three strip cards and .v-hero__stat.
     Opaque, so the blur it used to carry is gone — nothing shows through. */
  background: var(--v-sky-card);
  border: 1px solid rgba(79, 143, 199, 0.28);
  box-shadow: 0 14px 34px rgba(0, 0, 0, 0.28);
  font-size: 13px;
  line-height: 1.5;
  transition: transform 0.3s var(--v-ease), box-shadow 0.3s var(--v-ease),
              background-color 0.3s var(--v-ease), border-color 0.3s var(--v-ease);
}
/* .v-on-dark on the section would otherwise bleach the card copy */
.valeris-page .v-lead__card p { color: rgba(255, 255, 255, 0.82); }
.valeris-page .v-lead__card:hover {
  transform: translateY(-4px);
  background: var(--v-sky-card-hover);
  border-color: rgba(79, 143, 199, 0.45);
  box-shadow: 0 22px 46px rgba(0, 0, 0, 0.36);
}

/* Both cards share one pill treatment: a *solid* light-blue chip (no longer
   translucent). --v-sky-deep rather than --v-sky, because white 12px label
   text on a solid fill needs the AA-passing tone. */
.valeris-page .v-lead__pills { display: flex; flex-wrap: wrap; gap: 6px; }
.valeris-page .v-lead__pill {
  font-family: var(--v-font-head);
  font-size: 12px;
  font-weight: 500;
  padding: 5px 12px;
  border-radius: var(--v-radius-pill);
  background: var(--v-sky-deep);
  color: #fff;
}

/* --- portrait column --------------------------------------------------- */
.valeris-page .v-lead__portrait {
  position: relative;
  align-self: end;
  isolation: isolate;
  width: 100%;
  max-width: 560px;
  margin-inline: auto;
}
.valeris-page .v-lead__portrait img { width: 100%; height: auto; }
/* Trims the empty base of the cutout so he stands on the section edge. */
.valeris-page .v-lead__portrait-crop {
  display: block;
  aspect-ratio: 0.88 / 1;
  overflow: hidden;
}

/* --- scroll parallax on the photo ---------------------------------------
   The crop box (not the outer .v-lead__portrait figure) carries this, on
   purpose: .v-lead__portrait already owns a `transition` on `transform` for
   its one-time scroll-reveal entrance (see .v-reveal below). A scroll-driven
   `animation` on that same property, on the same element, would fight the
   transition for control of `transform` and jump/jank on scroll. Putting the
   two on separate elements lets the entrance and the ongoing parallax run
   independently. `.v-lead`'s own `overflow: hidden` safely clips the small
   drift at the section's edges. */
@keyframes v-lead-photo-drift {
  from { transform: translateY(-14px); }
  to   { transform: translateY(14px); }
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .valeris-page .v-lead {
      view-timeline-name: --v-lead-view;
      view-timeline-axis: block;
    }
    .valeris-page .v-lead__portrait-crop {
      animation-name: v-lead-photo-drift;
      animation-duration: auto;
      animation-timing-function: linear;
      animation-fill-mode: both;
      animation-timeline: --v-lead-view;
      animation-range: cover 0% cover 100%;
    }
  }
}

/* A soft, formless wash of light — deliberately not a circle/ring and
   navy-only (no copper), so it reads as ambient depth rather than a shape
   sitting behind him. Two irregular, off-round blobs (organic border-radius,
   not 50%) drift and slowly reshape so nothing ever reads as a drawn outline. */
.valeris-page .v-lead__halo {
  position: absolute;
  z-index: -1;
  bottom: -6%;
  /* 61.5%, not 50%: the cutout frames him right of centre (measured centroid
     of its opaque pixels), so centring the halo on the *element* left it
     visibly offset from his *body*. */
  left: 61.5%;
  translate: -50% 0;
  width: min(150%, 820px);
  /* Squashed rather than 1:1 — tall enough to glow past his shoulders,
     short enough that it never climbs into the fact cards stacked above
     it on narrower layouts. */
  aspect-ratio: 4 / 3;
  border-radius: 42% 58% 63% 37% / 47% 41% 59% 53%;
  background: radial-gradient(ellipse at 50% 40%,
    rgba(43, 66, 112, 0.50) 0%,
    rgba(27, 50, 96, 0.30) 34%,
    rgba(13, 28, 58, 0.16) 58%,
    rgba(13, 28, 58, 0) 78%);
  filter: blur(2px);
  transform-origin: center bottom;
}

/* A second, smaller wash offset toward his shoulder — gives the light a
   source rather than one flat glow centred behind him. */
.valeris-page .v-lead__halo::before {
  content: "";
  position: absolute;
  inset: 12% 6% auto 22%;
  height: 55%;
  border-radius: 55% 45% 48% 52% / 52% 58% 42% 48%;
  background: radial-gradient(ellipse at 50% 50%, rgba(70, 96, 150, 0.4) 0%, rgba(70, 96, 150, 0) 72%);
  filter: blur(6px);
}

@media (prefers-reduced-motion: no-preference) {
  .valeris-page .v-lead__halo {
    animation: v-lead-halo-breathe 9s cubic-bezier(0.45, 0, 0.2, 1) infinite alternate,
               v-lead-halo-morph 22s ease-in-out infinite;
    will-change: transform, opacity, border-radius;
  }
  .valeris-page .v-lead__halo::before {
    animation: v-lead-halo-morph 17s ease-in-out infinite reverse;
  }
}

@keyframes v-lead-halo-breathe {
  from { transform: translateY(8px) scale(0.97); opacity: 0.8; }
  to { transform: translateY(-8px) scale(1.04); opacity: 1; }
}

@keyframes v-lead-halo-morph {
  0% { border-radius: 42% 58% 63% 37% / 47% 41% 59% 53%; }
  50% { border-radius: 58% 42% 39% 61% / 55% 60% 40% 45%; }
  100% { border-radius: 42% 58% 63% 37% / 47% 41% 59% 53%; }
}

/* --- entrance animation -------------------------------------------------
   The column carries .v-reveal so the observer flips `is-in` on it, but the
   column itself no longer moves — its children stagger in instead, which
   reads far better than the whole block sliding as one slab. Same
   scripting/reduced-motion gating as every other reveal on the page.
   ----------------------------------------------------------------------- */
@media (scripting: enabled) {
  .valeris-page .v-lead__body.v-reveal { opacity: 1; transform: none; transition: none; }

  .valeris-page .v-lead__body > * {
    opacity: 0;
    transform: translateY(16px);
    transition: opacity 0.6s var(--v-ease), transform 0.6s var(--v-ease);
  }
  .valeris-page .v-lead__body.is-in > * { opacity: 1; transform: none; }
  .valeris-page .v-lead__body.is-in > *:nth-child(1) { transition-delay: 60ms; }
  .valeris-page .v-lead__body.is-in > *:nth-child(2) { transition-delay: 150ms; }
  .valeris-page .v-lead__body.is-in > *:nth-child(3) { transition-delay: 240ms; }
  .valeris-page .v-lead__body.is-in > *:nth-child(4) { transition-delay: 330ms; }

  /* A touch slower and with a hint of scale, so he settles rather than snaps. */
  .valeris-page .v-lead__portrait.v-reveal {
    transform: translateY(26px) scale(0.985);
    transition-duration: 0.85s;
  }
  .valeris-page .v-lead__portrait.v-reveal.is-in { transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .valeris-page .v-lead__body > * { opacity: 1; transform: none; }
}

/* Two columns once there is room; below 993px it stacks (see that breakpoint). */
@media (min-width: 993px) {
  .valeris-page .v-lead__grid {
    grid-template-columns: minmax(0, 1.04fr) minmax(0, 0.96fr);
  }
  /* The section has no bottom padding, so the text needs its own. */
  .valeris-page .v-lead__body { padding-bottom: clamp(34px, 4vw, 60px); }
  .valeris-page .v-lead__facts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ==========================================================================
   Testimonials
   ========================================================================== */
.valeris-page .v-quote {
  background: #fff;
  border: 1px solid var(--v-line);
  border-radius: var(--v-radius-lg);
  padding: clamp(26px, 3vw, 38px);
  display: flex;
  flex-direction: column;
}
.valeris-page .v-quote__mark { font-size: 26px; color: var(--v-copper); line-height: 1; margin-bottom: 18px; }
.valeris-page .v-quote blockquote { margin: 0 0 22px; font-size: var(--v-fs-body); line-height: 1.75; color: var(--v-text); }
.valeris-page .v-quote figcaption { margin-top: auto; padding-top: 18px; border-top: 1px solid var(--v-line); }
.valeris-page .v-quote figcaption strong {
  display: block;
  font-family: var(--v-font-head);
  font-size: var(--v-fs-sm);
  color: var(--v-navy);
}
.valeris-page .v-quote figcaption span { font-size: 12px; color: var(--v-muted); }


/* ==========================================================================
   Affiliates
   ========================================================================== */
.valeris-page .v-affiliates__grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 20px;
}
.valeris-page .v-affiliate {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 26px 24px;
  background: #fff;
  border: 1px solid var(--v-line);
  border-radius: var(--v-radius);
  transition: border-color 0.25s var(--v-ease), transform 0.25s var(--v-ease),
              background-color 0.25s var(--v-ease);
}
/* These cards also carry .v-reveal, whose rule sits later in this file at the
   same specificity — it replaces `transition` wholesale, which silently drops
   the hover colours above and makes the hover snap. Scoped one class tighter
   so it wins, and re-declaring the reveal's own opacity/transform timings so
   the entrance animation is unchanged. */
.valeris-page .v-affiliate.v-reveal {
  transition: opacity 0.6s var(--v-ease), transform 0.6s var(--v-ease),
              background-color 0.25s var(--v-ease), border-color 0.25s var(--v-ease);
}
/* Light-blue wash on hover. Kept faint on purpose — the card's own copy is
   navy and grey, and a stronger tint drops the small "Affiliate" label under
   4.5:1. At this strength the title holds 13.2:1 and the label 4.35:1. */
.valeris-page .v-affiliate:hover {
  background: rgba(79, 143, 199, 0.10);
  border-color: rgba(79, 143, 199, 0.35);
  transform: translateY(-3px);
}
.valeris-page .v-affiliate h3 { font-size: 17px; }
.valeris-page .v-affiliate span { font-size: 13px; color: var(--v-muted); }

/* ==========================================================================
   Contact CTA band
   ========================================================================== */
.valeris-page .v-cta { position: relative; isolation: isolate; overflow: hidden; background: var(--v-navy); }
.valeris-page .v-cta img {
  position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%; object-fit: cover;
}
.valeris-page .v-cta::after {
  content: "";
  position: absolute; inset: 0; z-index: -1;
  /* Kept dark enough that the skyline reads as texture behind the copy,
     never as competing detail under the contact cards. */
  background: linear-gradient(100deg, rgba(13, 28, 58, 0.96) 15%, rgba(13, 28, 58, 0.88) 55%, rgba(13, 28, 58, 0.8) 100%);
}
.valeris-page .v-cta__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
  gap: clamp(28px, 4vw, 60px);
  align-items: center;
}
.valeris-page .v-cta h2 { margin-bottom: 14px; }
.valeris-page .v-cta__contacts { display: grid; gap: 14px; }
.valeris-page .v-cta__contact {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 16px 20px;
  border: 1px solid rgba(79, 143, 199, 0.35);
  border-radius: var(--v-radius);
  /* Opaque: this section's background is a photograph, and the tint let the
     skyline read straight through the cards. */
  background: var(--v-sky-card);
  transition: background-color 0.25s var(--v-ease), border-color 0.25s var(--v-ease);
}
.valeris-page .v-cta__contact:hover { background: var(--v-sky-card-hover); border-color: rgba(79, 143, 199, 0.55); }
.valeris-page .v-cta__contact i { font-size: 18px; color: var(--v-copper); flex: none; }
.valeris-page .v-cta__contact span { display: block; font-size: 12px; color: rgba(255, 255, 255, 0.6); }
.valeris-page .v-cta__contact strong {
  display: block;
  font-family: var(--v-font-head);
  font-size: 14px;
  font-weight: 500;
  color: #fff;
}

/* Utility */
.valeris-page .v-sr {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
.valeris-page .v-head { margin-bottom: clamp(30px, 4vw, 48px); }
.valeris-page .v-head h2 + p { margin-top: 14px; }

/* --------------------------------------------------------------------------
   Motion — subtle reveal, fully opt-out under prefers-reduced-motion
   -------------------------------------------------------------------------- */
/* The reveal start-state is only applied when scripting is available. If JS is
   disabled or fails to load, nothing is ever hidden — the page reads normally,
   just without the fade. Browsers that don't support the `scripting` feature
   also fall through to fully visible content. */
@media (scripting: enabled) {
  .valeris-page .v-reveal {
    opacity: 0;
    transform: translateY(18px);
    transition: opacity 0.6s var(--v-ease), transform 0.6s var(--v-ease);
  }
  .valeris-page .v-reveal.is-in { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .valeris-page * ,
  .valeris-page *::before,
  .valeris-page *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  .valeris-page .v-reveal { opacity: 1; transform: none; }
  .valeris-page .v-hero__slide { transition: none; }
}

/* ==========================================================================
   Responsive
   ========================================================================== */

/* The container is 1340px with no left/right padding, so on a wide screen the
   content measures exactly 1340px. Below that a 20px safety gutter keeps text
   off the screen bezel — delete this block for a true zero gutter everywhere. */
@media (max-width: 1380px) {
  .valeris-page { --v-gutter: 20px; }
}

@media (max-width: 1080px) {
  .valeris-page .v-strip__grid { grid-template-columns: 1fr; }
  .valeris-page .v-strip__figure { min-height: 210px; }
  /* Applies to both carousels — the later rule wins over .v-quotes' own 2-up. */
  .valeris-page .v-carousel { --v-carousel-per: 2; }
}

@media (max-width: 992px) {
  .valeris-page .v-about__grid,
  .valeris-page .v-intro,
  .valeris-page .v-cta__grid { grid-template-columns: 1fr; }
  .valeris-page .v-about__media img { aspect-ratio: 16 / 11; }
  .valeris-page .v-intro { align-items: start; }

  /* Stacked: copy first, then the portrait standing on the section edge. */
  .valeris-page .v-lead__portrait { max-width: min(100%, 420px); }
  .valeris-page .v-lead__halo { width: min(150%, 560px); }

  .valeris-page .v-stats__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .valeris-page .v-affiliates__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 768px) {
  /* Portrait banner takes over. Below this width the hero box is taller than it
     is wide (aspect 0.88 at 768px, 0.35 on a phone) and the landscape crop keeps
     too little of the frame to read as a composition. */
  .valeris-page .v-hero__slide { display: none; }
  .valeris-page .v-hero__portrait { display: block; }

  /* The portrait banner needs the overlay the landscape one does not, and this is
     not a stylistic choice. That artwork is a full-frame composition — lit towers
     and facades across the whole middle, no dark text-safe side — and on a phone
     the copy spans nearly the full width, so it crosses those lit areas whatever
     the background-position. Bare, every line of body copy, the headline at 768px
     and the rating label all measure about 1.0:1 against white: not "low
     contrast", invisible.

     The alphas are measured, not picked: each region was solved for the minimum
     navy that reaches 4.5:1, which peaked at 0.60 through the copy band and 0.55
     at the rating. 0.66 across that band clears all of them with margin, and it
     eases off at both ends where nothing sits — the top, and the light trails at
     the foot of the frame. Worst glyph after this: 5.5:1 at 390px, 5.6:1 at 768px.

     The desktop banner is untouched and stays overlay-free. */
  .valeris-page .v-hero__scrim {
    background: linear-gradient(180deg,
      rgba(13, 28, 58, 0.34) 0%,
      rgba(13, 28, 58, 0.66) 16%,
      rgba(13, 28, 58, 0.66) 74%,
      rgba(13, 28, 58, 0.4) 100%);
  }

  /* Its shadow was there to survive the bare landscape banner's lit towers. Over
     the portrait overlay it has an even background and does not need it. */
  .valeris-page .v-hero__teamlabel { text-shadow: none; }

  /* One card per view, with the next one peeking so the carousel is
     obviously swipeable without needing the buttons. */
  .valeris-page .v-carousel { --v-carousel-per: 1; }
  .valeris-page .v-carousel__viewport { grid-auto-columns: 86%; }

  /* Stacked cards do not need the full flip-card height on the front — the
     back sits below it, so the tall front just pushed the card past the fold. */
  .valeris-page .v-svc__front { min-height: 300px; }

  /* Stacked: the cards' own borders already separate them, so the extra
     top-border/divider treatment the old flat layout needed is not used. */
  .valeris-page .v-strip__panel { grid-template-columns: 1fr; gap: 16px; }
  .valeris-page .v-highlight { border-radius: var(--v-radius-lg); padding: 22px; }
  .valeris-page .v-about__badge { position: static; max-width: none; margin-top: 16px; }
}

@media (max-width: 620px) {
  /* Must stay above the ::after fade band (130px at this width) or the last
     element in the copy column — the statistic card — sits on the lightened
     part of the gradient. 120px, which this was before the fade existed,
     overlapped it. */
  .valeris-page .v-hero { padding-bottom: clamp(165px, 30vw, 200px); }
  .valeris-page .v-stats__grid,
  .valeris-page .v-affiliates__grid { grid-template-columns: 1fr; }
  .valeris-page .v-mv { grid-template-columns: 1fr; }
  .valeris-page .v-hero__actions .v-btn { width: 100%; justify-content: center; }
}
