/*!*************************************************************************************************************************************************************************************************************************************************************!*\
  !*** css ./node_modules/next/dist/build/webpack/loaders/css-loader/src/index.js??ruleSet[1].rules[14].oneOf[10].use[2]!./node_modules/next/dist/build/webpack/loaders/postcss-loader/src/index.js??ruleSet[1].rules[14].oneOf[10].use[3]!./app/globals.css ***!
  \*************************************************************************************************************************************************************************************************************************************************************/
/* =========================================================================
   Radiance Realty — design tokens + base
   ========================================================================= */

/* --- Self-hosted display face -------------------------------------------
   D-DIN Condensed, supplied as OTF and converted to woff2 (~22KB each).
   Only two weights exist, so avoid asking for 500/600 in --font-display
   rules — the browser would synthesise them.
   ------------------------------------------------------------------------ */
@import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap');
/* v2 files: re-encoded with TrueType outlines (the originals were CFF/OTF,
   which some mobile browsers — iOS Safari especially — failed to render).
   woff2 first, woff and ttf as fallbacks. The -v2 names also bust any
   cached copy of the old files on phones. */
@font-face {
  font-family: "D-DIN Condensed";
  src: url("/fonts/d-din-condensed-400-v2.woff2") format("woff2"),
    url("/fonts/d-din-condensed-400-v2.woff") format("woff"),
    url("/fonts/d-din-condensed-400-v2.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "D-DIN Condensed";
  src: url("/fonts/d-din-condensed-700-v2.woff2") format("woff2"),
    url("/fonts/d-din-condensed-700-v2.woff") format("woff"),
    url("/fonts/d-din-condensed-700-v2.ttf") format("truetype");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

:root {
  /* --- Brand palette (sampled from the approved comps) --- */
  --navy-900: #06224a;
  --navy-800: #0a2c5c;
  --navy-700: #0c3a6c;
  --navy-600: #0e4173;
  --navy-500: #054783;
  --navy-400: #14538a;
  --navy-300: #2f6ba3;

  --gold-500: #f8a619;
  --gold-400: #ffb43a;
  --gold-600: #e0900c;

  --ink-900: #0d1b2a;
  --ink-700: #2b3b4d;
  --ink-500: #5a6a7c;
  --ink-300: #97a3b0;

  --paper: #ffffff;
  --paper-alt: #f0f0f0;
  --paper-blue: #d9e6f5;
  --line: rgba(12, 58, 108, 0.16);
  --line-light: rgba(255, 255, 255, 0.22);

  --grad-navy: linear-gradient(135deg, #0a2c5c 0%, #06224a 55%, #041a3a 100%);
  --grad-navy-panel: linear-gradient(120deg, #0c3a6c 0%, #072b57 60%, #06224a 100%);
  --grad-cta: linear-gradient(90deg, #1a5fa0 0%, #0d3f76 100%);
  /* CTA pill (.exbloretwoBtn / .btn--duo) — one orange ramp for every
     placement on the site. Retheme the buttons by editing these two stops. */
  --grad-cta-orange: linear-gradient(90deg, #f6800e 0%, #f9a41a 100%);
  --cta-orange-shadow: rgba(180, 88, 6, 0.34);
  --cta-orange-shadow-hover: rgba(180, 88, 6, 0.46);

  /* --- Typography --- */
  /* Swap these two lines to retheme the whole site.
     --font-display  D-DIN Condensed — section titles and display numerals.
                     The fallbacks are ordered so a failed webfont still lands
                     on something condensed: Arial Narrow (Windows), Helvetica
                     Neue Condensed (macOS/iOS), Roboto Condensed and the
                     sans-serif-condensed alias (Android). Without them a
                     phone drops straight to a wide system face, which is why
                     a font failure looks far worse on mobile than on a
                     Windows desktop.
     --font-body     Manrope — body copy, header nav, most headlines */
  --font-display: "D-DIN Condensed", "Arial Narrow", "Helvetica Neue Condensed", "Roboto Condensed", sans-serif-condensed, sans-serif;
  --font-body: "Manrope", system-ui, -apple-system, "Segoe UI", sans-serif;

  /* Fluid type scale */
  --fs-eyebrow: clamp(0.68rem, 0.62rem + 0.28vw, 0.84rem);
  --fs-body-sm: clamp(0.86rem, 0.8rem + 0.28vw, 0.98rem);
  --fs-body: clamp(0.95rem, 0.88rem + 0.36vw, 1.12rem);
  --fs-lead: clamp(1.1rem, 0.95rem + 0.72vw, 1.6rem);
  --fs-h4: clamp(1.05rem, 0.92rem + 0.62vw, 1.4rem);
  --fs-h3: clamp(1.35rem, 1.1rem + 1.2vw, 2.1rem);
  --fs-h2: clamp(2rem, 1.35rem + 3.1vw, 4.2rem);
  --fs-h1: clamp(2.4rem, 1.5rem + 4.4vw, 5.4rem);
  --fs-stat: clamp(2.8rem, 1.6rem + 5.6vw, 6.5rem);

  /* --- Spacing scale --- */
  --sp-1: 0.25rem;
  --sp-2: 0.5rem;
  --sp-3: 0.75rem;
  --sp-4: 1rem;
  --sp-5: 1.5rem;
  --sp-6: 2rem;
  --sp-7: 3rem;
  --sp-8: 4rem;
  --sp-9: 6rem;
  --sp-10: 8rem;

  --gutter: clamp(1.25rem, 4vw, 5rem);
  --maxw: 1440px;

  --radius-sm: 6px;
  --radius: 12px;
  --radius-lg: 22px;
  --radius-pill: 999px;

  --shadow-sm: 0 2px 10px rgba(6, 34, 74, 0.08);
  --shadow: 0 12px 40px rgba(6, 34, 74, 0.14);
  --shadow-lg: 0 30px 70px rgba(6, 34, 74, 0.22);

  --header-h: 84px;
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
}

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

* {
  margin: 0;
  padding: 0;
}

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

body {
  width: 100%;
  overflow-x: hidden;
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: 1.6;
  color: var(--ink-900);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

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

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

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  cursor: pointer;
}

ul,
ol {
  list-style: none;
}

:focus-visible {
  outline: 2px solid var(--gold-500);
  outline-offset: 3px;
}

/* =========================================================================
   Shared primitives
   ========================================================================= */

.shell {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section {
  position: relative;
  padding-block: clamp(3.5rem, 7vw, 7rem);
}

/* Headings ---------------------------------------------------------------- */

/*
   Every <h1> and <h2> is set in the display face by default. Section titles
   therefore need no font-family of their own — a heading that should use the
   body face has to opt out explicitly.

   D-DIN Condensed only ships 400 and 700, so heading rules must not request
   500/600 or the browser will synthesise a smeared weight.
*/
h1,
h2 {
  font-family: var(--font-display);
}

.eyebrow {
  font-family: var(--font-body);
  font-size: var(--fs-eyebrow);
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--navy-500);
}

.eyebrow--light {
  color: rgba(255, 255, 255, 0.78);
}

.display {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-h2);
  line-height: 0.98;
  letter-spacing: 0.005em;
  text-transform: uppercase;
  color: var(--navy-400);
}

.display--light {
  color: #fff;
}

.display--gold {
  color: var(--gold-500);
}

/* Apostrophes / commas inside display-face text, wrapped by lib/punct.jsx.
   Set in the body face so they read at weight against the condensed caps. */
.punct {
  display: inline !important; /* many `.x__title span { display: block }` rules exist */
  font-family: var(--font-body);
  font-weight: 600;
  /* Zero line-height so Manrope's taller ascent/descent can't grow the line
     box and push the lines around it out of the display face's rhythm. */
  line-height: 0;
  vertical-align: baseline;
}

.title {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: var(--fs-h3);
  line-height: 1.15;
  letter-spacing: -0.01em;
}

.lead {
  font-size: var(--fs-lead);
  font-weight: 400;
  line-height: 1.28;
  letter-spacing: -0.005em;
}

.muted {
  color: var(--ink-500);
}

.muted--light {
  color: rgba(255, 255, 255, 0.74);
}

/* Buttons ----------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  padding: 0.85em 1.9em;
  border-radius: var(--radius-pill);
  font-family: var(--font-body);
  font-size: var(--fs-body-sm);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  white-space: nowrap;
  transition: transform 0.35s var(--ease), box-shadow 0.35s var(--ease),
    background-color 0.35s var(--ease), color 0.35s var(--ease);
}

.btn:hover {
  transform: translateY(-2px);
}

/* A .btn may be a <button> rather than an <a> — every Download Brochure
   button opens the popup form instead of navigating. Wrapped in :where() so
   the reset carries no specificity of its own and every .btn--* variant
   still paints its own background and border over it. */
button:where(.btn) {
  border: 0;
  background: none;
  font: inherit;
  cursor: pointer;
}

.btn--solid {
  /* The sheen is an ::after inside the pill, so it has to clip. */
  position: relative;
  overflow: hidden;
  background: var(--navy-500);
  color: #fff;
  box-shadow: var(--shadow-sm);
  /* .btn already transitions transform / box-shadow / background / color —
     letter-spacing is the one this hover adds. */
  transition: transform 0.45s var(--ease), box-shadow 0.45s var(--ease),
    background-color 0.45s var(--ease), letter-spacing 0.45s var(--ease);
}

/* Same sheen the two-action pill uses (.exbloretwoBtn::after), so a solid
   button and a duo pill answer the pointer the same way. */
.btn--solid.btn--solid::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(
    100deg,
    transparent 35%,
    rgba(255, 255, 255, 0.22) 50%,
    transparent 65%
  );
  transform: translateX(-100%);
  transition: transform 0.7s var(--ease);
}

.btn--solid:hover {
  background: var(--navy-400);
  transform: translateY(-2px);
  box-shadow: 0 16px 34px rgba(6, 34, 74, 0.34);
  letter-spacing: 0.16em;
}

.btn--solid.btn--solid:hover::after {
  transform: translateX(100%);
}

/* The label sits above the sheen. */
.btn--solid.btn--solid > * {
  position: relative;
  z-index: 1;
}

.btn--gradient {
  background: var(--grad-cta);
  color: #fff;
  box-shadow: 0 14px 30px rgba(6, 34, 74, 0.35);
}

.btn--ghost-light {
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.35);
  color: #fff;
  -webkit-backdrop-filter: blur(6px);
          backdrop-filter: blur(6px);
}

.btn--ghost-light:hover {
  background: rgba(255, 255, 255, 0.18);
}

.btn--ghost-dark {
  background: linear-gradient(90deg, #e4edf8 0%, #f4f8fd 100%);
  color: var(--navy-500);
}

.btn__divider {
  opacity: 0.45;
}

/* =========================================================================
   Two-action button
   -------------------------------------------------------------------------
   A single pill carrying two links, split by a hairline: rounded off on the
   left, squared on the right.

   Two markup shapes, one look:
     .exbloretwoBtn   container with two <a class="btn"> inside — each half
                      lights independently on hover
     .btn--duo        one <a> with an inline .btn__divider

   Hover runs four things at once: the half lights, a sheen sweeps the pill,
   the squared end rounds out, and the whole thing lifts.
   ========================================================================= */

.exbloretwoBtn,
.btn--duo {
  --duo-radius: 999px 10px 10px 999px;

  position: relative;
  display: inline-flex;
  align-items: stretch;
  /* The ribbon card is a stretch flex column — without this the pill would
     span its full width instead of hugging its text. */
  align-self: flex-start;
  max-width: 100%;
  overflow: hidden;
  border-radius: var(--duo-radius);
  background: var(--grad-cta-orange);
  box-shadow: 0 10px 26px var(--cta-orange-shadow);
  transition: border-radius 0.45s var(--ease), transform 0.45s var(--ease),
    box-shadow 0.45s var(--ease);
}

.exbloretwoBtn:hover,
.btn--duo:hover {
  border-radius: 999px;
  transform: translateY(-2px);
  box-shadow: 0 16px 34px var(--cta-orange-shadow-hover);
}

/* Sheen sweeping left → right across the whole pill. */
.exbloretwoBtn::after,
.btn--duo::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(
    100deg,
    transparent 35%,
    rgba(255, 255, 255, 0.22) 50%,
    transparent 65%
  );
  transform: translateX(-100%);
  transition: transform 0.7s var(--ease);
}

.exbloretwoBtn:hover::after,
.btn--duo:hover::after {
  transform: translateX(100%);
}

/* The halves themselves are plain type — the container carries the shape. */
.exbloretwoBtn > .btn {
  position: relative;
  margin: 0;
  border: 0;
  border-radius: 0;
  background-color: transparent;
  background-image: linear-gradient(
    90deg,
    rgba(255, 255, 255, 0.2),
    rgba(255, 255, 255, 0.05)
  );
  background-repeat: no-repeat;
  background-size: 0% 100%;
  box-shadow: none;
  -webkit-backdrop-filter: none;
          backdrop-filter: none;
  color: #fff;
  white-space: nowrap;
  transition: background-size 0.45s var(--ease), letter-spacing 0.45s var(--ease);
}

/* The generic .btn lift would fight the container's. */
.exbloretwoBtn > .btn:hover {
  transform: none;
  background-size: 100% 100%;
  letter-spacing: 0.16em;
}

/* Hairline between the two halves. */
.exbloretwoBtn > .btn + .btn::before {
  content: "";
  position: absolute;
  left: 0;
  top: 28%;
  bottom: 28%;
  width: 1px;
  background: rgba(255, 255, 255, 0.4);
}

.btn--duo {
  color: #fff;
}

.btn--duo:hover {
  letter-spacing: 0.16em;
}

@media (max-width: 560px) {
  /* Two halves plus padding will not fit one line on a phone. */
  .exbloretwoBtn {
    flex-direction: column;
    align-items: stretch;
    border-radius: 22px;
  }

  .exbloretwoBtn > .btn {
    justify-content: center;
  }

  .exbloretwoBtn > .btn + .btn::before {
    left: 14%;
    right: 14%;
    top: 0;
    bottom: auto;
    width: auto;
    height: 1px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .exbloretwoBtn,
  .btn--duo,
  .exbloretwoBtn > .btn {
    transition-duration: 0.01ms;
  }

  .exbloretwoBtn::after,
  .btn--duo::after {
    display: none;
  }

  .exbloretwoBtn:hover,
  .btn--duo:hover {
    transform: none;
  }
}

/* Divider ----------------------------------------------------------------- */

.rule {
  height: 1px;
  background: var(--line);
  border: 0;
}

.rule--light {
  background: var(--line-light);
}

/* Watermark text ---------------------------------------------------------- */

.watermark {
  position: absolute;
  font-family: var(--font-display);
  font-weight: 700;
  text-transform: uppercase;
  line-height: 0.8;
  pointer-events: none;
  -webkit-user-select: none;
     -moz-user-select: none;
          user-select: none;
  white-space: nowrap;
}

/* Heading mask wipe ------------------------------------------------------- */
/*
   Each line slides up from behind its own mask. `.maskUp` is the clipping box
   and its direct children are the lines that travel.

   Two ways to apply it, both driven by the same rule:
     - heading has block-level line spans  → put .maskUp on the heading
     - heading is inline/flex or one line  → wrap it in <div class="maskUp">

   Reveal is triggered by the shared [data-reveal] observer adding .is-visible.
*/

.maskUp {
  overflow: hidden;
  /* Room for descenders at rest, without changing the layout box. */
  padding-bottom: 0.14em;
  margin-bottom: -0.14em;
}

.maskUp > * {
  transform: translateY(110%);
  transition: transform 0.95s var(--ease);
  will-change: transform;
}

.maskUp.is-visible > * {
  transform: none;
}

.maskUp.is-visible > *:nth-child(2) { transition-delay: 0.09s; }
.maskUp.is-visible > *:nth-child(3) { transition-delay: 0.18s; }
.maskUp.is-visible > *:nth-child(4) { transition-delay: 0.27s; }
.maskUp.is-visible > *:nth-child(5) { transition-delay: 0.36s; }

/* The reveal repeats, so elements are rearmed when they scroll fully out of
   view. Rearming must be instant — a transition on the way out would leave a
   half-played state ready to be caught on the way back in. */
.maskUp:not(.is-visible) > *,
[data-reveal]:not(.is-visible) {
  transition-duration: 0s;
  transition-delay: 0s;
}

/* The mask supersedes the generic fade — otherwise the clipping box itself
   would move and the wipe would read as a plain slide. */
.maskUp[data-reveal] {
  opacity: 1;
  transform: none;
  transition: none;
}

/* Reveal-on-scroll -------------------------------------------------------- */

[data-reveal] {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity 0.9s var(--ease), transform 0.9s var(--ease);
}

[data-reveal].is-visible {
  opacity: 1;
  transform: none;
}

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

  [data-reveal] {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .maskUp {
    overflow: visible;
  }

  .maskUp > * {
    transform: none;
    transition: none;
  }
}

/* =========================================================================
   Pinned horizontal scroll rig
   (vertical scroll distance is mapped to horizontal translate by JS)
   ========================================================================= */

.hscroll {
  /* Strip reserved at the bottom for the progress line, so it never sits on
     top of the imagery. The track is inset by this amount. */
  --progress-h: clamp(34px, 5vh, 56px);

  position: relative;
  /* Consecutive pinned sections are overlapped by 100vh (see
     useHorizontalScroll → measure) so the next ribbon starts the moment the
     previous one ends. Each section must therefore be its own stacking
     context, or the outgoing section's progress line (z-index: 5) would paint
     over the incoming section. With contexts, plain DOM order applies and the
     later section covers the earlier one. */
  isolation: isolate;
  padding: 0;
  background: var(--paper);
}

.hscroll__wrap {
  position: -webkit-sticky;
  position: sticky;
  top: 0;
  height: 100vh;
  width: 100%;
  overflow: hidden;
}

/*
   Progress line — 0 → 100% of the horizontal travel.

   Drawn on the sticky wrapper, not the track, so it stays put in the viewport
   while the content slides underneath. `--hp` is written by
   useHorizontalScroll on each frame.

   ::before is the rail, ::after the fill. `scaleX` on a transform-origin of
   left keeps this on the compositor — animating `width` would lay out on every
   frame of the scroll.
*/
.hscroll__wrap::before,
.hscroll__wrap::after {
  content: "";
  position: absolute;
  /* Centred in the reserved strip and inset to the page gutter, so it reads as
     a rule under the content rather than an overlay on it. */
  left: var(--gutter);
  bottom: calc(var(--progress-h) / 2 - 1px);
  height: 2px;
  width: calc(100% - var(--gutter) * 2);
  z-index: 5;
  pointer-events: none;
}

.hscroll__wrap::before {
  background: rgba(255, 255, 255, 0.16);
}

.hscroll__wrap::after {
  background: linear-gradient(90deg, var(--gold-500), var(--gold-400));
  transform-origin: left center;
  transform: scaleX(var(--hp, 0));
}

/* On the pale-opening theme the rail needs contrast against near-white. */
.project--light .hscroll__wrap::before {
  background: rgba(12, 58, 108, 0.16);
}

.hscroll__track {
  position: absolute;
  /* Bottom inset keeps the content clear of the progress strip. Height is
     therefore derived from the insets, not set to 100%. */
  inset: 0 auto var(--progress-h) 0;
  height: auto;
  display: flex;
  will-change: transform;
}

/* Inner parallax layer — counter-translated by useHorizontalScroll so text
   drifts slower than the track. Tag any element inside the track with
   data-hpx="0–1" (higher = slower / farther back). */
.hscroll [data-hpx] {
  will-change: transform;
}

.hscroll__panel {
  flex: 0 0 100vw;
  width: 100vw;
  height: 100%;
  position: relative;
  overflow: hidden;
}

/* On touch / narrow screens the horizontal rig is disabled and the panels
   stack vertically — see each section's own stylesheet for the fallbacks. */
@media (max-width: 900px) {
  .hscroll__wrap {
    position: static;
    height: auto;
    overflow: visible;
  }

  /* The rig is off and the panels stack, so there is no horizontal travel
     to report. */
  .hscroll__wrap::before,
  .hscroll__wrap::after {
    display: none;
  }

  .hscroll__track {
    position: static;
    display: block;
    transform: none !important;
  }

  .hscroll [data-hpx] {
    transform: none !important;
  }

  .hscroll__panel {
    width: 100%;
    height: auto;
  }
}


.legacy{ background-image: url('/media/legacy-interior.jpg');
  background-size: cover;
  background-position: center;}

/* =========================================================================
   Motion primitives — aurora field
   -------------------------------------------------------------------------
   A drop-in decorative background layer, kept here rather than in a page
   stylesheet so any section can use it. useAurora (hooks/useMotionFx.js)
   writes --ax / --ay — the pointer's position over the host section, 0–1 —
   which the blobs read to drift toward the cursor.

   Every property carries its own default, so a section renders correctly
   with the hook absent, JavaScript off, or motion reduced.
   ========================================================================= */

/* --- Aurora ---------------------------------------------------------------
   Three large blurred blobs on their own clocks. The host must establish a
   stacking context and clip — .fxField does both, and is a positioned layer
   rather than a background on the section itself so it can be dropped into a
   section whose own overflow must stay unclipped (the About band, whose
   sticky legacy-card pin would die under overflow:hidden).
   ------------------------------------------------------------------------ */

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

.fxField__aurora {
  position: absolute;
  inset: -20%;
  /* Blur is expensive, so these are few and large rather than many and
     small. Applied to the group, not per blob, for one filter pass. */
  filter: blur(90px);
  opacity: 0.55;
}

.fxBlob {
  position: absolute;
  display: block;
  border-radius: 50%;
  will-change: transform;
}

.fxBlob--a {
  top: calc(var(--ay, 0.32) * 26%);
  left: calc(var(--ax, 0.5) * 34%);
  width: 46vw;
  height: 46vw;
  background: radial-gradient(circle, rgba(248, 166, 25, 0.5), transparent 68%);
  animation: fxDrift 22s var(--ease) infinite alternate;
}

.fxBlob--b {
  top: calc(18% + var(--ay, 0.32) * 22%);
  right: calc(var(--ax, 0.5) * -12%);
  width: 52vw;
  height: 52vw;
  background: radial-gradient(circle, rgba(47, 107, 163, 0.75), transparent 66%);
  animation: fxDrift 28s var(--ease) 2s infinite alternate-reverse;
}

.fxBlob--c {
  bottom: -10%;
  left: calc(20% + var(--ax, 0.5) * 18%);
  width: 40vw;
  height: 40vw;
  background: radial-gradient(circle, rgba(20, 83, 138, 0.8), transparent 70%);
  animation: fxDrift 34s var(--ease) 1s infinite alternate;
}

@keyframes fxDrift {
  from {
    transform: translate3d(-4%, 2%, 0) scale(1);
  }
  to {
    transform: translate3d(6%, -5%, 0) scale(1.14);
  }
}

/* Film grain over the gradient. An SVG turbulence data URI, so there is no
   asset to ship and no extra request. */
.fxGrain {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.16;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
  animation: fxGrainShift 0.7s steps(2) infinite;
}

@keyframes fxGrainShift {
  0% { transform: translate(0, 0); }
  50% { transform: translate(-3%, 2%); }
  100% { transform: translate(2%, -3%); }
}

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

/* =========================================================================
   Banner opening
   -------------------------------------------------------------------------
   The scroll-opening photo banner, shared by the About and Contact pages.
   The banner starts inset with rounded corners and widens to full bleed with
   square ones as it comes into view, the photograph parallaxing inside it.

     <div class="bannerOpen" ref>          ← useBannerReveal writes --bp/--bpx
       <div class="bannerOpen__frame">     ← carries the width + shadow
         <figure class="bannerOpen__card"> ← page sets its height
           <img class="bannerOpen__img">

   The opening is a real width change, not a transform. Scaling would only
   magnify an already-inset banner — bigger, softer, and still never touching
   the edges.

   Because width drives layout, the card's height is set by the page in
   absolute terms rather than as an aspect-ratio. If the height tracked the
   width, everything below the banner would shift up the page on every frame
   of the opening; with a set height only the width changes and the rest of
   the page stays put. object-fit absorbs the changing crop.

   --bp defaults to 0, the *start* of the animation, not the end. The
   stylesheet is what paints before the hook has measured anything, so
   defaulting to 1 would send the first frame out full-bleed and then snap it
   inward once JavaScript ran.
   ========================================================================= */

.bannerOpen {
  --bp: 0;
  --bpx: 0;

  position: relative;
  z-index: 1;
}

/* Auto margins keep the banner centred at every width. drop-shadow rather
   than a box-shadow on the card, so the glow follows the rounded corners as
   they square off. */
.bannerOpen__frame {
  position: relative;
  width: calc(60% + var(--bp) * 40%);
  margin-inline: auto;
  filter: drop-shadow(0 30px 70px rgba(4, 20, 45, 0.4));
}

.bannerOpen__card {
  position: relative;
  overflow: hidden;
  border-radius: calc((1 - var(--bp)) * 30px);
}

/* Overscaled vertically so there is something to parallax against: 20% of
   headroom carries 16% of travel, leaving 4% of margin so no edge is ever
   exposed at either end of the range. */
.bannerOpen__img {
  display: block;
  width: 100%;
  height: 120%;
  object-fit: cover;
  transform: translate3d(0, calc(var(--bpx) * -16%), 0);
  will-change: transform;
}

/* The hook is off below 1101px, so --bp stays at 0 — the resting width has to
   be near full here or a phone would be left with a narrow banner. */
@media (max-width: 1100px), (prefers-reduced-motion: reduce) {
  .bannerOpen__frame {
    width: calc(94% + var(--bp) * 6%);
  }

  .bannerOpen__img {
    height: 100%;
    transform: none;
  }
}
/* Every moving rail gets its own compositor layer, so the per-frame
   transform never repaints the page around it. */
.hscroll__track,
.zero__track,
.leaders__track,
.am__track,
.cn__track,
.qband__track,
.pg__track,
.st__track,
.cTicker__track,
.projects__marquee span {
  will-change: transform;
  -webkit-backface-visibility: hidden;
          backface-visibility: hidden;
}

/*!****************************************************************************************************************************************************************************************************************************************************************!*\
  !*** css ./node_modules/next/dist/build/webpack/loaders/css-loader/src/index.js??ruleSet[1].rules[14].oneOf[10].use[2]!./node_modules/next/dist/build/webpack/loaders/postcss-loader/src/index.js??ruleSet[1].rules[14].oneOf[10].use[3]!./app/components.css ***!
  \****************************************************************************************************************************************************************************************************************************************************************/
/* =========================================================================
   Radiance Realty — component styles
   Ordered top-to-bottom in page order.
   ========================================================================= */

h2.display {  font-size: 100px !important; color: #0b4c80;}
.visually-hidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  -webkit-clip-path: inset(50%);
          clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---------------------------------------------------------------- Logo -- */
/*
   The wordmark is artwork, not type. `font-size` on .logo sets its height and
   the width follows the artwork's aspect ratio, so it scales with the type
   around it exactly as the old typeset version did.
*/

.logo {
  display: block;
  width: auto;
  height: 70px;
  font-size: clamp(1.15rem, 0.9rem + 1vw, 1.9rem);
  -webkit-user-select: none;
     -moz-user-select: none;
          user-select: none;
}

.logo--ghost {
  height: auto;
  width: 100%;
  font-size: clamp(2.6rem, 1.4rem + 5vw, 6rem);
  opacity: 0.13;
      filter: grayscale(100%) opacity(0.9);
}

/* Project lockup — artwork variant: height set like type, width from ratio. */
.lockup--art {
  display: block;
  width: auto;
  max-width: 300px;
  object-fit: contain;
  object-position: left center;
}
.project.project--navy .lockup {
    filter: brightness(0) invert(1);
}
/* Project lockup — composed fallback for developments without artwork. */
.lockup {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  margin: 0 0 20px;
}

.lockup__pillars {
  display: grid;
  grid-template-columns: repeat(4, 4px);
  grid-gap: 3px;
  gap: 3px;
  height: 44px;
  align-items: end;
}

.lockup__pillars span {
  display: block;
  width: 4px;
  background: currentColor;
  opacity: 0.9;
}

.lockup__pillars span:nth-child(1) { height: 60%; }
.lockup__pillars span:nth-child(2) { height: 100%; }
.lockup__pillars span:nth-child(3) { height: 78%; }
.lockup__pillars span:nth-child(4) { height: 44%; }

.lockup--light { color: #fff; }
.lockup--dark { color: var(--navy-500); }

.lockup__text {
  display: flex;
  flex-direction: column;
  line-height: 1;
}

.lockup__logo {
  font-size: clamp(0.95rem, 0.8rem + 0.5vw, 1.3rem);
}

.lockup__name {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 1rem + 2.2vw, 2.9rem);
  font-weight: 400;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  margin-top: 0.12em;
}

.lockup__place {
  font-family: var(--font-body);
  font-size: var(--fs-eyebrow);
  font-weight: 500;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  opacity: 0.85;
  margin-top: 0.5em;
}

.exbloretwoBtn {opacity: 1; transform: inherit;}
 .btn--duo {opacity: 1; transform: inherit;}

.exbloretwoBtn, .btn--duo {
    --duo-radius: 999px 10px 10px 999px;
    position: relative;
    display: inline-flex;
    align-items: stretch;
    align-self: flex-start;
    max-width:max-content;
    overflow: hidden;
    box-shadow: none;
       border-radius: 35px;
    transition: border-radius 0.45s var(--ease), transform 0.45s var(--ease), box-shadow 0.45s var(--ease);
    background-image: linear-gradient(to right, #f6800e, #f9a51a, #f6800e);
    opacity: 1; transform: inherit; 
}

.exbloretwoBtn a{font-size: 14px;;}
.exbloretwoBtn button{font-size: 14px;;}

/* -------------------------------------------------------------- Header --
   Fixed, and reveals on scroll up:
     at top      transparent, sitting over the banner
     scrolled ↓  slides out of the way (translateY(-100%))
     scrolled ↑  slides back in, solid
   Frozen while the drawer is open so it can't move underneath it.
   ------------------------------------------------------------------------- */

.header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 100;
  font-family: var(--font-body);
  transition: transform 0.45s var(--ease), background-color 0.4s var(--ease),
    box-shadow 0.4s var(--ease), -webkit-backdrop-filter 0.4s var(--ease);
  transition: transform 0.45s var(--ease), background-color 0.4s var(--ease),
    backdrop-filter 0.4s var(--ease), box-shadow 0.4s var(--ease);
  transition: transform 0.45s var(--ease), background-color 0.4s var(--ease),
    backdrop-filter 0.4s var(--ease), box-shadow 0.4s var(--ease), -webkit-backdrop-filter 0.4s var(--ease);
}

.header.is-scrolled {
  background: #0a1d49;
   box-shadow: none;
}

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

/* The overlay sits above the header and covers it; keep the bar neutral so
   nothing shows through during the fade. */
.header.is-open {
  background: transparent;
  -webkit-backdrop-filter: none;
          backdrop-filter: none;
  box-shadow: none;
}

.header__inner {
  display: grid;
  grid-template-columns: 1fr auto 1fr auto;
  align-items: center;
  grid-gap: var(--sp-5);
  gap: var(--sp-5);
  max-width: var(--maxw);
  margin-inline: auto;
  padding: var(--sp-4) var(--gutter);
  min-height: var(--header-h);
}

.header__nav {
  display: flex;
  align-items: center;
  gap: clamp(1rem, 2.4vw, 2.8rem);
}

.header__nav--left { justify-content: flex-end; }
.header__nav--right { justify-content: flex-start; }

.header__link {
  position: relative;
  font-size: 17px;
  font-weight: 600;
  /* Manrope's uppercase is wider than the previous face — slightly tighter
     tracking keeps six links + logo + burger on one row down to ~1024px. */
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.92);
  white-space: nowrap;
  padding-block: 0.3em;
}

.header__link::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 1px;
  background: var(--gold-500);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.35s var(--ease);
}

.header__link:hover::after {
  transform: scaleX(1);
}

.header__logo {
  justify-self: center;
}

/* ---- hamburger: present at every breakpoint, always far right ---- */

.burger {
  justify-self: end;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  z-index: 120;
  transition: background-color 0.3s var(--ease);
 position: absolute;
   right: 30px;
  
}

/* Hover: the bars wipe out to the right and sweep back in from the left,
   staggered, landing gold — plus a soft ring bloom on the button. */
.burger:hover {
  
}

.burger__bars {
  display: grid;
  grid-gap: 5px;
  gap: 5px;
  width: 50px;
  overflow: hidden; /* clips the wipe */
}

.burger__bars span {
  height: 2px;
  background: #fff;
  border-radius: 2px;
  transition: transform 0.4s var(--ease), opacity 0.2s var(--ease),
    background-color 0.3s var(--ease);
}

.burger__bars span:last-child { display: none; }

.burger:hover .burger__bars span,
.burger:focus-visible .burger__bars span {
  animation: burgerSweep 0.55s var(--ease) both;
  background: var(--gold-500);
}

.burger:hover .burger__bars span:nth-child(2),
.burger:focus-visible .burger__bars span:nth-child(2) {
  animation-delay: 0.08s;
}

@keyframes burgerSweep {
  0%   { transform: translateX(0);      opacity: 1; }
  42%  { transform: translateX(115%);   opacity: 0; }
  50%  { transform: translateX(-115%);  opacity: 0; }
  100% { transform: translateX(0);      opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .burger:hover .burger__bars span,
  .burger:focus-visible .burger__bars span {
    animation: none;
  }
}



/* ----------------------------------------------------- Full-screen menu --
   Left: links panel on white. Right: three city columns, one active at a time
   (orange plate, white type, colour photograph); the others sit near-white and
   desaturated. Hover or focus moves the active column.
   ------------------------------------------------------------------------- */

.siteMenu {
  position: fixed;
  inset: 0;
  z-index: 110;
  display: grid;
  grid-template-columns: minmax(0, 37fr) minmax(0, 63fr);
  background: #fff;
  color: var(--ink-900);
  visibility: hidden;
  opacity: 0;
  transition: opacity 0.45s var(--ease), visibility 0.45s var(--ease);
}

.siteMenu.is-open {
  visibility: visible;
  opacity: 1;
}

/* ---- left panel ---- */

.siteMenu__panel {
  display: grid;
  align-content: start;
  grid-gap: 10px;
  gap: 10px;
  padding: 50px 0 50px 130px;
  overflow-y: auto;
}
.siteMenu__nav{order: 2;}

.siteMenu__logo {
  display: inline-flex;
  font-size: clamp(1.6rem, 1rem + 1.8vw, 2.6rem);
}

.siteMenu__nav ul,
.siteMenu__statuses ul {
  display: grid;
}

.siteMenu__nav a {
  display: inline-block;
  font-weight: 600;
  font-size: 22px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: #000;
  padding: 0 0 5px;
  transition: color 0.25s var(--ease), transform 0.25s var(--ease);
}

.siteMenu__statuses {
  margin-top: 0;  margin-bottom: 5px;
}

.siteMenu__statuses a {
  display: inline-block;
  font-family: var(--font-body);
  font-weight: 300;
  font-size: clamp(1.5rem, 1rem + 2vw, 2.9rem);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #292929;
   transition: color 0.25s var(--ease), transform 0.25s var(--ease);
}

.siteMenu__nav a:hover,
.siteMenu__statuses a:hover {
  color: var(--gold-600);
  transform: translateX(6px);
}

/* Links stagger in behind the panel once it opens. */
.siteMenu__nav li,
.siteMenu__statuses li {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.5s var(--ease), transform 0.5s var(--ease);
}

.siteMenu.is-open .siteMenu__nav li,
.siteMenu.is-open .siteMenu__statuses li {
  opacity: 1;
  transform: none;
  transition-delay: calc(0.18s + var(--i) * 0.035s);
}

/* ---- right: city columns ---- */

.siteMenu__cities {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  height: 100%;
  min-height: 0;
}

/* Every column carries the orange plate and its own photograph now, not
   only the hovered one. What changes on hover is how strongly it reads:
   held back and washed out at rest, full strength and a shade deeper under
   the pointer. */
.menuCity {
  position: relative;
  overflow: hidden;
  border-left: 1px solid rgba(12, 58, 108, 0.08);
  background: linear-gradient(180deg, #f7a41b 0%, #f2921a 100%);
      filter: grayscale(100%);
      
}
/* Lit column: full colour. Driven by .is-active (React sets it on hover AND
   on focus, and opens the menu with Chennai already set) rather than by
   :hover alone, so the keyboard and the default state get the same treatment
   the pointer does. */
.menuCity.is-active {
  filter: grayscale(0);
}

/* :hover is guarded so it never applies on a touch screen. iOS treats the
   first tap on an element that has :hover styling as a hover — the tap paints
   the hover state and the link is not followed until a second tap, which is
   what read as "the menu links don't work on mobile". */
@media (hover: hover) and (pointer: fine) {
  .menuCity:hover {
    filter: grayscale(0);
  }
}

/* Touch: there is no hover to reveal anything, so every column is drawn at
   full strength and a single tap follows the link. */
@media (hover: none) {
  .menuCity {
    filter: none;
  }

  .menuCity .menuCity__media img {
    opacity: 1;
  }

  .menuCity .menuCity__link::after {
    background: rgba(6, 34, 74, 0.12);
  }
}

.menuCity__link {
  position: relative;
  display: block;
  height: 100%;
  padding: clamp(2rem, 5vh, 4rem) clamp(0.75rem, 1.5vw, 1.5rem);
}

/* One veil over the plate, the photograph and the watermark together, so a
   resting column recedes as a whole rather than in three pieces at three
   rates.

   Drawn as the link's ::after rather than ::before: a pseudo-element is the
   link's first or last child, and only the last one paints above
   .menuCity__media. .menuCity__name carries its own z-index, so the name
   still sits above the veil and stays legible at rest. */
.menuCity__link::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: rgba(255, 255, 255, 0.58);
  transition: background-color 0.5s var(--ease);
}

/* Hovered or focused: the wash turns to a slight darkening, so the plate
   reads deeper than plain orange rather than merely uncovered. */
.menuCity.is-active .menuCity__link::after {
  background: rgba(6, 34, 74, 0.12);
}

/* Big vertical ghost of the city name, reading bottom-to-top. */
.menuCity__watermark {
  position: absolute;
  left: clamp(0.25rem, 1vw, 1rem);
  top: clamp(1rem, 4vh, 3rem);
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 70px;
  line-height: 1;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.3);
  pointer-events: none;
  -webkit-user-select: none;
     -moz-user-select: none;
          user-select: none;
  transition: color 0.5s var(--ease);
}

.menuCity.is-active .menuCity__watermark {
  color: rgba(255, 255, 255, 0.24);
}

/* Landmark photograph. With no image supplied the plate alone shows through. */
.menuCity__media {
  position: absolute;
  inset: 0;
  display: block;
  overflow: hidden;
}
  
.menuCity__media img {
   width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center bottom;
  filter: grayscale(20%);
  transform: scale(1.04);
      opacity: 0.2;
  transition: filter 0.55s var(--ease), transform 0.55s var(--ease);
}
/* The resting photo is held at opacity 0.2 above; .is-active below restores
   it. Only the pointer path needs its own rule. */
@media (hover: hover) and (pointer: fine) {
  .menuCity:hover .menuCity__media img {
    opacity: 1;
  }
}

.menuCity.is-active .menuCity__media img {
  filter: none;
  transform: none;
     opacity: 1;
}

.menuCity__name {
  position: relative;
  z-index: 1;
  display: inline-block;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.5rem, 0.8rem + 2.4vw, 3rem);
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--navy-900);
  padding-bottom: 0.16em;
  border-bottom: 3px solid transparent;
  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.35);
  transition: color 0.4s var(--ease), border-color 0.4s var(--ease);
}

.menuCity.is-active .menuCity__name {
  color: #fff;
  border-bottom-color: #fff;
  text-shadow: 0 1px 2px rgba(6, 34, 74, 0.35);
}

/* Columns wipe up as the menu opens. */
.menuCity {
  transform: translateY(3%);
  opacity: 0;
  transition: background-color 0.5s var(--ease), transform 0.6s var(--ease),
    opacity 0.6s var(--ease);
    text-align: center;
}

.siteMenu.is-open .menuCity {
  transform: none;
  opacity: 1;
  transition-delay: calc(0.1s + var(--i) * 0.08s);
}

/* ---- close ---- */

.siteMenu__close {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 2;
  display: grid;
  justify-items: center;
  grid-gap: 0.35em;
  gap: 0.35em;
  color: var(--ink-900);
  transition: transform 0.3s var(--ease), color 0.3s var(--ease);
}

.siteMenu__close:hover {
  transform: rotate(90deg);
  color: #000;
}

.siteMenu__close svg {
  width: 30px;
  height: 30px;
}

.siteMenu__close span {
  font-size: var(--fs-eyebrow);
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
}

.siteMenu__close:hover span {
  opacity: 0;
}

/* ---- narrow screens: panel on top, cities as strips below ---- */



@media (prefers-reduced-motion: reduce) {
  .siteMenu,
  .siteMenu li,
  .menuCity,
  .menuCity__media img {
    transition-duration: 0.01ms;
  }

  .siteMenu__close:hover {
    transform: none;
  }
}

/* ==================================================== Home banner (merged) ==
   The photograph (.bImg) and the brand screen (.image-container) are two
   layers of ONE section, matching the original `.homeBanner` template.

   Progressive enhancement — two presentations:

   BASE          both layers sit in normal flow, fully visible. This is what
                 renders before hydration, with JS off, on narrow screens and
                 under prefers-reduced-motion. Nothing is ever hidden by
                 default, so there is no flash of a blank hero.

   .is-pinned    added by usePinnedZoom when it takes over. The layers become
                 absolutely positioned on a sticky stage and `--p` (0 → 1)
                 drives the sequence:

                   --settle  p 0.00 → 0.35   photo eases out of its push-in
                   --wash    p 0.18 → 0.35   plate fades in over the photo,
                                             .bImg__headline fades out
                   --zoom    p 0.18 → 0.78   plate scale(4.5) → scale(1)
                   --reveal  p 0.60 → 0.78   .bannerText + .bottom fade up

   The reveal runs over the tail of the zoom and lands exactly as the mark
   settles. Retime by editing the four constants below — if you move --reveal's
   start, move `data-pin-reveal` in HomeBanner.jsx to match, since that is what
   gates visibility and pointer events.
   ========================================================================= */

.homeBanner {
  --p: 0;
  --settle: clamp(0, calc(var(--p) / 0.35), 1);
  --wash: clamp(0, calc((var(--p) - 0.18) / 0.17), 1);
  --zoom: clamp(0, calc((var(--p) - 0.18) / 0.6), 1);
  --reveal: clamp(0, calc((var(--p) - 0.6) / 0.18), 1);

  position: relative;
  background: var(--navy-900);
  color: #fff;
}

.homeBanner__stage {
  position: relative;
}

/* ---------------- layer 1: photograph ---------------- */

.bImg {
  position: relative;
  min-height: 100svh;
  display: flex;
  align-items: flex-end;
  overflow: hidden;
}

/* The <picture> wrapper only exists to carry the mobile <source>; it must not
   become the flex item itself. `display: contents` keeps the <img> laid out as
   though it were still a direct child — but it does NOT change selector
   matching, so every `.bImg > img` rule below names the wrapped img too. */
.bImg > picture {
  display: contents;
}

.bImg > img,
.bImg > picture > img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 40%;
  animation: bannerFadeIn 1.4s var(--ease) both;
}

@keyframes bannerFadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

.bImg__scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(
      100deg,
      rgba(6, 34, 74, 0.88) 0%,
      rgba(6, 34, 74, 0.35) 32%,
      rgba(6, 34, 74, 0) 58%
    ),
    linear-gradient(to top, rgba(4, 20, 45, 0.9) 0%, rgba(4, 20, 45, 0) 45%);
}

.bImg__body {
  position: relative;
  width: 100%;
  padding-bottom: clamp(4rem, 10vh, 9rem);
  padding-top: calc(var(--header-h) + var(--sp-6));
   padding-left:5%;
}

.bImg__headline {
  font-weight: 400;
  font-size: var(--fs-h1);
  line-height: 1.04;
  letter-spacing: -0.02em;
  color: #fff;
  text-wrap: balance;
}

.bImg__headline span {
  display: block;
  opacity: 0;
  transform: translateY(34px);
  animation: bannerLine 1s var(--ease) forwards;
}

.bImg__headline span:nth-child(1) { animation-delay: 0.25s; }
.bImg__headline span:nth-child(2) { animation-delay: 0.4s; }

@keyframes bannerLine {
  to { opacity: 1; transform: none; }
}

.bImg__cue {
  position: absolute;
  right: var(--gutter);
  bottom: clamp(2rem, 6vh, 4rem);
  display: grid;
  justify-items: center;
}

.bImg__cue span {
  width: 1px;
  height: 56px;
  background: linear-gradient(to bottom, rgba(255, 255, 255, 0.7), transparent);
  animation: cue 2.4s var(--ease) infinite;
}

@keyframes cue {
  0%, 100% { transform: scaleY(0.4); transform-origin: top; opacity: 0.4; }
  50% { transform: scaleY(1); transform-origin: top; opacity: 1; }
}

/* ---------------- layer 2: brand screen ---------------- */

.image-container {
  position: relative;
  min-height: 100svh;
  display: grid;
  grid-template-rows: 1fr auto;
  align-items: center;
  grid-gap: clamp(1.5rem, 5vw, 2.5rem);
  gap: clamp(1.5rem, 5vw, 2.5rem);
  padding-block: calc(var(--header-h) + var(--sp-5)) clamp(1.5rem, 4vh, 3rem);
  background: #0d3a72;
  overflow: hidden;
}

/* The <picture> wrapper only exists to carry the mobile <source>; it must not
   become the grid/flex item itself. */
.image-container picture {
  display: contents;
}

.image-container .img {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.bannerText,
.bottom {
  position: relative;
  z-index: 1;
  width: 100%;
}

.bannerText {
  display: grid;
  grid-template-columns: minmax(0, 1fr) min(200vh, 34vw) minmax(0, 1fr);
  align-items: center;
  grid-column-gap: clamp(1rem, 3vw, 3rem);
  column-gap: clamp(1rem, 3vw, 3rem);
}

.bannerText .left {
  justify-self: end;
  text-align: right;
}

.bannerText .left h2 {
  font-weight: 300;
  font-size: 55px;
  line-height: 1;
  letter-spacing: 1px;
}

/*
.bannerText .left h2 {
     color: transparent;
    background-image: url('https://images.unsplash.com/photo-1732535725600-f805d8b33c9c?q=80&w=1470&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D'); 
    background-size: 200%;  
    background-position: 0 50%;
    background-clip: text;
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    animation: animate-background 5s infinite alternate linear;
}

@keyframes animate-background {
    0% {
        background-position: 0 50%;
    }
    100% {
        background-position: 100% 50%;
    }
}
*/

.bannerText .left h2 span {
  display: block;
}

.bannerText .right {
    display: grid;
    justify-items: start;
    grid-gap: var(--sp-5);
    grid-gap: 19px;
    gap: 19px;
    max-width: 32ch;
    padding-left: 40px;
    padding-top: 164px;
        text-align: justify;
}
.bannerText .right .exbloretwoBtn{display: none;}

.bannerText .right p {
  font-size: var(--fs-body-sm);
  line-height: 1.55;
  color: rgba(255, 255, 255, 0.5);
    margin: 0 0 25px;
        text-align: justify;
    text-align-last: left;
    -webkit-hyphens: auto;
            hyphens: auto;
    overflow-wrap: normal;
}

/* ---- bottom strip ---- */

.bottom {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: end;
  grid-column-gap: clamp(1rem, 3vw, 3rem);
  column-gap: clamp(1rem, 3vw, 3rem);
  padding: 0 5%;
}

.bottom .years {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-3);
}

.bottom .years h3 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(2.6rem, 1.4rem + 4vw, 5rem);
  line-height: 0.82;
  color: var(--gold-500);
}

.bottom .years h3::after {
  content: "+";
  font-size: 0.3em;
  vertical-align: super;
  position: relative;
      top: -27px;
    right: -5px;
}

.bottom .years p {
  display: grid;
  font-size: var(--fs-eyebrow);
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  line-height: 1.4;
  color: rgba(255, 255, 255, 0.9);
  padding-top: 0.35em;
}

.bottom .locations {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: clamp(0.75rem, 2vw, 2rem);
  font-size: var(--fs-eyebrow);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.6);
  white-space: nowrap;
}

.bottom .scroll {
  justify-self: end;
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  font-size: var(--fs-eyebrow);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.75);
}

.bottom .scroll svg {
  width: 18px;
  height: 18px;
  animation: cueNudge 2.2s var(--ease) infinite;
}

/* The cue is an anchor into #ongoing — give it the affordance of one. */
.bottom a.scroll {
  cursor: pointer;
  transition: color 0.3s var(--ease);
}

.bottom a.scroll:hover,
.bottom a.scroll:focus-visible {
  color: #fff;
}

@keyframes cueNudge {
  0%, 100% { transform: translateY(-3px); opacity: 0.5; }
  50% { transform: translateY(3px); opacity: 1; }
}

/* ======================= enhanced: usePinnedZoom took over ================ */

.homeBanner.is-pinned .homeBanner__stage {
  position: -webkit-sticky;
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: hidden;
  isolation: isolate;
}

/* The photograph itself never fades — it stays at full opacity underneath and
   is simply covered by the brand plate as that washes in on top. */
.homeBanner.is-pinned .bImg {
  position: absolute;
  inset: 0;
  z-index: 0;
  min-height: 0;
}

.homeBanner.is-pinned .bImg > img,
.homeBanner.is-pinned .bImg > picture > img {
  scale: calc(1.16 - 0.16 * var(--settle));
  will-change: scale;
}

/* Only the headline hides on scroll, so it doesn't read through the crossfade
   while the brand copy is arriving. */
.homeBanner.is-pinned .bImg__headline {
  opacity: calc(1 - var(--wash));
  translate: 0 calc(-6vh * var(--wash));
  will-change: opacity, translate;
}

.homeBanner.is-pinned .image-container {
  position: absolute;
  inset: 0;
  z-index: 1;
  min-height: 0;
  gap: 0;
  background: none;
  /* inert until the copy is revealed — see .is-revealed below */
  pointer-events: none;
}

.homeBanner.is-pinned .image-container .img {
  opacity: var(--wash);
  scale: calc(4.5 - 3.5 * var(--zoom));
  will-change: opacity, scale;
}

.homeBanner.is-pinned .bannerText,
.homeBanner.is-pinned .bottom {
  opacity: var(--reveal);
  translate: 0 calc(24px * (1 - var(--reveal)));
  will-change: opacity, translate;
  /* Hidden content is also inert, so links can't be clicked or tabbed to
     during the photograph and zoom phases. usePinnedZoom adds .is-revealed
     at the `data-pin-reveal` threshold. */
  visibility: hidden;
}

.homeBanner.is-pinned.is-revealed .bannerText,
.homeBanner.is-pinned.is-revealed .bottom {
  visibility: visible;
  pointer-events: auto;
}

/* Mask wipe on the banner heading is driven by the pin, not the viewport
   observer — see the comment in HomeBanner.jsx. `.is-revealed` lands at the
   same moment `.bannerText` becomes visible, so the wipe is actually seen, and
   it rearms when the pin scrolls back out. */
.homeBanner.is-revealed .maskUp > * {
  transform: none;
  /* globals.css zeroes the transition on `.maskUp:not(.is-visible) > *` so the
     rearm is instant. This heading never receives `.is-visible`, so the
     duration has to be restored here or the wipe would snap. */
  transition-duration: 0.95s;
}

.homeBanner.is-revealed .maskUp > *:nth-child(2) { transition-delay: 0.09s; }
.homeBanner.is-revealed .maskUp > *:nth-child(3) { transition-delay: 0.18s; }
.homeBanner.is-revealed .maskUp > *:nth-child(4) { transition-delay: 0.27s; }
.homeBanner.is-revealed .maskUp > *:nth-child(5) { transition-delay: 0.36s; }

/* ---- bottom strip: staggered entrance ----------------------------------
   The strip's own fade is switched off and each part carries its own motion,
   so the years, the cities and the cue arrive in sequence rather than as one
   block. Driven by `.is-revealed` — the pin, not the viewport observer, for
   the same reason as the heading above.
   ----------------------------------------------------------------------- */

.homeBanner.is-pinned .bottom {
  opacity: 1;
  translate: none;
}

.homeBanner.is-pinned .bottom .years h3,
.homeBanner.is-pinned .bottom .years p span,
.homeBanner.is-pinned .bottom .locations span,
.homeBanner.is-pinned .bottom .scroll {
  opacity: 0;
  translate: 0 20px;
  transition: opacity 0.6s var(--ease), translate 0.6s var(--ease),
    scale 0.6s var(--ease);
}

/* The numeral also settles down in scale, so it reads as the anchor. */
.homeBanner.is-pinned .bottom .years h3 {
  scale: 1.14;
  transform-origin: left bottom;
}

.homeBanner.is-pinned.is-revealed .bottom .years h3,
.homeBanner.is-pinned.is-revealed .bottom .years p span,
.homeBanner.is-pinned.is-revealed .bottom .locations span,
.homeBanner.is-pinned.is-revealed .bottom .scroll {
  opacity: 1;
  translate: none;
  scale: 1;
}

.homeBanner.is-pinned.is-revealed .bottom .years h3 { transition-delay: 0.04s; }
.homeBanner.is-pinned.is-revealed .bottom .years p span:nth-child(1) { transition-delay: 0.16s; }
.homeBanner.is-pinned.is-revealed .bottom .years p span:nth-child(2) { transition-delay: 0.22s; }
.homeBanner.is-pinned.is-revealed .bottom .years p span:nth-child(3) { transition-delay: 0.28s; }

.homeBanner.is-pinned.is-revealed .bottom .locations span:nth-child(1) { transition-delay: 0.30s; }
.homeBanner.is-pinned.is-revealed .bottom .locations span:nth-child(2) { transition-delay: 0.38s; }
.homeBanner.is-pinned.is-revealed .bottom .locations span:nth-child(3) { transition-delay: 0.46s; }
.homeBanner.is-pinned.is-revealed .bottom .locations span:nth-child(4) { transition-delay: 0.54s; }
/* Any city added beyond the fourth still animates, just together. */
.homeBanner.is-pinned.is-revealed .bottom .locations span:nth-child(n + 5) { transition-delay: 0.58s; }

.homeBanner.is-pinned.is-revealed .bottom .scroll { transition-delay: 0.62s; }

 


/* ---- mobile brand screen (≤900px) -------------------------------------
   Layout: circle photo → 2-line headline → copy → 76+ → pill CTA → cities.
   Every size is a multiple of --u so the whole stack fits one 100svh stage
   (the pinned stage clips): --u is 1vw, shrunk on short screens so ~212u of
   content plus the dock clearance always fits.

   `.homeBanner.is-pinned` rules add the desktop scroll animation on top.
   ----------------------------------------------------------------------- */

.bannerText__body--m {
  display: none;
}

/* The circle is scaled up to 4.5x during the zoom. `clip` (unlike hidden)
   doesn't create a scroll container, so the sticky stage keeps working and
   iOS can't pan sideways into the overflow. */
.homeBanner {
  overflow-x: clip;
}

@media (max-width: 900px) {
  /* both must be clip: if html isn't `visible`, a body `overflow-x:hidden`
     turns body into a scroll container and the sticky stage stops sticking */
  html,
  html body {
    overflow-x: clip;
  }

  .homeBanner .image-container {
    --u: min(1vw, calc((100svh - 118px) / 214), 4.4px);
    justify-content: center;
    gap: 0;
    padding: 0;
    background: #0f2c68;
    isolation: isolate; 
  }

  /* gradient plate — its own layer so the pin can fade it in */
  .homeBanner .image-container::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background: #0a1d49;
  }

  /* 1 — circle photo */
  .homeBanner .image-container .img {
    order: 1;
    flex: none;
    width: calc(79 * var(--u));
    height: calc(79 * var(--u));
    border-radius: 50%;
    object-fit: cover;
    transform-origin: center;
  }

  /* 2 — headline: "Homes Built on Trust." / "Radiance Living Experience." */
  .homeBanner .image-container .bannerText .left {
    order: 2;
    margin-top: calc(5 * var(--u));
    text-align: center;
  }

  .homeBanner .image-container .bannerText .left h2 {
    font-size: calc(10 * var(--u));
    font-weight: 400;
    line-height: 1.1;
    letter-spacing: 0;
    white-space: nowrap;
    text-wrap: nowrap;
  }

  .homeBanner .image-container .bannerText .left h2 span {
    display: inline;
    margin-right: 0.22em;
  }

  .homeBanner .image-container .bannerText .left h2 span:nth-child(2)::after {
    content: ".\A";
    white-space: pre;
  }

  .homeBanner .image-container .bannerText .left h2 span:nth-child(4) {
    margin-right: 0;
  }

  .homeBanner .image-container .bannerText .left h2 span:nth-child(4)::after {
    content: ".";
  }

  /* 3 — copy (mobile text) */
  .homeBanner .image-container .bannerText__body {
    display: none;
  }

  .homeBanner .image-container .bannerText .right .bannerText__body--m {
    display: block;
    order: 3;
    max-width: 80%;
    margin: calc(3.5 * var(--u)) auto 0;
    font-size: 14px;
    line-height: 1.5;
    color: rgba(255, 255, 255, 0.82);
    text-wrap: balance;
  }

  /* 4 — 76+ */
  .homeBanner .image-container .bottom .years {
    order: 4;
    margin-top: calc(9 * var(--u));
    display: flex;
    align-items: flex-end;
    justify-content: center;
    gap: calc(5 * var(--u));
  }

  .homeBanner .image-container .bottom .years h3 {
    position: relative;
    font-size: 90px;
    line-height: 0.78;
    color: var(--gold-500);
    transform-origin: center bottom;
  }
.homeBanner.is-pinned .homeBanner__stage { height: 103svh;}
    .projects__tabs {
         margin: 0 0 20px;
    }
  .homeBanner .image-container .bottom .years h3::after {
    position: absolute;
    top: calc(-1 * var(--u));
    right: calc(-4.5 * var(--u));
    font-family: var(--font-body);
    font-size: calc(5 * var(--u));
    font-weight: 400;
    line-height: 1;
    vertical-align: baseline;
    color: rgba(255, 255, 255, 0.8);
  }

  .homeBanner .image-container .bottom .years p {
    padding: 0 0 calc(0.4 * var(--u));
    text-align: left;
    font-size: calc(3.4 * var(--u));
    font-weight: 500;
    letter-spacing: 0.06em;
    line-height: 1.3;
    color: rgba(255, 255, 255, 0.72);
  }

  /* 5 — pill CTA */
  .homeBanner .image-container .bannerText .right .exbloretwoBtn {
    order: 5;
    margin: calc(12 * var(--u)) auto 0;
    align-self: center;
    border-radius: 999px;
  }

  .homeBanner .image-container .exbloretwoBtn .btn {
    padding: calc(3.1 * var(--u)) calc(10.5 * var(--u));
    font-size: calc(3.3 * var(--u));
    font-weight: 700;
    letter-spacing: 0.08em;
    color: #fff;
  }

  /* 6 — cities */
  .homeBanner .image-container .bottom .locations {
    order: 6;
    display: flex;
    flex-wrap: nowrap;
    justify-content: center;
    align-items: center;
    gap: 0;
    margin-top: calc(8 * var(--u));
    font-size: calc(3.7 * var(--u));
    font-weight: 500;
    letter-spacing: 0.1em;
    color: rgba(255, 255, 255, 0.42);
    display: none;
  }

  .homeBanner .image-container .bottom .locations span + span::before {
    content: "";
    display: inline-block;
    width: 1px;
    height: 0.8em;
    margin: 0 calc(3.5 * var(--u));
    vertical-align: -0.05em;
    background: rgba(255, 255, 255, 0.35);
  }

  /* ---- pinned: same animation as desktop ----
     Mobile retimes the phases so the zoom-out fills the whole pin
     (scrolls 2 and 3) instead of a short middle slice. --reveal still
     starts at 0.6 to match data-pin-reveal. */
  .homeBanner.is-pinned {
    --settle: clamp(0, calc(var(--p) / 0.3), 1);
    --wash: clamp(0, calc(var(--p) / 0.15), 1);
    --zoom: clamp(0, calc(var(--p) / 0.85), 1);
    --reveal: clamp(0, calc((var(--p) - 0.6) / 0.3), 1);
  }

  .homeBanner.is-pinned .image-container {
    background: none;
  }

  .homeBanner.is-pinned .image-container::before {
    opacity: var(--wash);
  }

  .homeBanner.is-pinned .image-container .bannerText .left,
  .homeBanner.is-pinned .image-container .bannerText .right .bannerText__body--m,
  .homeBanner.is-pinned .image-container .bannerText .right .exbloretwoBtn {
    opacity: var(--reveal);
    translate: 0 calc(24px * (1 - var(--reveal)));
    will-change: opacity, translate;
  }

  /* cities join the staggered strip entrance */
  .homeBanner.is-pinned .image-container .bottom .locations span {
    opacity: 0;
    translate: 0 20px;
  }

  .homeBanner.is-pinned.is-revealed .image-container .bottom .locations span {
    opacity: 1;
    translate: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  /* The strip's staggered entrance is scoped to .is-pinned, which the hook
     never adds under reduced motion — but be explicit in case the class is
     present from a previous state. */
  .homeBanner .bottom .years h3,
  .homeBanner .bottom .years p span,
  .homeBanner .bottom .locations span,
  .homeBanner .bottom .scroll {
    opacity: 1;
    translate: none;
    scale: 1;
    transition: none;
  }

  .homeBanner .bottom::before {
    transform: scaleX(1);
    transition: none;
  }

  .bImg > img,
  .bImg > picture > img,
  .bImg__headline span {
    animation: none;
    opacity: 1;
    transform: none;
  }

  .bImg__cue span,
  .bottom .scroll svg {
    animation: none;
  }
}

/* ------------------------------------------------------------ Projects --
   Heading, city tabs and the horizontal project panels are one section.
   Switching a tab swaps the panels; the hooks re-measure on REMEASURE_EVENT.
   ------------------------------------------------------------------------- */

.projects {
  position: relative;
  background: var(--paper);
}

.projects__intro {
  position: relative;
  overflow: hidden;
  text-align: center;
  padding-block: clamp(3rem, 6vw, 6rem) clamp(2rem, 4vw, 3.5rem);
}

.projects__marquee {
  position: absolute;
  top: clamp(1rem, 3vw, 3rem);
  left: 0;
  width: 100%;
  overflow: hidden;
  pointer-events: none;
}

.projects__marquee span {
  display: inline-flex;
  white-space: nowrap;
  animation: marquee 20s linear infinite; /* was 42s */
}

.projects__marquee em {
  font-family: var(--font-body);
  font-style: normal;
  font-weight: 300;
  font-size: clamp(2.5rem, 1rem + 6vw, 6rem);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: rgba(12, 58, 108, 0.07);
  line-height: 1;
}

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

.projects__head {
  position: relative;
  display: grid;
  justify-items: center;
  grid-gap: var(--sp-3);
  gap: var(--sp-3);
  padding-top: clamp(2rem, 5vw, 4.5rem);
}

.projects__heading {
  font-size: clamp(1.9rem, 1rem + 4vw, 4rem);
  color: var(--navy-400);
}

.projects__tabs {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: clamp(1rem, 3vw, 3.5rem);
  margin-top: var(--sp-5);
  padding-block: var(--sp-4);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  width: min(760px, 100%);
}

.projects__tab {
  position: relative;
  display: inline-flex;
  align-items: flex-start;
  gap: 0.25em;
  font-family: var(--font-body);
  font-size: clamp(1.15rem, 0.9rem + 1.1vw, 2rem);
  font-weight: 400;
  color: var(--navy-400);
  opacity: 0.72;
  padding-bottom: var(--sp-2);
  transition: opacity 0.3s var(--ease);
}

.projects__tab:hover {
  opacity: 0.92;
}

.projects__tab::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -1px;
  width: 100%;
  height: 5px;
  background: var(--navy-500);
  border-radius: 3px;
  transform: scaleX(0);
  transform-origin: center;
  transition: transform 0.4s var(--ease);
}

.projects__tab.is-active {
  opacity: 1;
  font-weight: 700;
}

.projects__tab.is-active::after {
  transform: scaleX(1);
}

.projects__tab-count {
  font-size: 0.5em;
  font-weight: 600;
  line-height: 1;
  padding-top: 0.35em;
  opacity: 0.6;
  display: none;
}

.projects__empty {
  padding-block: clamp(3rem, 8vw, 6rem);
  text-align: center;
  font-size: var(--fs-lead);
  color: var(--ink-500);
  max-width: 46ch;
}

/* ---- projects awaiting figures / renders ---- */

.pending {
  position: relative;
  overflow: hidden;
  padding-block: clamp(3.5rem, 9vw, 7rem);
}

.pending--navy {
  background: var(--grad-navy-panel);
  color: #fff;
}

.pending--light {
  background: linear-gradient(180deg, #f6f8fb 0%, #eef3f9 100%);
  color: var(--ink-900);
}

.pending__inner {
  position: relative;
}

.pending__watermark {
  top: -8%;
  right: -4%;
  font-size: clamp(4rem, 12vw, 12rem);
  color: rgba(255, 255, 255, 0.06);
}

.pending--light .pending__watermark {
  color: rgba(12, 58, 108, 0.06);
}

.pending__body {
  position: relative;
  display: grid;
  justify-items: start;
  grid-gap: var(--sp-5);
  gap: var(--sp-5);
  max-width: 46ch;
}

.pending__lede {
  font-weight: 400;
}

.pending__note {
  font-size: var(--fs-body-sm);
  opacity: 0.8;
}

/* ------------------------------------------------------------- Project --
   One continuous horizontal ribbon, not viewport-sized panels:

     render → copy → location + figures → tower → statement → aerial

   Images are full height with automatic width (their `--ratio` gives the width
   before load, so useHorizontalScroll measures the track correctly on first
   paint). Text blocks have their own widths. The whole strip scrolls to its end.
   ------------------------------------------------------------------------- */

.project--navy { background: var(--grad-navy-panel); }
.project--light { background: linear-gradient(110deg, #eef3f9 0%, #f6f8fb 26%, #0c3a6c 46%, #072b57 100%); }

.ribbon {
  /* Block widths live here so the rule and the blocks can't drift apart. */
  --card-w: clamp(320px, 52vh, 620px);
  --facts-w: clamp(340px, 56vh, 660px);
  --statement-w: clamp(280px, 40vh, 460px);
  /* Height at which the continuous rule sits, and which the facts grid
     aligns its labels to. Nudge this one value to move both together. */
  --rule-top: 42%;

  position: relative;
  display: flex;
  align-items: stretch;
  height: 100%;
  color: #fff;
}

/*
   The continuous hairline. `width: 100%` resolves against the track, which is
   the full ribbon — so it runs 0 → 100% of the horizontal scroll and travels
   with it.

   It must not be oversized: the track is what useHorizontalScroll measures via
   `scrollWidth`, and an absolutely positioned child sticking out to the right
   would inflate that and stretch the section's scroll distance.
*/
.ribbon::before {
  content: "";
  position: absolute;
  z-index: 1;
  left: 0;
  top: var(--rule-top);
  width: 100%;
  height: 1px;
  background: linear-gradient(
    90deg,
    rgba(255, 255, 255, 0) 0%,
    rgba(255, 255, 255, 0.3) 6%,
    rgba(255, 255, 255, 0.3) 94%,
    rgba(255, 255, 255, 0) 100%
  );
  pointer-events: none;
}

.project--light .ribbon::before {
  background: linear-gradient(
    90deg,
    rgba(12, 58, 108, 0) 0%,
    rgba(12, 58, 108, 0.22) 6%,
    rgba(255, 255, 255, 0.3) 46%,
    rgba(255, 255, 255, 0.3) 94%,
    rgba(255, 255, 255, 0) 100%
  );
}

/* Content sits above the rule; the plates sit below it so it reads as one
   line running behind the imagery. */
.ribbon__card,
.ribbon__facts,
.ribbon__statement {
  position: relative;
  z-index: 2;
}

/* ---- imagery ---- */
.hscroll__wrap::before, .hscroll__wrap::after{display: none;}
.ribbon::before{display: none;}
.ribbon__plate {
  flex: 0 0 auto;
  position: relative;
  height: 100%;
  /* Width is resolved from the declared ratio, so the track measures correctly
     on first paint instead of reflowing once the image lands. */
  width: auto;
   margin: 0;
  overflow: hidden;
}
 .ribbon__plate.lastImg{left: -462px;}

/* A plate that carries a narrow-screen alternate wraps its img in <picture>
   (see Plate in ProjectShowcase.jsx). The wrapper is layout-neutral by
   `display: contents` — the img stays a direct child as far as the flex track
   and the mobile aspect-ratio box are concerned, so a plate with an alternate
   measures exactly like one without. An inline <picture> would instead add a
   baseline gap and break the track's width measurement. */
.ribbon__plate picture {
  display: contents;
}

.ribbon__plate img {
  display: block;
  height: 100%;
  width: auto;
  max-width: none;
  object-fit: cover;
}

/* Whole-plate link (see Plate in ProjectShowcase.jsx). Sits over the render
   and under anything the plate nests inside it, so a plate with its own CTA
   buttons keeps those working. */
.ribbon__plateLink {
  position: absolute;
  inset: 0;
  z-index: 3;
  cursor: pointer;
}

.ribbon__plateLink:focus-visible {
  outline: 2px solid var(--gold-500);
  outline-offset: -4px;
}

/* ---- plate flash -------------------------------------------------------
   A one-shot glint that fires as the rail carries a plate into frame, plus a
   short settle on the render behind it.

   Two earlier attempts drove this from a per-frame scroll value of their own.
   This one instead hangs off `.is-in`, the class useRibbonReveal already
   toggles for the ribbon cards — the same rig, the same trigger line, the
   same re-arm on the way back. One proven mechanism for the whole section
   rather than a second one running beside it.

   Everything is scoped to [data-ribbon-anim], which that hook sets per
   section, so without JavaScript the plates render plain and unanimated. */

.ribbon__flash {
  position: absolute;
  /* Over-tall so the skew never exposes a corner. */
  top: -10%;
  bottom: -10%;
  left: 0;
  z-index: 1;
  width: 34%;
  min-width: 120px;
  max-width: 380px;
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(
    100deg,
    transparent,
    rgba(255, 255, 255, 0.1) 30%,
    rgba(255, 255, 255, 0.55) 50%,
    rgba(255, 255, 255, 0.1) 70%,
    transparent
  );
  transform: translate3d(-110%, 0, 0) skewX(-14deg);
  display: none;
}

/* The bar is ~34% of the plate, so crossing it takes roughly 290% of the
   bar's own width — hence the end offset. */
[data-ribbon-anim] .ribbon__plate.is-in .ribbon__flash {
  animation: ribbonFlash 1.15s var(--ease) var(--dx, 0ms) 1;
}

@keyframes ribbonFlash {
  0% {
    opacity: 0;
    transform: translate3d(-110%, 0, 0) skewX(-14deg);
  }
  14%,
  86% {
    opacity: 1;
  }
  100% {
    opacity: 0;
    transform: translate3d(290%, 0, 0) skewX(-14deg);
  }
}
 

@keyframes ribbonSettle {
  from {
    transform: scale(1.05);
    filter: brightness(0.82) saturate(0.78);
  }
  to {
    transform: none;
    filter: none;
  }
}

/* On a near-white render a white glint reads as a smudge — warmed to gold. */
.project--light .ribbon__flash {
  background: linear-gradient(
    100deg,
    transparent,
    rgba(248, 166, 25, 0.1) 30%,
    rgba(248, 166, 25, 0.42) 50%,
    rgba(248, 166, 25, 0.1) 70%,
    transparent
  );
}

@media (prefers-reduced-motion: reduce) {
  [data-ribbon-anim] .ribbon__plate.is-in .ribbon__flash,
  [data-ribbon-anim] .ribbon__plate.is-in img {
    animation: none;
  }

  .ribbon__flash {
    display: none;
  }
}

/* ---- ribbon entrances -------------------------------------------------
   The content inside each ribbon card glides in as the rail carries the
   card into frame. The hidden state exists only under [data-ribbon-anim]
   — set per section by useRibbonReveal — so without JS the ribbon renders
   fully visible. `.is-in` is toggled on the cardOut from the track's real
   translation, and --dx spreads same-frame batches left → right.

   Rearming (class removed once the block leaves to the right) is instant:
   a transition on the way out would leave a half-played state waiting to
   be caught on the way back in. */

/* The cardOut itself (the navy field) never moves — only the content
   wrappers inside it glide up as the rail carries the card into frame.
   The data-reveal pieces inside continue their own finer stagger. */
[data-ribbon-anim] .ribbon__cardOut .ribbon__card,
[data-ribbon-anim] .ribbon__cardOut .ribbon__facts,
[data-ribbon-anim] .ribbon__cardOut .ribbon__factsStatement {
  opacity: 0;
  transform: translateY(clamp(24px, 3.5vh, 42px));
}

[data-ribbon-anim] .ribbon__cardOut.is-in .ribbon__card,
[data-ribbon-anim] .ribbon__cardOut.is-in .ribbon__facts,
[data-ribbon-anim] .ribbon__cardOut.is-in .ribbon__factsStatement {
  opacity: 1;
  transform: none;
  transition: opacity 0.8s var(--ease) var(--dx, 0ms),
    transform 1s var(--ease) var(--dx, 0ms);
}

/* Copy leads, facts follow, the statement lands last. */
[data-ribbon-anim] .ribbon__cardOut.is-in .ribbon__facts {
  transition-delay: calc(var(--dx, 0ms) + 140ms);
}

[data-ribbon-anim] .ribbon__cardOut.is-in .ribbon__factsStatement {
  transition-delay: calc(var(--dx, 0ms) + 260ms);
}

@media (prefers-reduced-motion: reduce) {
  [data-ribbon-anim] .ribbon__cardOut .ribbon__card,
  [data-ribbon-anim] .ribbon__cardOut .ribbon__facts,
  [data-ribbon-anim] .ribbon__cardOut .ribbon__factsStatement {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* Soften the joins where a render meets the navy field. */
.ribbon__plate--lead::after,
.ribbon__plate--aerial::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  width: clamp(60px, 8vh, 140px);
  pointer-events: none;
}

.ribbon__plate--lead::after {
  right: 0;
  background: linear-gradient(90deg, transparent, rgba(7, 43, 87, 0.85));
}

/* Light: the white→navy diagonal is baked into the exterior render, so the
   soft edge fades are off — the flat fields colour-match the jpg edges
   instead (#f1f1f1 left, #00407d right). */
.project--light .ribbon__plate--lead::before,
.project--light .ribbon__plate--lead::after,
.project--light .ribbon__plate--aerial::before {
  display: none;
}

.ribbon__plate--aerial::before {
  left: 0;
  /*background: linear-gradient(90deg, rgba(7, 43, 87, 0.85), transparent);*/
}

/* Copy + figures are wrapped together, so the pair is one flex item on the
   track. It must itself be a row, or the two blocks stack. */
.ribbon__cardOut {
  flex:auto;
  position: relative;
  z-index: 2;
  display: flex;
  align-items: stretch;
}

.ribbon__cardOut .exbloretwoBtn{margin-bottom: 20px;}

/* ---- copy block ---- */
.ribbon__cardOut{ display: flex;  background-image: linear-gradient(to right, #062b5b, #02407d);}
 .ribbon__cardOut::before{
   content:''; position: absolute;  top:404px;  left: 179px; width: 120%; height: 1px; background: #fff; opacity: 0.2;
   /* Scales 0 → 100% with the horizontal scroll; --hp is set per-frame by useHorizontalScroll. */
   transform: scaleX(var(--hp, 0));
   transform-origin: left center;
   will-change: transform;
  }

/* ---- light theme (Solitaire comp): copy on the white field, facts +
   statement share one navy card, CTAs ride the aerial. Field colours match
   the render's baked-in edges exactly. ---- */
.project--light .ribbon__cardOut--copy {
  background-image: none;
  background-color: #f1f1f1;
}

.project--light .ribbon__cardOut--copy::before {
  display: none; /* the progress line only reads on navy */
}

.project--light .ribbon__cardOut--facts {
  background-image: none;
  background-color: #00407d;
  flex-direction: column;
  align-items: flex-start;
  /* Comp is top-weighted: locus up top, stats row, statement below. */
  justify-content: flex-start;
  padding: clamp(2.5rem, 7vh, 4.5rem) clamp(2rem, 8vh, 5rem) clamp(2rem, 6vh, 4rem) 70px;
}

.project--light .ribbon__cardOut--facts::before {
  left: 0;
  width: 100%;
}

.project--light .ribbon__lede {
  color: var(--ink-900);
}

.project--light .ribbon__blurb {
  color: #5c718a;
}

/* Comp pill: one bordered button on the white field. */
.project--light .ribbon__card .btn--ghost-dark {
  background: transparent;
  border: 1px solid rgba(12, 58, 108, 0.35);
}

/* Stats read as one four-column row: 660 · 5.37 · bedrooms · sq. ft. */
.project--light .ribbon__facts {
  grid-template-columns: repeat(4, auto);
  grid-template-rows: auto auto auto;
  column-gap: clamp(2.5rem, 9vh, 8rem);
  row-gap: clamp(0.75rem, 2.5vh, 1.5rem);
  padding: 20px 0 0;
  text-align: left;
  justify-items: start;
}

.project--light .ribbon__locus {
  padding-bottom: clamp(2rem, 8vh, 4rem);
}
.project--solitaire,
.project--imperia {
    background: #02407d;
}
.project--solitaire .ribbon__cardOut--facts::before,
.project--imperia .ribbon__cardOut--facts::before {
    left: 0;
    width: 180%;  top: 260px;
}
.project--solitaire  .ribbon__cardOut--copy,
.project--imperia  .ribbon__cardOut--copy {
     padding: 0 0 0 8%;
}

.project--solitaire  .ribbon__cardOut--copy .exbloretwoBtn > .btn + .btn::before,
.project--imperia  .ribbon__cardOut--copy .exbloretwoBtn > .btn + .btn::before {
     background: #000;
}
.project--solitaire .ribbon__watermark,
.project--imperia .ribbon__watermark {  left: 20%;}
.project--solitaire .ribbon__statSmall,
.project--imperia .ribbon__statSmall {
  grid-row: 3;
  padding-top: 0;
  align-self: center;
  width:200px;
}
.project--solitaire .ribbon__statValue,
.project--imperia .ribbon__statValue {
    width: 160px;
}
.project--solitaire .ribbon__cardOut--facts,
.project--imperia .ribbon__cardOut--facts {  margin: 0 0 0 -531px;  background: transparent; padding: 65px 0 0 320px;}
.project--solitaire .ribbon__facts,
.project--imperia .ribbon__facts {
    margin: 0 0 200px;
}
.project--solitaire .ribbon__factsStatement h3,
.project--imperia .ribbon__factsStatement h3 { padding: 0 0 0 320px;
    color: #fff;
    font-size:60px;
    font-family: "D-DIN Condensed", "Arial Narrow", "Helvetica Neue Condensed", "Roboto Condensed", sans-serif-condensed, sans-serif;
    line-height : 1;
}

   .project--solitaire .ribbon__plate.lastImg,
.project--imperia .ribbon__plate.lastImg {
    left: -80px; 
}

.project--solitaire .lockup--art,
.project--imperia .lockup--art {  max-width: 260px;}

.project--solitaire .ribbon__cardOut--copy .exbloretwoBtn,
.project--imperia .ribbon__cardOut--copy .exbloretwoBtn,
.project--solitaire .ribbon__cardOut--copy .btn--duo,
.project--imperia .ribbon__cardOut--copy .btn--duo {
     background-image: linear-gradient(to right, #9dc1e5, transparent);
}
.project--solitaire .ribbon__cardOut--copy .exbloretwoBtn > .btn,
.project--imperia .ribbon__cardOut--copy .exbloretwoBtn > .btn {
   color: #050a4c; 
}

/* CTAs overlaid bottom-right of the aerial render. */
/* Above .ribbon__plateLink, so the plate's own buttons keep their clicks
   while the rest of the render carries the project link. */
.ribbon__plate-cta {
  position: absolute;
  right: 170px;
  bottom: 87px;
  z-index: 4;
  display: grid;
  justify-items: end;
  grid-gap: clamp(1rem, 3vh, 1.75rem);
  gap: clamp(1rem, 3vh, 1.75rem);
  color: #fff;
}

.ribbon__card {
  flex: 0 0 auto;
  position: relative;
  display: flex;
  flex-direction: column;
  /*justify-content: center;*/
  height: 100%;
  gap: 10px;
  padding: 200px 0 0;
 }
 .project--solitaire .ribbon__cardOut--copy .exbloretwoBtn, .project--imperia .ribbon__cardOut--copy .exbloretwoBtn, .project--solitaire .ribbon__cardOut--copy .btn--duo, .project--imperia .ribbon__cardOut--copy .btn--duo {
    background-image: linear-gradient(to right, #f6800e, #f9a51a, #f6800e);
}
.project--solitaire .ribbon__cardOut--copy .exbloretwoBtn > .btn, .project--imperia .ribbon__cardOut--copy .exbloretwoBtn > .btn {
    color: #fff;
}
.project--solitaire .ribbon__cardOut--copy .exbloretwoBtn > .btn + .btn::before, .project--imperia .ribbon__cardOut--copy .exbloretwoBtn > .btn + .btn::before {
    background: #fff;
}

.hscroll .pinIcon {  color: #f8a619;  }

/* On the light theme the copy block sits on the pale half of the gradient, so
   it inverts — the facts and statement stay on navy and keep white. */
.project--light .ribbon__card {
  color: var(--ink-900);
}
.hscroll__wrap::before, .hscroll__wrap::after {
    content: "";
    position: absolute;
    left: 0;
    top: 41.8%;
}
.ribbon__watermark {
  top: 4%;
    left: 0;
    font-size: 172px;
    color: #fff;
    letter-spacing: 0.02em;
    font-family: "D-DIN Condensed", "Arial Narrow", "Helvetica Neue Condensed", "Roboto Condensed", sans-serif-condensed, sans-serif;
    font-weight: 400;
    opacity: 0.02;
}

/* On light the watermark rides the navy facts card, so it stays white. */
.project--light .ribbon__watermark {
  color: #fff;
  opacity: 0.05;
}

/* maskUp slides direct children; they must be block-level for transform. */
.ribbon__lede > span,
.pending__lede > span {
  display: block;
}

.ribbon__lede {
   font-weight: 400;
    color: #e5eaef;
    font-size: 38px;
    font-family: "D-DIN Condensed", "Arial Narrow", "Helvetica Neue Condensed", "Roboto Condensed", sans-serif-condensed, sans-serif;
    margin: 0 0 10px;
 
  }
  
.ribbon__blurb {
      max-width: 30ch;
    font-size: var(--fs-body-sm);
    margin: 0 0 20px;
    color: #809bb7;
}

.ribbon__walkthrough {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  font-size: var(--fs-eyebrow);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  line-height: 1.35;

  /*
    This is an <a> when the walkthrough is a link and a <button> when it opens
    the popup player, so the UA button chrome is cleared here rather than in a
    second rule. font-family only — the size, weight, spacing and line-height
    above are deliberate and `font: inherit` would wipe them.
  */
  -webkit-appearance: none;
     -moz-appearance: none;
          appearance: none;
  border: 0;
  background: none;
  padding: 0;
  margin: 0;
  color: inherit;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
  opacity: 1;
    transform: inherit;
}

/* Light-theme ribbons carry their walkthrough on the aerial render
   (.ribbon__plate-cta), which is desktop-only. ProjectShowcase renders a second
   walkthrough inside the copy card for those projects; it is off here so the
   desktop ribbon is unchanged, and switched on in the mobile blocks below. */
.ribbon__walkthrough--mobile {
  display: none;
}

.ytIcon {
  width: 42px;
  height: 30px;
  flex: none;
  filter: drop-shadow(0 4px 10px rgba(0, 0, 0, 0.25));
}

.pinIcon {
  width: 58px;
   color: #0c4e81;
  flex: none;
}

.pinIcon--sm {
  width: 1em;
  height: 1em;
  display: inline-block;
  vertical-align: -0.15em;
}

/* ---- location + figures ---- */
/*
   Four-row grid so the labels end exactly on the ribbon's continuous rule:

     row 1   locus, bottom-aligned
     row 2   stat labels, bottom-aligned — ends at --rule-top
     ─────   the rule (drawn by .ribbon::before)
     row 3   big values
     row 4   the two small figures
*/

.ribbon__facts {
  flex: 0 0 auto;
  width:auto;
  display: grid;
  grid-template-columns: 1fr 1fr;
  /*grid-template-rows: calc(var(--rule-top) - 2.6em) 2.7em auto auto;*/
  grid-column-gap: clamp(1rem, 3vh, 2.5rem);
  column-gap: clamp(1rem, 3vh, 2.5rem);
  grid-row-gap: clamp(0.5rem, 1.5vh, 1rem);
  row-gap: clamp(0.5rem, 1.5vh, 1rem);
  align-content: start;
      padding: 200px 0 0 70px;
  text-align: center;
}

.ribbon__locus {
  grid-column: 1 / -1;
  grid-row: 1;
  align-self: end;
  display: flex;
  align-items: center;
  gap: 0;
    padding-bottom: 105px;
        text-align: left;
}

.ribbon__locus span {
  display: grid;
  line-height: 1.1;
}

.ribbon__locus strong {
  font-size: 45px;
  font-weight: 400;
    line-height: 1;
    font-family: "D-DIN Condensed", "Arial Narrow", "Helvetica Neue Condensed", "Roboto Condensed", sans-serif-condensed, sans-serif;
}

.ribbon__locus em {
  font-style: normal;
  font-size:11px;
  letter-spacing: 1px;
  text-transform: uppercase;
  opacity: 1;
}

.ribbon__statLabel {
  grid-row: 2;
    align-self: end;
    padding-bottom: 0;
    font-size: 12px;
    font-weight: 500;
    letter-spacing: 1px;
    text-transform: uppercase;
}

.ribbon__statValue,
.ribbon__statSmall {
  display: grid;
  grid-gap: 0.35em;
  gap: 0.35em;
}

.ribbon__statValue {
  grid-row: 3;
  padding-top: 0;
}

.ribbon__statSmall {
  grid-row: 4;
  padding-top: clamp(1rem, 4vh, 3rem);
}

.ribbon__statValue b,
.ribbon__statSmall b {
  font-family: var(--font-display);
  font-weight: 400;
  color: var(--gold-500);
  line-height: 0.9;
}

.ribbon__statValue b {
  font-size: 100px;
}

.ribbon__statSmall b {
  font-size: 48px;
}

.ribbon__statValue em,
.ribbon__statSmall em {
  font-style: normal;
  font-size: 16px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  opacity: 0.9;
}

/* ---- closing statement ---- */

.ribbon__statement {
  flex: 0 0 auto;
  width:auto;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  align-items: flex-start;
  gap: 15px;
  padding:130px 0 0 70px;
}
  .ribbon__statement h3{ 
     color: #02062c;
    font-size: 42px;
    font-family: "D-DIN Condensed", "Arial Narrow", "Helvetica Neue Condensed", "Roboto Condensed", sans-serif-condensed, sans-serif;
    line-height: 1;
    }

.ribbon__statement-text span {
  display: block;
  font-weight: 400;
}

.ribbon__statement .exbloretwoBtn {
    background-image: linear-gradient(to right, #f6800e, #f9a51a, #f6800e);
}
.ribbon__statement .exbloretwoBtn a{
    color: #fff;
    background-image: linear-gradient(90deg, rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.05) 77%);
}
.ribbon__statement .exbloretwoBtn button{ 
    color: #fff;
 }
/* ---- narrow screens: the ribbon becomes a stack ---- */

/* -------------------------------------------------------------- Legacy -- */

.legacy {
    position: relative;
    overflow: hidden;
    min-height: 100%;
    padding: 80px 0 0;
    background-position: center -220px;
    background-repeat: no-repeat;
}

/* Family cutout: bottom-anchored and centred, sized as a share of the section
   rather than in fixed pixels, so it tracks the room photo at any width. */
.legacy__media {
    position: absolute;
    z-index: 1;
   left: 51%;
    top: 19%;
    transform: translateX(-51%);
    width: auto;
    height: 74%;
    pointer-events: none;
    z-index: 10;
}

.legacy__media img {
  display: block;
  width: auto;
  height: 100%;
  max-width: none;
  object-fit: contain;
  object-position: bottom center;
}

/* The <picture> wrapper only exists to carry the narrow-screen <source>; it
   must not become a box of its own, or the img's `height: 100%` would resolve
   against it instead of .legacy__media. */
.legacy__media picture {
  display: contents;
}

/* Copy sits above the cutout. */
.legacy__inner {
  position: relative;
  z-index: 2;
  display: grid;
  grid-gap: clamp(2.5rem, 6vw, 5rem);
  gap: clamp(2.5rem, 6vw, 5rem);
}

.legacy__headline {
  font-weight: 400;
  font-size: 50px;
  line-height: 1.16;
  letter-spacing: -0.015em;
 
}

/* Each line is the maskUp slide unit; tone runs stay inline within it. */
.legacy__headline-line {
  display: block;
}

.legacy__headline--light { color: #fff; }
.legacy__headline--gold { color: var(--gold-500); }

/* Traced ring, centred on the cutout the way the comp has it — positioned from
   its own centre so it stays locked to the family at any width. */
.legacy__arc {
  position: absolute;
  left: 43%;
  top: 52%;
  transform: translate(-50%, -50%);
  width: min(560px, 29vw);
  aspect-ratio: 985 / 1058;
  z-index: 1;
  pointer-events: none;
  overflow: visible;
}

/* The generic [data-reveal] fade would slide the mark — the draw is the
   animation here, so the svg itself stays put and fully opaque. */
.legacy__arc[data-reveal] {
    opacity: 0.5;
    transform: translate(-48%, -50%);
}

/* Each traced contour hides behind a full-length dash (pathLength=1) and
   draws itself while the section is on screen. non-scaling-stroke keeps the
   hairline weight constant at any rendered size. */
.legacy__arc {
  /* One place to retime the loop. --arc-draw is the visible draw, --arc-hold
     the pause at full length, --arc-step the stagger between contours. */
  --arc-draw: 1.8s;
  --arc-hold: 1.6s;
  --arc-step: 0.15s;
}

/* Shared by every mounting of LegacyMark — the homepage Legacy band and the
   About page's Why Choose ring. Placement and the animation itself are scoped
   to each wrapper (.legacy__arc here, .why__arc in about.css). */
/* The C silhouette behind the contours — transparent unless a wrapper opts in
   (.why__arc does; the homepage mark stays as pure outlines). */
.arcMark__fill {
  fill: none;
  stroke: none;
}

.arcMark__line {
  fill: none;
  stroke: #d1b48c;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 1 1;
  stroke-dashoffset: 1;
}

/*
   Draw in from the head, hold at full length, then let the dash keep travelling
   to -1 so the line retracts from the same end it entered — one continuous
   chase rather than a pop back to empty.

   Percentages are derived from the durations above via calc() on the delay, so
   retiming only means touching the two custom properties.
*/
@keyframes legacyArcTrace {
  0%   { stroke-dashoffset: 1; }
  38%  { stroke-dashoffset: 0; }
  62%  { stroke-dashoffset: 0; }
  100% { stroke-dashoffset: -1; }
}

.legacy__arc.is-visible .legacy__arcLine {
  animation: legacyArcTrace calc(var(--arc-draw) * 2 + var(--arc-hold))
    cubic-bezier(0.22, 0.61, 0.21, 1) infinite;
}

/* Slight stagger so the contours ripple rather than move as one. */
.legacy__arc.is-visible .legacy__arcLine:nth-child(3) { animation-delay: calc(var(--arc-step) * 1); }
.legacy__arc.is-visible .legacy__arcLine:nth-child(4) { animation-delay: calc(var(--arc-step) * 2); }
.legacy__arc.is-visible .legacy__arcLine:nth-child(5) { animation-delay: calc(var(--arc-step) * 3); }
.legacy__arc.is-visible .legacy__arcLine:nth-child(6) { animation-delay: calc(var(--arc-step) * 4); }
.legacy__arc.is-visible .legacy__arcLine:nth-child(7) { animation-delay: calc(var(--arc-step) * 5); }
.legacy__arc.is-visible .legacy__arcLine:nth-child(8) { animation-delay: calc(var(--arc-step) * 6); }

/* Off-screen the loop stops and the mark rearms empty, so re-entering starts a
   clean pass instead of resuming mid-cycle. */
.legacy__arc:not(.is-visible) .legacy__arcLine {
  animation: none;
  stroke-dashoffset: 1;
}

/* A looping ambient animation is exactly what this opts out of — draw once and
   leave it at full length. */
@media (prefers-reduced-motion: reduce) {
  .legacy__arc.is-visible .legacy__arcLine {
    animation: none;
    stroke-dashoffset: 0;
  }
}

.legacy__stats {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-gap: clamp(2rem, 10vw, 10rem) clamp(2rem, 30vw, 34rem);
    grid-gap: clamp(2rem, 9vw, 8rem) clamp(2rem, 30vw, 34rem);
    gap: clamp(2rem, 9vw, 8rem) clamp(2rem, 30vw, 34rem);
    max-width: 100%;
    padding: 0 48px 223px;
}
.legacyStat {
  display: flex;
   align-items: flex-end;
  gap: var(--sp-4);
}

.legacyStat__figure {
  display: inline-flex;
  align-items: flex-start;
  font-family: var(--font-display);
  color: var(--gold-500);
  line-height: 0.85;
}

.legacyStat__num {
  font-size: 140px;
  font-weight: 400;
}

.legacyStat__unit {
  font-size: clamp(1.4rem, 0.9rem + 1.8vw, 2.4rem);
  align-self: flex-end;
  font-weight: 400;
  top: -7px;
    position: relative;
}

.legacyStat__sup {
  font-size: clamp(1rem, 0.7rem + 1vw, 1.5rem);
  line-height: 1;
}

.legacyStat__label {
  display: grid;
  font-size: var(--fs-body-sm);
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  line-height: 1.35;
  padding-top: 0.6em;
  color: rgba(255, 255, 255, 0.92);
}


/* ------------------------------------------------------------ Timeline -- */
/*
   Journey Wall.

   The comp is a single 4467 × 1282 artboard: a navy intro panel 615 wide, then
   a 3852-wide rail. Rather than re-flow it, the rail is reproduced at scale —
   `--u` is one comp pixel expressed against the pinned viewport height, and
   every position and type size in here is `comp px × --u`. Coordinates come
   from data/journeyWall.js, measured off the artboard.

   The wave itself is the one part that can't be rebuilt from the repo's assets,
   so it ships as a raster strip (/media/journey-wave.jpg) masked down to the
   photo band — the comp's baked-in text is stripped out, and every year, rule
   and dot on top of it is live DOM.
*/

.timeline {
  /* One comp pixel. The track is inset from the wrap by the progress strip, so
     the rail's height is the viewport less that. */
  --u: calc((100vh - var(--progress-h)) / 1282);

  /*
     Column measure, in comp pixels, shared by every milestone.

     The comp's own columns vary (210 → 310), but matching them per-item is a
     trap: the site's body face doesn't wrap where the comp's did, so copying
     the widths just moves the overflow around. Instead every column gets the
     same measure, chosen to fit the tightest same-row gap on the wall —
     2008 → 2009–2015 at 338 comp px. 300 + the 26 indent clears it, and the
     bottom row's tightest gap (409) has room to spare, so blocks can't run
     into their neighbours no matter how the text wraps.
  */
  --col: 300;

  /*
     Global type multiplier. Every size below is comp px × --u × --tscale, so if
     the rendered face sits heavier than the comp's and blocks run long, nudge
     this one value down rather than retuning sizes individually.
  */
  --tscale: 1;

  background: #fff;
}

.timeline__intro {
  flex: 0 0 calc(615 * var(--u));
  width: calc(615 * var(--u));
  height: 100vh;
  background: var(--grad-navy-panel);
  color: #fff;
  display: grid;
  align-items: center;
}

.timeline__intro-inner {
  padding-inline: calc(60 * var(--u));
  display: grid;
  grid-gap: calc(46 * var(--u));
  gap: calc(46 * var(--u));
}

.timeline__heading {
  font-weight: 400;
  font-size: calc(78 * var(--u));
  line-height: 1.06;
  letter-spacing: -0.02em;
}

.timeline__heading span {
  display: block;
}

.timeline__heading-accent {
  color: var(--gold-500);
  font-weight: 700;
}

.timeline__blurb {
  font-size: calc(25 * var(--u));
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.82);
}

/* Width is the comp ratio, so the rail is exactly as long as the artboard. */
.timeline__rail {
  flex: 0 0 calc(3852 * var(--u));
  width: calc(3852 * var(--u));
  height: 100%;
  position: relative;
  overflow: visible;
}

.timeline__wave {
  position: absolute;
  left: 0;
  top: 0;
  width: 102%;
  height: auto;
  max-width: none;
  object-fit: fill;
  -webkit-user-select: none;
     -moz-user-select: none;
          user-select: none;
  pointer-events: none;
}

/* The slider's arrows belong to the mobile fallback only — above 900px the
   list is the absolutely-placed wall and there is nothing to page. */
.timeline__nav {
  display: none;
}

.timeline__list {
  position: absolute;
  inset: 0;
  list-style: none;
  margin: 0;
  padding: 0;
}

/* --x / --y / --w are unitless comp pixels set inline by Milestones.jsx. */
.milestone {
  position: absolute;
  left: calc(var(--x) * var(--u));
  top: calc(var(--y) * var(--u));
  /* Columns sit 400 comp px apart per row; cap the measure to that so a
     short viewport can't run one column's copy into the next. */
  width: min(280px, calc(400 * var(--u)));
  padding-right: 28px;
}

.milestone__body {
  padding-left: calc(26 * var(--u));
  /* A long unbroken token (a project name, a URL) would otherwise push the
     column past its measure and into the next milestone. */
  overflow-wrap: break-word;
}

/* A stacked milestone (2019 under 2016) flows below its host rather than being
   pinned, so the pair grows apart instead of into each other. */
.milestone__body + .milestone__body {
  margin-top: calc(30 * var(--u));
}

/* The connector runs the full measured span from the dot to the wave edge.
   --l1/--l2 are canvas-absolute, so they're offset back against --y. */
.milestone__stem {
  position: absolute;
  left: 0;
  top: calc((var(--l1) - var(--y)) * var(--u));
  height: calc((var(--l2) - var(--l1)) * var(--u));
  width: 1px;
  background: rgba(27, 90, 153, 0.55);
}

.milestone__stem i {
  position: absolute;
  left: 50%;
  width: calc(17 * var(--u));
  height: calc(17 * var(--u));
  transform: translateX(-50%);
  border-radius: 50%;
  background: #1b5a99;
}

/* The dot caps the outer end — top when the block hangs above the wave. */
.milestone__stem i { bottom: calc(-8 * var(--u)); }
.milestone__stem--up i { bottom: auto; top: calc(-8 * var(--u)); }

.milestone__year {
  display: block;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 40px;
  line-height: 0.74;
  color: var(--gold-500);
}

.milestone__title {
   font-weight: 700;
  font-size: 18px;
  line-height: 1.02;
  color: #26608e;
  margin: calc(14 * var(--u)) 0 0;
  max-width: 85%;
}

.milestone__text,
.milestone__note {
  font-size: calc(23 * var(--u));
  line-height: 1.15;
  color: var(--ink-700);
  margin: calc(25 * var(--u)) 0 0;
  max-width: 85%;
}

.milestone__note strong {
  display: block;
  color: var(--ink-900);
}

/* Foot-anchored column (see Milestones.jsx): the list is exactly 1282 comp px
   tall, so the foot sits at comp y = --b. The stem runs from the text top
   (its dot) down to the wave edge at --l2. */
.milestone--anchored {
  top: auto;
  bottom: calc((1282 - var(--b)) * var(--u));
}

.milestone--anchored .milestone__stem {
  top: 0;
  height: auto;
  bottom: calc((var(--b) - var(--l2)) * var(--u));
}

/* Per-column nudges now live in data/journeyWall.js (they were nth-child
   overrides here, which broke whenever the milestone list changed). */

.milestone__points {
  list-style: none;
  padding: 0;
}

.milestone__points li {
  position: relative;
  padding-left: 0.9em;
}

.milestone__points li + li {
  margin-top: 0.3em;
}

.milestone__points li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.5em;
  width: 0.34em;
  height: 0.34em;
  border-radius: 50%;
  background: var(--gold-500);
}

.milestone__tagline {
  font-weight: 700;
  color: #26608e;
}
    

/* ---------------------------------------------- Journey Wall — reveal --

   Each milestone builds itself in the order the eye would read it: the
   connector draws out of the wave, the dot lands on its end, then the year,
   title and body lift in behind it. `.is-in` is toggled by useRailReveal from
   the rail's own translation, so the sequence starts when the track has
   genuinely carried the column into frame — not when an observer's shrunken
   root happens to clip it.

   Everything is gated on [data-rail-anim], which the hook sets on mount. Before
   hydration, or with JS off, none of the hiding applies and the wall reads as
   plain static content.
*/

.timeline[data-rail-anim] .milestone__stem {
  transform: scaleY(0);
  /* The stem grows *out of the wave*, so the fixed end is whichever end meets
     the photo band — the opposite end from the dot. */
  transform-origin: 50% 0;
  transition: transform 620ms cubic-bezier(0.22, 1, 0.36, 1);
  transition-delay: var(--dx, 0ms);
}

.timeline[data-rail-anim] .milestone__stem--up {
  transform-origin: 50% 100%;
}

.timeline[data-rail-anim] .milestone.is-in .milestone__stem {
  transform: scaleY(1);
}

/* The dot lands once the line has nearly finished drawing, with a touch of
   overshoot so it reads as arriving rather than fading up. */
.timeline[data-rail-anim] .milestone__stem i {
  transform: translateX(-50%) scale(0);
  opacity: 0;
  transition: transform 420ms cubic-bezier(0.34, 1.56, 0.64, 1),
    opacity 200ms linear;
  transition-delay: calc(440ms + var(--dx, 0ms));
}

.timeline[data-rail-anim] .milestone.is-in .milestone__stem i {
  transform: translateX(-50%) scale(1);
  opacity: 1;
}

/* Copy lifts in behind the dot. Steps of ~90ms: enough to read as a cascade,
   short enough that the whole block has settled before the next column
   arrives at the trigger line. */
.timeline[data-rail-anim] .milestone__year,
.timeline[data-rail-anim] .milestone__title,
.timeline[data-rail-anim] .milestone__text,
.timeline[data-rail-anim] .milestone__note {
  opacity: 0;
  transform: translateY(calc(22 * var(--u)));
  transition: opacity 560ms ease, transform 640ms cubic-bezier(0.22, 1, 0.36, 1);
  /* --d is the within-column cascade (year → title → body). --dx is set by
     useRailReveal only when several columns cross the trigger on the same frame
     — the opening screenful — so those fan out left-to-right instead of
     arriving as one slab. */
  transition-delay: calc(var(--d, 0ms) + var(--dx, 0ms));
}

.timeline[data-rail-anim] .milestone__year { --d: 300ms; }
.timeline[data-rail-anim] .milestone__title { --d: 390ms; }
.timeline[data-rail-anim] .milestone__text { --d: 480ms; }
.timeline[data-rail-anim] .milestone__note { --d: 570ms; }

/* A stacked milestone (2019 riding under 2016) is a second reading beat, so its
   block follows the host's rather than racing it. */
.timeline[data-rail-anim] .milestone__body + .milestone__body .milestone__year { --d: 560ms; }
.timeline[data-rail-anim] .milestone__body + .milestone__body .milestone__title { --d: 650ms; }
.timeline[data-rail-anim] .milestone__body + .milestone__body .milestone__text { --d: 740ms; }
.timeline[data-rail-anim] .milestone__body + .milestone__body .milestone__note { --d: 830ms; }

.timeline[data-rail-anim] .milestone.is-in .milestone__year,
.timeline[data-rail-anim] .milestone.is-in .milestone__title,
.timeline[data-rail-anim] .milestone.is-in .milestone__text,
.timeline[data-rail-anim] .milestone.is-in .milestone__note {
  opacity: 1;
  transform: none;
}

/* Leaving is not the entrance in reverse — a column sliding off the left edge
   should just drop away, not play a 900ms cascade backwards at the same time
   the next one is arriving. */
.timeline[data-rail-anim] .milestone:not(.is-in) .milestone__stem,
.timeline[data-rail-anim] .milestone:not(.is-in) .milestone__stem i,
.timeline[data-rail-anim] .milestone:not(.is-in) .milestone__year,
.timeline[data-rail-anim] .milestone:not(.is-in) .milestone__title,
.timeline[data-rail-anim] .milestone:not(.is-in) .milestone__text,
.timeline[data-rail-anim] .milestone:not(.is-in) .milestone__note {
  transition-duration: 200ms;
  transition-delay: 0ms;
}

@media (prefers-reduced-motion: reduce) {
  .timeline[data-rail-anim] .milestone__stem,
  .timeline[data-rail-anim] .milestone__stem i,
  .timeline[data-rail-anim] .milestone__year,
  .timeline[data-rail-anim] .milestone__title,
  .timeline[data-rail-anim] .milestone__text,
  .timeline[data-rail-anim] .milestone__note {
    transform: none;
    transition: opacity 240ms linear;
    transition-delay: 0ms;
  }

  .timeline[data-rail-anim] .milestone__stem { opacity: 0; }
  .timeline[data-rail-anim] .milestone.is-in .milestone__stem { opacity: 1; }
  .timeline[data-rail-anim] .milestone__stem i { transform: translateX(-50%); }
}

/* Stacked layout has no rail to ride, so the reveal is off entirely — the hook
   marks every milestone `.is-in` up front and these resets make sure nothing
   transitions on the way there. */


/* ---------------------------------------------------------- Commitment -- */

.commit {
    background-image: url("/media/commitment-family.jpg");
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  padding-top: clamp(3rem, 7vw, 6rem);
padding: 80px 0 0;
}

.commit__head {
  text-align: center;
  display: grid;
  grid-gap: var(--sp-2);
  gap: var(--sp-2);
  margin-bottom: 20px;
 
}

.commit__title span {
  display: block;
}

.commit__sub {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1rem, 0.85rem + 0.7vw, 1.5rem);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-700);
  display: none;
}

.commit__stage {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  color: #fff;
  padding-block: clamp(3rem, 8vw, 7rem);

  /* Timings for the left-to-right wipe. The ring leads and the photograph
     follows one beat behind, so the two depths read as a single edge crossing
     the stage. These four values are the whole tuning surface. */
  --wipe-dur: 1050ms;
  --wipe-ease: cubic-bezier(0.22, 1, 0.36, 1);
  --wipe-lead: 0ms;
  --wipe-follow: 200ms;
}

/* The generic [data-reveal] rule fades and lifts the element it is placed on.
   Here the attribute is only wanted for its `.is-visible` bookkeeping — the
   stage itself must not move, or the whole navy band would slide. Same
   neutralising trick .maskUp[data-reveal] uses in globals.css. */
.commit__stage[data-reveal] {
  opacity: 1;
  transform: none;
  transition: none;
}

/* Rearming has to be instant. Left to transition out, the wipe would play
   backwards as the section leaves and could be caught mid-retreat on the way
   back in — the same reason globals.css zeroes the duration on
   [data-reveal]:not(.is-visible). */
.commit__stage:not(.is-visible) .commit__mark,
.commit__stage:not(.is-visible) .commit__media img {
  transition-duration: 0s;
  transition-delay: 0s;
}

.commit__media {
  position: absolute;
  inset: 0;
      top: -12px;
  z-index: -2;
}

.commit__media img {
      width: 43%;
    height: auto;
    object-fit: cover;
    object-position: center 30%;
    margin: 0 auto;

  /*
     Uncovers left to right: the clip's right inset animates 100% → 0, so the
     edge travels across the cutout. A small leftward offset released to zero
     rides along with it, which keeps the figure moving *with* the wipe instead
     of standing still behind a passing edge.

     clip-path rather than a wrapper with overflow, because the image is centred
     by auto margins — a clipping wrapper would have to reproduce that geometry
     to sit in the right place.

     The offset lands on exactly 0, so the final frame is the untransformed
     image and the cutout's edges stay crisp.
  */
  -webkit-clip-path: inset(0 100% 0 0);
          clip-path: inset(0 100% 0 0);
  translate: -4% 0;
  transition: translate var(--wipe-dur) var(--wipe-ease) var(--wipe-follow),
    -webkit-clip-path var(--wipe-dur) var(--wipe-ease) var(--wipe-follow);
  transition: clip-path var(--wipe-dur) var(--wipe-ease) var(--wipe-follow),
    translate var(--wipe-dur) var(--wipe-ease) var(--wipe-follow);
  transition: clip-path var(--wipe-dur) var(--wipe-ease) var(--wipe-follow),
    translate var(--wipe-dur) var(--wipe-ease) var(--wipe-follow),
    -webkit-clip-path var(--wipe-dur) var(--wipe-ease) var(--wipe-follow);
  will-change: clip-path, translate;
}

.commit__stage.is-visible .commit__media img {
  -webkit-clip-path: inset(0 0 0 0);
          clip-path: inset(0 0 0 0);
  translate: 0 0;
}

 

.commit__stage.is-visible .commit__mark {
  translate: -50% -50%;
  -webkit-clip-path: inset(0 0 0 0);
          clip-path: inset(0 0 0 0);
  opacity: 1;
}

.commit__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  padding: 85px 120px 0;
}

.commit__col {
  display: grid;
  grid-gap: clamp(2rem, 6vh, 4.5rem);
  gap: clamp(2rem, 6vh, 4.5rem);
  align-content: space-between;
}

.pillar--right {
  text-align: right;
}

.commit h3 {
     font-weight: 400;
    font-size: 30px;
    line-height: 1;
    color: var(--gold-500);
    white-space: pre-line;
    font-family: "D-DIN Condensed", "Arial Narrow", "Helvetica Neue Condensed", "Roboto Condensed", sans-serif-condensed, sans-serif;
}
.commit ul li h3{width:255px;} 
.pillar--right .pillar__title {
  margin-left: auto;
}

.pillar__body {
    margin-top: 0.7em;
    font-size: 14px;
    color: rgba(255, 255, 255, 0.70);
    max-width: 18ch;
}

.pillar--right .pillar__body {
  margin-left: auto;
}

.commit__footer {
  text-align: center;
   padding-inline: var(--gutter);
   margin: 100px 0 0;
   opacity: 1;
    transform: inherit;
}

/* The footer is a child of the grid now, so a phone can scroll it as the last
   card in the rail. On desktop it simply spans both columns on row 2, which is
   where it already sat as the grid's next sibling. */
.commit__grid > .commit__footer {
  grid-column: 1 / -1;
}

.commit__footer-title {
  font-family: var(--font-body);
  font-weight: 400;
  font-size: clamp(1.1rem, 0.9rem + 1vw, 1.8rem);
  color: var(--gold-500);
}

.commit__footer-body {
  margin-top: 0.6em;
  font-size: var(--fs-body-sm);
  color: rgba(255, 255, 255, 0.85);
  max-width: 52ch;
  margin-inline: auto;
}

/* globals.css already neutralises [data-reveal] under reduced motion, but these
   two layers are children driven off the stage's class, so they need their own
   opt-out or they would sit clipped forever — .is-visible still lands, but with
   no transition the wipe would never be seen to run. Pinned to the finished
   state instead. */
@media (prefers-reduced-motion: reduce) {
  .commit__mark,
  .commit__stage.is-visible .commit__mark {
    translate: -50% -50%;
    -webkit-clip-path: none;
            clip-path: none;
    opacity: 1;
    transition: none;
    will-change: auto;
  }

  .commit__media img,
  .commit__stage.is-visible .commit__media img {
    translate: 0 0;
    -webkit-clip-path: none;
            clip-path: none;
    transition: none;
    will-change: auto;
  }
}



/* ----------------------------------------------------------- ZeroDelay -- */

.zero {
  background: var(--paper-blue);
  text-align: center;
  overflow: hidden;
}

/* The zero heading is inline-flex, so its mask wrapper needs to stay centred. */
.maskUp--center {
  display: flex;
  justify-content: center;
}

/* The heading rides the section's own `.is-live` flag rather than the shared
   [data-reveal] observer, so the copy, the sub and the cards can be sequenced
   against one another instead of each firing on its own threshold. */
.zero__headMask {
  display: flex;
  justify-content: center;
  overflow: hidden;
  padding-bottom: 0.14em;
  margin-bottom: -0.14em;
}

.zero__headMask > * {
  transform: translateY(112%);
  transition: transform 1s var(--ease);
  will-change: transform;
}

.zero.is-live .zero__headMask > * {
  transform: none;
}

.zero__heading {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.8rem, 0.9rem + 4.4vw, 4.4rem);
  line-height: 1;
  text-transform: uppercase;
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  justify-content: center;
      gap: 10px;
}

.zero__muted {
  color: var(--navy-300);
  font-weight: 400; 
}

.zero__bold {
  color: var(--navy-400); margin-right: 8px;
}

.zero__ring {
  display: inline-block;
  width: 0.56em;
  height: 0.92em;
  border: 0.11em solid #e8541f;
  border-radius: 0.5em;
  margin-inline: 0.02em;
  position: relative;
  margin-right: 8px;
   margin-left: -8px;
}

/* The two orange rings snap in a beat after the words have landed. */
.zero__ring {
  transform: scaleY(0.1);
  opacity: 0;
  transition: transform 0.7s var(--ease-out-back, cubic-bezier(.34,1.56,.64,1)),
    opacity 0.4s var(--ease);
  transition-delay: 0.55s;
}

.zero.is-live .zero__ring {
  transform: none;
  opacity: 1;
}
.zero__ring::before {
    content: '';
    position: absolute;
    background-color: #e8541f;
    width: 100%;
    height: 100%;
    border: solid 5px #fff;
    left: 0;
    border-radius: 23px;
}
.zero__sub {
  margin-top: var(--sp-3);
  font-family: var(--font-display);
  font-size: clamp(0.85rem, 0.75rem + 0.6vw, 1.3rem);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-700);
  font-weight: 400;
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.8s var(--ease) 0.28s, transform 0.8s var(--ease) 0.28s;
}

.zero.is-live .zero__sub {
  opacity: 1;
  transform: none;
}

.zero__sub strong {
  color: var(--ink-900);
  font-weight: 700;
}

.zero__railWrap {
  position: relative;
  margin-top: clamp(2rem, 5vw, 4rem);
}

/* The rail is a fixed viewport; `.zero__track` is the belt that moves inside
   it. Overflow is hidden rather than scrollable because position is owned by
   the RAF loop in ZeroDelay.jsx — a native scrollbar would fight it. */
.zero__rail {
  position: relative;
  overflow: hidden;
  /* Geometry of the hanging grid: the rule sits --ruleY from the rail's top
     edge, and every card hangs --tick below the rule. */
  --ruleY: 0px;
  --tick: 100px;
  padding-bottom: var(--sp-6);
  cursor: -webkit-grab;
  cursor: grab;
  touch-action: pan-y;
  -webkit-user-select: none;
  -moz-user-select: none;
       user-select: none;
  /* Cards dissolve into the section colour at both ends instead of being
     chopped off, which is what sells the loop as endless. */
  -webkit-mask-image: linear-gradient(
    to right,
    transparent 0,
    #000 8%,
    #000 92%,
    transparent 100%
  );
  mask-image: linear-gradient(
    to right,
    transparent 0,
    #000 8%,
    #000 92%,
    transparent 100%
  );
}

.zero__rail.is-dragging {
  cursor: -webkit-grabbing;
  cursor: grabbing;
}

/* The horizontal rule the whole section hangs from. It lives on the rail, not
   the track, so it stays still while the belt slides underneath it — and so it
   can draw itself out from the centre as the first beat of the reveal. */
.zero__rail::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: var(--ruleY);
  height: 1px;
  background: rgba(12, 58, 108, 0.16);
  z-index: 2;
  pointer-events: none;
  transform: scaleX(0);
  transform-origin: center;
  transition: transform 1s var(--ease);
}

.zero.is-live .zero__rail::before {
  transform: scaleX(1);
}

.zero__track {
  display: flex;
  align-items: flex-start;
  gap: 45px;
  width: max-content;
  will-change: transform;
  /* Cards start one tick-length below the rule, so each tick spans the gap. */
  padding-top: calc(var(--ruleY) + var(--tick));
}

.delivery {
  position: relative;
  flex: 0 0 clamp(210px, 22vw, 400px);
  text-align: center;
  padding-inline: var(--sp-4);
  /* The tick drops from the rule to this card's top edge — never across the
     name or the image. A lifted card is --lift closer to the rule, so its tick
     is exactly that much shorter and both still start on the rule. */
  --lift: 0px;
  --lineLen: calc(var(--tick, 100px) - var(--lift));
  /* One delay per card, reused by the tick and then by its content. */
  --tDelay: calc(0.55s + var(--i, 0) * 0.1s);
}

/* The tick draws itself top-to-bottom, and only once it has landed does the
   card's content come up underneath it. */
.delivery::before {
  content: "";
  position: absolute;
  left: 50%;
  top: calc(-1 * var(--lineLen));
  height: var(--lineLen);
  width: 1px;
  background: rgba(12, 58, 108, 0.16);
  pointer-events: none;
  transform: scaleY(0);
  transform-origin: top center;
  transition: transform 0.6s var(--ease);
  transition-delay: var(--tDelay);
}

.zero.is-live .delivery::before {
  transform: scaleY(1);
}

/* Content is staged on the children, not the card, so the card box stays put
   and the ::before tick is free to animate on its own clock. */
.delivery > * {
  opacity: 0;
  transform: translateY(34px);
  transition: opacity 0.7s var(--ease), transform 0.8s var(--ease);
  transition-delay: calc(var(--tDelay) + 0.5s);
}

.zero.is-live .delivery > * {
  opacity: 1;
  transform: none;
}

/* Name, place, image, label, months come up in that order. */
.delivery > *:nth-child(2) { transition-delay: calc(var(--tDelay) + 0.56s); }
.delivery > *:nth-child(3) { transition-delay: calc(var(--tDelay) + 0.62s); }
.delivery > *:nth-child(4) { transition-delay: calc(var(--tDelay) + 0.70s); }
.delivery > *:nth-child(5) { transition-delay: calc(var(--tDelay) + 0.76s); }

/* Rearming has to be instant — a delayed exit would leave half-played states
   waiting to be caught when the section scrolls back into view. */
.zero:not(.is-live) .zero__rail::before,
.zero:not(.is-live) .delivery::before,
.zero:not(.is-live) .delivery > * {
  transition-duration: 0s;
  transition-delay: 0s;
}

/* Lift is a margin, not a transform, so the entrance transform stays free.
   No fixed height — the card sizes to its own content and the rail's
   flex-start alignment lets the tops sit wherever the stagger puts them. */
.delivery--lift {
  --lift: 50px;
  margin-top: calc(-1 * var(--lift));
}

.delivery * {
  pointer-events: none;
}

.delivery__name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 35px;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color:#0c4e81;
}

.delivery__place {
  font-size:17px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #042640;
   
}

/* Frame is fixed and the art is cropped to fill it, so a mismatched upload
   never changes the card's height and breaks the stagger. Override per card
   with `ratio` in the data if a particular render needs its own crop. */
.delivery__thumb {
  margin-top: var(--sp-4);
  aspect-ratio: var(--thumbRatio, 7 / 5);
  border-radius: var(--radius-sm);
  background: linear-gradient(140deg, #cfe0f2 0%, #a9c4e0 60%, #8fb0d2 100%);
  display: grid;
  place-items: center;
  color: rgba(6, 34, 74, 0.55);
  font-family: var(--font-display);
  font-size: clamp(1rem, 0.8rem + 0.8vw, 1.4rem);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}

.delivery__thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.8s var(--ease);
}

.delivery:hover .delivery__thumb img {
  transform: scale(1.06);
}

.delivery__label {
  margin-top: var(--sp-4);
  font-size:16px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #000;
}

.delivery__months {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 50px;
  color: var(--navy-400);
  line-height: 1.1;
}

.zero__arrow {
  position: absolute;
  top: 50%;
  translate: 0 -50%;
  z-index: 2;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: #fff;
  color: var(--navy-500);
  box-shadow: var(--shadow);
  transition: transform 0.3s var(--ease);
  display: none;
}

.zero__arrow:hover { transform: translateY(-50%) scale(1.08); }
.zero__arrow svg { width: 20px; height: 20px; }
.zero__arrow--prev { left: max(0.5rem, calc(var(--gutter) - 2.75rem)); rotate: 180deg; }
.zero__arrow--next { right: max(0.5rem, calc(var(--gutter) - 2.75rem)); }

/* Drag affordance — fades out for good once the user has actually dragged. */
.zero__hint {
  margin-top: calc(var(--sp-4) * -1);
  display: inline-flex;
  align-items: center;
  gap: 0.55em;
  font-size: var(--fs-eyebrow);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--navy-500);
  opacity: 0;
  transition: opacity 0.6s var(--ease) 1.2s;
  display: none;
}

.zero.is-live .zero__hint {
  opacity: 0.5;
}

.zero.has-dragged .zero__hint {
  opacity: 0;
  transition-delay: 0s;
}

.zero__hintDot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #e8541f;
  animation: zeroHintPulse 1.8s ease-in-out infinite;
}

@keyframes zeroHintPulse {
  0%, 100% { transform: scale(0.6); opacity: 0.4; }
  50%      { transform: scale(1);   opacity: 1; }
}



@media (prefers-reduced-motion: reduce) {
  .zero__headMask { overflow: visible; }
  .zero__headMask > *,
  .zero__ring,
  .zero__sub,
  .delivery > * {
    transform: none;
    opacity: 1;
    transition: none;
  }
  .delivery::before,
  .zero__rail::before {
    transform: none;
    transition: none;
  }
  .zero__hintDot { animation: none; }
}

/* ------------------------------------------------------------- Quality -- */

.quality {
  background: linear-gradient(160deg, #0b3268 0%, #072a56 55%, #06224a 100%);
  color: #fff;
  overflow: hidden;
  padding: 80px 0;
}

.quality__inner {
  padding: 0;
  display: grid;
  grid-gap: clamp(1.5rem, 3vw, 2.5rem);
  gap: clamp(1.5rem, 3vw, 2.5rem);
}

.quality__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
      justify-content: center;
  gap: clamp(0.75rem, 2vw, 2rem);
}

.quality__title {
  font-size: clamp(1.9rem, 1rem + 4vw, 4rem);
}

.quality__sub {
  font-size: clamp(1rem, 0.85rem + 0.9vw, 1.7rem);
  line-height: 1.2;
  font-weight: 300;
}

.quality__sub span,
.quality__sub strong {
  display: block;
}

.quality__sub strong {
  font-weight: 600;
}

.quality__counter {
    display: flex;
    align-items: flex-start;
        justify-content: center;
    font-family: "Poppins", sans-serif;
    font-weight: 900;
    font-size: 440px;
    line-height: 1;
    letter-spacing: -13px;
}

/* One layer of numerals per photo, stacked in a single grid cell. */
.quality__counter-stack {
    display: grid;
}

.quality__counter-num {
    grid-area: 1 / 1;
    /* the image itself is set inline from data/site.js (quality.counter.images) */
    /* oversized so there's room to travel — `cover` leaves nothing to pan */
    background-size: 220% auto;
    background-repeat: no-repeat;
    background-position: 0% 50%;
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    -webkit-text-fill-color: transparent;
   /* animation: qualityCounterPan 18s ease-in-out infinite alternate;*/
    will-change: background-position, opacity;
    opacity: 0;
    background-size: cover;
}

/* The outgoing photo holds at full strength underneath… */
.quality__counter-num.is-prev {
    opacity: 1;
    z-index: 1;
}

/* …while the incoming one fades in on top of it — a true cross-dissolve
   with no see-through dip in the middle. */
.quality__counter-num.is-active {
    opacity: 1;
    z-index: 2;
    /* Shorter than `interval` in data/site.js (quality.counter), or the
       next photo starts before this one has finished arriving. */
    transition: opacity 0.35s cubic-bezier(0.45, 0, 0.55, 1);
}

@keyframes qualityCounterPan {
    from { background-position: 0% 50%; }
    to   { background-position: 100% 50%; }
}

@media (prefers-reduced-motion: reduce) {
    .quality__counter-num {
        animation: none;
        background-position: center;
    }
}

/* Poppins' comma reads too heavy at this size — only the comma swaps to
   D-DIN Condensed; the digits stay Poppins. */
.quality__counter-comma {
  font-family: "Manrope", system-ui, -apple-system, "Segoe UI", sans-serif;
  font-weight: 700;
  font-size: 230px;
}

.quality__counter sup {
  -webkit-text-fill-color: #fff;
  color: #fff;
  font-size: 0.16em;
  font-weight: 600;
  margin-top: 0.4em;
}

.quality__copy {
    display: flex;
    gap: 60px;
    align-items: start;
      font-weight: 400;
    justify-content: center;
     margin: -55px 0 0;
}

.quality__lead {
  max-width: 24ch;
    font-family: var(--font-display);
      font-size: 38px;
    font-weight: 400;
    color: #e3e3e3;
    line-height: 1
}

.quality__aside {
  display: grid;
  grid-gap: var(--sp-5);
  gap: var(--sp-5);
  justify-items: start;
  font-size: var(--fs-body-sm);
  color: rgba(255, 255, 255, 0.82);
  max-width: 28ch;
}

.quality__ai {
  position: relative;
  isolation: isolate;
  text-align: center;
  padding-block: clamp(2.5rem, 6vw, 5rem);
  border-top: none;
}

/* ------------------------------------------------------------------ board --
   /ai-circuit-brand.svg — the AI die with its traces fanning out — sits behind
   the headline and supplies the chip the copy reads around. Its own stylesheet
   carries the etch-in, the gold signal pulses and the reduced-motion opt-out;
   everything here is placement.

   Three columns rather than a centred flex row: `1fr auto 1fr` is what puts the
   middle column dead centre no matter how the two copy blocks measure, and the
   board is pinned to that same centre. A flex row centres the *group*, so the
   longer side would push the chip off-axis and the board would no longer line
   up with it.
*/
.quality__ai-head {
  --chip-w: clamp(104px, 13.5vw, 232px);
 position: relative;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  justify-items: center;
  grid-gap: clamp(0.5rem, 2vw, 1.5rem);
  gap: clamp(0.5rem, 2vw, 1.5rem);
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 0.98;
  text-transform: uppercase;
  font-size: 68px;
  color: #fff;
}

.quality__ai-head span {
  display: grid;
  text-align: right;
      color: #d1d2d8;
          right: -100px;
    position: relative;
}
.quality__ai-head span:last-child{text-align: left;  right:0; left: -50px;}

.quality__ai-head em {
  font-style: normal;
}

/* Empty box holding the centre column open at the size the board's chip paints,
   so the flanking copy clears the die instead of sitting on it. */
.quality__chip {
  width: var(--chip-w);
  aspect-ratio: 351 / 334;
}

/* The chip is 351 of the SVG's 1536 user units wide and its viewBox is centred
   on the die, so scaling by 1536/351 and pinning centre-to-centre lands the
   painted chip exactly in the slot above. Both numbers move together — retuning
   --chip-w rescales the whole board around it. */
.quality__aiBoard {
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: -1;
  width: calc(var(--chip-w) * 800 / 350);
  max-width: none;
  height: auto;
  transform: translate(-50%, -50%);
  pointer-events: none;
  -webkit-user-select: none;
     -moz-user-select: none;
          user-select: none;
}

/* Below the copy break the two blocks stack, so the board would be taller than
   the band and swamp it. Shrink the die and let the traces run off the sides. */


.quality__ai-body {
  margin: var(--sp-4) auto 0;
  max-width: 58ch;
  font-size: 20px;
  color: rgba(255, 255, 255, 0.72);
}



/* ------------------------------------------------------------- Stories --
   Staggered collage. The header pins while the cards scroll up over it, each
   column travelling at its own rate; when the section ends the header releases
   and the next section scrolls normally.

   `--sp` (0 → 1 through the viewport) comes from useSectionProgress, which
   writes no layout — the parallax is pure transform.
   ------------------------------------------------------------------------- */

.stories {
  --sp: 0;
  background: var(--paper-alt);
  overflow: clip;
}
.stories .shell {  padding-inline : 0; }
.stories .shell{max-width: 85%;}

.stories__inner {
  position: relative;
}

/* ---- pinned header ---- */

.stories__head {
  position: -webkit-sticky;
  position: sticky;
  top: calc(var(--header-h) + clamp(1rem, 4vh, 3rem));
  z-index: 0;
  text-align: center;
  display: grid;
  justify-items: center;
  grid-gap: var(--sp-2);
  gap: var(--sp-2);
 transform: scale(calc(1 - 0.05 * clamp(0, calc((var(--sp) - 0.3) / 0.4), 1)));
  will-change: opacity, transform;
  margin: 0 0 120px;
}

.stories__title {
  font-size: clamp(1.9rem, 1rem + 4vw, 4rem);
}

.stories__sub {
   font-weight: 600;
    color: #3f3f3f;
    font-size: 42px;
}

.rating {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  margin-top: var(--sp-5);
  text-align: left;
}

.rating__body {
  display: grid;
  grid-gap: 0.15em;
  gap: 0.15em;
}

.googleG {
  width: 75px;
  height: 75px;
  flex: none;
}

.rating__source {
font-size: 22px;
    color: #606060;
    font-weight: 600;
    line-height: 1;
}

.rating__score {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  line-height: 1;
}

.rating__score strong {
  font-family: var(--font-display);
  font-size: 40px;
  font-weight: 700;
  color: var(--ink-900);
}

.stars {
  display: inline-flex;
  gap: 2px;
}

.stars svg {
  width: 40px;
  height: 40px;
}

.rating__link {
 font-size: 18px;
    color: #818181;
    text-decoration: none;
    text-underline-offset: 3px;
}

/* ---- collage ---- */

/* row-gap must not be 0. The rows are content-sized and the quote text
   reflows with the viewport, so a zero gap leaves neighbouring rows touching
   at whatever height the copy happens to land on — which is what let the row-2
   video tile ride up over the row-1 card. */
.stories__grid {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  grid-column-gap: clamp(0.75rem, 2vw, 1.75rem);
  column-gap: clamp(0.75rem, 2vw, 1.75rem);
  grid-row-gap: clamp(1.25rem, 3vw, 2.5rem);
  row-gap: clamp(1.25rem, 3vw, 2.5rem);
  margin-top: clamp(-6rem, -4vw, -2rem);
  padding-bottom: clamp(2rem, 6vw, 4rem);
}

/* Each element rises at its own rate as the section passes — the parallax.
   `--sp` only exists once useSectionProgress runs; the fallback of 1 pins the
   collage to its settled position for the first paint and for the cleanup
   path, where the property is removed again. */
.story,
.storyVideo {
  translate: 0 calc(var(--drift, 0px) * (1 - var(--sp, 1)));
  will-change: translate;
}

/* Drift must never decrease going down a column pair that shares columns: the
   lower element carrying the larger --drift means the gap between them only
   ever opens during the scroll, never closes. Keep that true when retuning. */
.story--1     { grid-column: 2 / 9;   grid-row: 1;     --drift: 90px; }
.storyVideo--1{ grid-column: 6 / 9;   grid-row: 2;     --drift: 75px; }
.story--2     { grid-column: 9 / 13;  grid-row: 1 / 3; --drift: 40px; }
.storyVideo--2{ grid-column: 1 / 4;   grid-row: 3;     --drift: 320px; }
.story--3     { grid-column: 4 / 10;  grid-row: 3;     --drift: 320px; }
.storyVideo--3{ grid-column: 10 / 13; grid-row: 3;     --drift: 420px; margin-top: clamp(1rem, 4vw, 3rem); }

/* ---- quote card ---- */

/* Belt and braces on the stacking: if any two ever do graze — a long quote, an
   odd viewport — the card that carries text wins, so nothing is made
   unreadable by a tile landing on it. */
.story {
  position: relative;
  z-index: 2;
  align-self: start;
  background: #fff;
  padding: 80px 50px 80px;
  box-shadow: 0 18px 50px rgba(12, 58, 108, 0.07);
  display: grid;
  align-content: start;
  grid-gap: 18px;
  gap: 18px;
  overflow: hidden;
}

/* The faint Radiance counter behind the copy. */
.story::before {
  content: "";
  position: absolute;
  left:0;
  top: 0;
  width: 40%;
  height: 100%;
  aspect-ratio: 1;
  /*border-radius: 50%;
  border: clamp(28px, 5vw, 58px) solid rgba(12, 58, 108, 0.035);
  border-right-color: transparent;*/
  pointer-events: none;
  background: url(/media/story-c-bg.png) no-repeat;
  filter: grayscale(100%) opacity(0.9);
  background-size: 100%;
}
.story.story--2::before{  width: 100%;}
.story.story--3::before{  width: 45%;}

.story__all {
  justify-self: end;
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-eyebrow);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #000;
  transition: color 0.3s var(--ease), gap 0.3s var(--ease);
}

.story__all:hover {
  color: var(--navy-500);
  gap: var(--sp-3);
}

.arrowIcon {
  width: 18px;
  height: 18px;
}

.story__quote {
  position: relative;
  font-size: 22px;
  font-weight: 600;
  line-height: 1.32;
  color: #0f3d6a;
  max-width: 40ch;
      white-space: pre-line;
      text-align: justify;
    text-align-last: left;
    -webkit-hyphens: auto;
            hyphens: auto;
    overflow-wrap: normal;
}

.story__body {
    position: relative;
     color: #12121d;
       max-width: 65ch;
    line-height: 1.4;
    font-size: 16px;
    text-align: justify;
    text-align-last: left;
    -webkit-hyphens: auto;
            hyphens: auto;
    overflow-wrap: normal;
    
}

.story__by {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin-top: var(--sp-3);
}

.story__avatar {
  display: grid;
  place-items: center;
  width: 50px;
  height: 50px;
  margin-right:10px;
  border-radius: 4px;
  background: var(--navy-500);
  color: #fff;
  font-family: var(--font-display);
  font-size: 1.2rem;
  flex: none;
}

/* With a portrait set the plate becomes the frame for it; without one the
   initial stays centred on the navy plate above. */
.story__avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: inherit;
  display: block;
}

.story__by strong {
    display: block;
    font-family: var(--font-body);
    font-weight: 600;
    font-size: 30px;
    color: #0f3d6a;
    line-height: 1;
}

.story__by em {
 font-weight: 500;
 font-style: normal;
  font-size:18px;
  letter-spacing: 0;
  text-transform: uppercase;
  color: #1c1414;
}

/* ---- video tile ---- */

.storyVideo {
  position: relative;
  z-index: 1;
  align-self: start;
}

/* The tile is a <button> (it opens the popup player, not a page); the anchor
   selector is kept so older markup stays styled. */
.storyVideo button {
  border: 0;
  padding: 0;
  background: none;
  cursor: pointer;
  width: 100%;
}

.storyVideo a,
.storyVideo button {
  position: relative;
  display: block;
  aspect-ratio: 16 / 14;
  overflow: hidden;
  background: linear-gradient(140deg, #cfdcea 0%, #aac0d8 60%, #93aecb 100%);
  box-shadow: 0 18px 44px rgba(12, 58, 108, 0.14);
  transition: transform 0.45s var(--ease), box-shadow 0.45s var(--ease);
}

.storyVideo a:hover,
.storyVideo button:hover {
  transform: translateY(-4px);
  box-shadow: 0 26px 56px rgba(12, 58, 108, 0.22);
}

.storyVideo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.storyVideo__play {
  position: absolute;
  right: clamp(0.75rem, 2vw, 1.5rem);
  bottom: clamp(0.75rem, 2vw, 1.5rem);
  width: clamp(44px, 5vw, 62px);
  filter: drop-shadow(0 6px 14px rgba(0, 0, 0, 0.3));
  transition: transform 0.35s var(--ease);
}

.storyVideo a:hover .storyVideo__play,
.storyVideo button:hover .storyVideo__play {
  transform: scale(1.08);
}

.storyVideo__play svg {
  width: 100%;
  height: auto;
}

/* --- Popup video player (VideoModal.jsx) ---------------------------------- */

/* Portalled to <body>, so these live in the global sheet — the player is
   opened from the homepage collage, the project stories rail and the intro
   strip's walkthrough link alike. */
.vModal {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: grid;
  place-items: center;
  padding: clamp(1rem, 4vw, 3rem);
  background: rgba(2, 16, 38, 0.85);
  -webkit-backdrop-filter: blur(6px);
          backdrop-filter: blur(6px);
}

.vModal__body {
  position: relative;
  width: min(1080px, 100%);
  aspect-ratio: 16 / 9;
  background: #000;
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.5);
}

.vModal__body iframe {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}

.vModal__close {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 2;
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.92);
  color: #031f47;
  font-size: 24px;
  line-height: 1;
  cursor: pointer;
}

.vModal__close:hover {
  background: #fff;
}

.stories__cta {
  position: relative;
  z-index: 1;
  display: grid;
  justify-items: center;
  margin-top: 80px;
}
.faq .display {
    color: #1b4a88;
}
 
/* The site's solid CTA — the orange gradient pill. It answers the pointer the
   same way the two-action pill does (.exbloretwoBtn in globals.css): lift,
   deeper shadow, the sheen sweeping across, and the tracking opening up.

   The selectors are doubled so this transition outranks [data-reveal]'s, which
   is declared later in globals.css and would otherwise replace it on any
   button that also carries data-reveal — that is what made the hover snap
   instead of easing. The sheen itself is .btn--solid::after in globals.css. */
.btn--solid.btn--solid {
  position: relative;
  overflow: hidden;
  padding: 9px 28px;
  background-color: #0f3d6a;
  background-image: linear-gradient(to right, #f6800e, #f9a51a, #f6800e);
  color: #fff;
  box-shadow: 0 14px 30px rgba(246, 128, 14, 0.32);
  transition: transform 0.45s var(--ease), box-shadow 0.45s var(--ease),
    letter-spacing 0.45s var(--ease), background-position 0.45s var(--ease);
}

.btn--solid.btn--solid:hover {
  background-image: linear-gradient(to right, #f6800e, #f9a51a, #f6800e);
  transform: translateY(-2px);
  box-shadow: 0 18px 38px rgba(246, 128, 14, 0.45);
  letter-spacing: 0.16em;
}
/* ---- stacked ---- */


@media (prefers-reduced-motion: reduce) {
  .stories__head {
    opacity: 1;
    transform: none;
  }

  .story,
  .storyVideo {
    translate: none;
  }
}

/* ----------------------------------------------------------------- NRI -- */

.nri {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background: #061626;
  color: #fff;
  padding-block: clamp(3.5rem, 8vw, 7rem);
  --nri-ease-back: cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* The photograph lives on a pseudo-element rather than on .nri itself so the
   slow drift can run on `transform` (compositor-only). Animating the section's
   own background-position would repaint a full-bleed band every frame.
   The negative inset bleeds the layer past the section, so the scale never
   exposes an edge. */
.nri::before {
  content: "";
  position: absolute;
  inset: -5%;
  z-index: -1;
  background: url(/media/nri-bg.jpg) center / cover no-repeat;
  animation: nriDrift 26s ease-in-out infinite alternate;
  will-change: transform;
}

@keyframes nriDrift {
  from { transform: scale(1); }
  to   { transform: scale(1.09) translate3d(-1.5%, 0.5%, 0); }
}

.nri__media {
  position: absolute;
  inset: 0;
  z-index: -1;
}

.nri__inner {
  position: relative;
  max-width: min(var(--maxw), 100%);
}

.nri__title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.9rem, 1rem + 4.2vw, 4.2rem);
  line-height: 1;
  text-transform: uppercase;
}

.nri__title--gold { color: var(--gold-500); }
.nri__title--light { color: #fff; }

.nri__sub {
  font-family: var(--font-display);
  font-weight: 700;
  font-size:40px;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: #fff;
  margin-top: 0.15em;
}

/* Cards are narrower than the column and alternate which edge they hang off,
   so the stack reads as a staggered collage rather than a list. The tight gap
   lets consecutive cards graze each other the way the design does. */
.nri__list {
  display: grid;
  grid-gap: clamp(0.4rem, 1.2vw, 0.85rem);
  gap: clamp(0.4rem, 1.2vw, 0.85rem);
  margin-top: clamp(1.5rem, 4vw, 3rem);
  max-width: max-content;
}

.nriItem {
    position: relative;
    z-index: calc(var(--i, 0) + 1);
    max-width: 70%;
    display: flex;
    align-items: center;
    gap: var(--sp-4);
    padding: 15px 30px;
    border-radius: var(--radius);
    font-weight: 600;
    font-size: 18px;
    box-shadow: var(--shadow);
    margin: -16px 0 0;
}
/* Tilt knobs. --tilt is where the card settles, --tilt-in where it starts.
   Set these, not `transform` — see the note on the reveal rules below. */
.nriItem--solid {
  background: var(--navy-500);
  color: #fff;
  --tilt: -2.2deg;
  --tilt-in: -5deg;
  --slide-in: -58px;
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.38);
      z-index: 10;
}

.nriItem--pale {
  background: #dceaf8;
  color: var(--navy-500);
  margin-left: auto;
  --tilt: 0.6deg;
  --tilt-in: 5deg;
  --slide-in: 58px;
}

/* Each card flies in from the edge it sits against — solid from the left, pale
   from the right — instead of the generic fade-up.

   The rotation lives on the independent `rotate` property, NOT inside the
   `transform` shorthand. `.nriItem[data-reveal].is-visible` has to reset the
   slide with `transform: none`, and a rotate packed into that same shorthand
   would be wiped along with it — the tilt would exist for the length of the
   fly-in and then vanish, which is exactly the "rotate not working" symptom.
   `translate` / `rotate` / `scale` are separate properties that compose with
   `transform` and with each other, so each animation here owns one of them:
     translate → the idle float
     rotate    → the tilt
     scale     → hover lift and the badge pop
     transform → the reveal slide
   Adding a `transform: rotate(...)` anywhere on .nriItem will silently lose to
   the `transform: none` below. Set --tilt instead. */
.nriItem[data-reveal] {
  opacity: 0;
  transform: translateX(var(--slide-in, -58px));
  rotate: var(--tilt-in, -5deg);
  transition:
    opacity 0.85s var(--ease),
    transform 0.85s var(--ease),
    rotate 0.85s var(--ease),
    scale 0.35s var(--ease),
    box-shadow 0.35s var(--ease);
}

.nriItem[data-reveal].is-visible {
  opacity: 1;
  transform: none;
  rotate: var(--tilt, 0deg);
}

/* The float uses `translate`, not `transform`, so it composes with the reveal
   transition above rather than overriding it — an animation on `transform`
   would win outright and the fly-in would never be seen. The negative delay
   starts each card mid-cycle, so they drift out of step immediately. */
.nriItem.is-visible {
  animation: nriFloat 7s ease-in-out infinite alternate;
  animation-delay: calc(var(--i, 0) * -1.35s);
}

@keyframes nriFloat {
  from { translate: 0 -5px; }
  to   { translate: 0 5px; }
}

/* Sheen. Driven by background-position rather than a moved layer, because the
   number badge overhangs the card and `overflow: hidden` would decapitate it. */
.nriItem::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  background-image: linear-gradient(
    105deg,
    transparent 40%,
    rgba(255, 255, 255, 0.42) 50%,
    transparent 60%
  );
  background-size: 220% 100%;
  background-repeat: no-repeat;
  background-position: 200% 0;
}

.nriItem.is-visible::after {
  animation: nriSheen 1.15s 0.4s ease-out 1;
}

@keyframes nriSheen {
  0%   { background-position: 200% 0; opacity: 0; }
  12%  { opacity: 1; }
  100% { background-position: -120% 0; opacity: 0; }
}

@media (hover: hover) {
  .nriItem:hover {
    scale: 1.025;
    box-shadow: 0 18px 44px rgba(0, 0, 0, 0.38);
    z-index: 9;
  }
}

.nriItem__num {
  position: absolute;
  top: -12px;
  left: -12px;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--navy-500);
  color: #fff;
  font-size: 0.85rem;
  font-weight: 700;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
  /* `scale`, not transform — the badge is absolutely positioned off the corner
     and a transform-based scale would fight nothing, but keeping the two
     independent properties separate matches the card above. */
  scale: 0.2;
  opacity: 0;
  transition: scale 0.5s var(--nri-ease-back), opacity 0.3s linear;
}

/* Lands after the card has settled, so it reads as being pinned on. */
.nriItem.is-visible .nriItem__num {
  scale: 1;
  opacity: 1;
  transition-delay: 0.34s;
}

.nriItem--pale .nriItem__num {
  left: auto;
  right: -12px;
}

.nri__actions {
  margin-top: clamp(2rem, 5vw, 3.5rem);
}



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

  .nriItem[data-reveal],
  .nriItem[data-reveal].is-visible {
    opacity: 1;
    transform: none;
    rotate: none;
    transition: none;
  }

  .nriItem.is-visible,
  .nriItem.is-visible::after {
    animation: none;
  }

  .nriItem__num {
    scale: 1;
    opacity: 1;
    transition: none;
  }
}

/* ------------------------------------------------------------ Passport -- */

.passport {
  position: relative;
  overflow: hidden;
  background: #fff;
   padding: 0 0 15px;

  /* One place to retune the whole rig.
     --lift   how far the render rises on entrance
     --tiltX/--tiltY  the pointer parallax ceiling, in degrees
     --floatY the idle drift amplitude */
  --lift: clamp(40px, 7vw, 88px);
  --tiltX: 4.5deg;
  --tiltY: 6deg;
  --floatY: clamp(6px, 1.1vw, 14px);
}
 .passport::after{content: ''; position: absolute; width: 100%; height: 100px; background: #063b73; bottom: 0;}
 .passport .maskUp { position: relative;   z-index: 999;  top: 210px; }
  .passport .maskUp h2.display{justify-content: flex-start;     padding: 0 0 0 83px;}
.passport__watermark {
    top: 5%;
    left: 50%;
    translate: -50% 0;
    font-size: 225px;
    color: rgba(12, 58, 108, 0.035);
    letter-spacing: 0.02em;
    animation: passportWatermarkDrift 26s ease-in-out infinite;
    text-align: center;
    display: flex;
    justify-content: center;
    align-items: center;
}
/* Orbits ------------------------------------------------------------------ */

.passport__orbits {
  position: absolute;
  left: 50%;
  top: 54%;
  translate: -50% -50%;
  width: min(1240px, 96vw);
  height: auto;
  overflow: visible;
  pointer-events: none;
}

/*
  The rings' own job is to scale up from the centre, so the generic
  [data-reveal] slide is replaced rather than added to.

  Centring stays on the individual `translate` property above and the reveal
  only touches `transform` — the two compose (translate, then transform) instead
  of fighting, which is why translate(-50%,-50%) must NOT be repeated here.
*/
.passport__orbits[data-reveal] {
  opacity: 0;
  transform: scale(0.9);
  transition: opacity 1.1s var(--ease), transform 1.4s var(--ease);
}

.passport__orbits[data-reveal].is-visible {
  opacity: 1;
  transform: scale(1);
}

.passport__ring,
.passport__tracer {
  fill: none;
}

/* non-scaling-stroke keeps the hairline at 1px however wide the svg renders.
   Deliberately not applied to the tracer: that ring's dash lengths are
   normalised by pathLength, and stroking in screen space instead of user space
   is where those two features are known to disagree. */
.passport__ring {
  stroke: rgba(12, 58, 108, 0.13);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}

/* Inner rings sit slightly stronger, so the set reads as depth rather than as
   three identical outlines. */
.passport__orbits g:nth-child(2) .passport__ring { stroke: rgba(12, 58, 108, 0.1); }
.passport__orbits g:nth-child(3) .passport__ring { stroke: rgba(12, 58, 108, 0.08); }

/*
  A 12%-long dash on a pathLength="1" ellipse, walked from 0 to -1: the lit arc
  leaves one end of the ring exactly as it re-enters the other, so the loop has
  no seam. Alternate rings run backwards for counter-rotation.
*/
.passport__tracer {
  stroke: rgba(248, 166, 25, 0.55);
  /* User units against the 1200-wide viewBox, so it thins out with the svg —
     which is what you want on a decorative arc at phone widths. */
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-dasharray: 0.12 0.88;
  stroke-dashoffset: 0;
  opacity: 0;
}

.passport__orbits.is-visible .passport__tracer {
  opacity: 1;
  animation: passportTrace var(--trace, 22s) linear infinite;
  transition: opacity 0.8s var(--ease) 0.5s;
}

.passport__orbits.is-visible g:nth-child(2) .passport__tracer {
  animation-direction: reverse;
  stroke: rgba(12, 58, 108, 0.4);
}

.passport__orbits.is-visible g:nth-child(3) .passport__tracer {
  stroke: rgba(248, 166, 25, 0.4);
}

/* Off-screen the loop stops and rearms, matching the reveal's replay. */
.passport__orbits:not(.is-visible) .passport__tracer {
  animation: none;
  stroke-dashoffset: 0;
}

@keyframes passportTrace {
  to { stroke-dashoffset: -1; }
}

@keyframes passportWatermarkDrift {
  0%, 100% { translate: -50% 0; }
  50%      { translate: calc(-50% + 1.2%) -0.4%; }
}

/* Heading ----------------------------------------------------------------- */

.passport__inner {
  position: relative;
  z-index: 10;
}

.passport__title {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: center;
  gap: clamp(0.5rem, 2vw, 1.5rem);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2rem, 1rem + 4.6vw, 4.6rem);
  letter-spacing: 0.02em;
  text-transform: uppercase;
  text-align: center;
}

.passport__title--navy { color: var(--navy-400); margin-right: 180px; }

/*
  The gold word carries a sheen: a light band clipped to the glyphs and slid
  across once the heading has finished its mask wipe. background-clip: text is
  the whole effect, so the fallback for anything that lacks it is the flat gold
  the colour declaration already provides.
*/
.passport__title--gold {
  color: var(--gold-500);
  background-image: linear-gradient(
    100deg,
    var(--gold-500) 38%,
    #ffe4a8 50%,
    var(--gold-500) 62%
  );
  background-size: 280% 100%;
  background-position: 100% 0;
  background-repeat: no-repeat;
  -webkit-background-clip: text;
  background-clip: text;
}

@supports ((-webkit-background-clip: text) or (background-clip: text)) or (-webkit-background-clip: text) {
  .maskUp.is-visible .passport__title--gold {
    animation: passportSheen 7s ease-in-out 1.1s infinite;
  }
}

@keyframes passportSheen {
  0%, 55%, 100% { background-position: 100% 0; }
  22%           { background-position: 0 0; }
}

.passport__title small {
  display: grid;
  font-family: var(--font-body);
  font-size: clamp(0.9rem, 0.78rem + 0.5vw, 1.18rem);
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
     color: #000;
    text-align: left;
    line-height: 1.35; 
    top: -40px;
    position: relative;
}

.passport__title em {
  font-style: normal;
}

/* Composition ------------------------------------------------------------- */

.passport__grid {
  position: relative;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  grid-gap: clamp(1.5rem, 4vw, 3.5rem);
  gap: clamp(1.5rem, 4vw, 3.5rem);
  margin-top: clamp(2rem, 5vw, 4rem);
}

/*
  The wrapper exists only so a phone can scroll both feature lists as one
  rail. Here it dissolves and its two lists become grid items themselves.
  The device follows them in the markup, so `order` is what puts it back in
  the middle column.
*/
.passport__rail {
  display: contents;
}

.passport__col--left { order: 1; }
.passport__device { order: 2; }
.passport__col--right { order: 3; }

.passport__col {
  display: grid;
  grid-gap: clamp(2rem, 6vh, 4.5rem);
  gap: clamp(2rem, 6vh, 4.5rem);
}

.passport__col.passport__col--right {
margin-left: 0;
}

.quality h2.display {
      color: #faa61c;
}
/* Features ---------------------------------------------------------------- */

/*
  --dx is a visual nudge, not layout: the lower block on each side sits further
  along the render's diagonal, which is what keeps the four blocks reading as a
  ring around the phone instead of two straight stacks. Because it lives in the
  transform it also has to be the reveal's rest position — hence the shared
  translateX below.
*/
.pfeature {
  --dx: 0px;
  --fx: 0px;
  position: relative;
}

.passport__col--left .pfeature:nth-child(2) { --dx: clamp(0px, 3.6vw, 56px); }
.passport__col--right .pfeature:nth-child(2) { --dx: clamp(0px, 5.8vw, 92px); }

.pfeature--left {
  text-align: right;
  padding-right: var(--sp-4);
  --fx: 34px;
}

.pfeature--right {
  padding-left: var(--sp-4);
  --fx: -120px;
}

/* The rule is a pseudo-element, not a border, so it can draw itself. */
.pfeature::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  width: 2px;
  background: rgba(12, 58, 108, 0.25);
  transform: scaleY(0);
  transform-origin: top center;
  transition: transform 0.75s var(--ease) 0.12s;
}

.pfeature--left::before { right: 0; }
.pfeature--right::before { left: 0; }

.pfeature.is-visible::before {
  transform: scaleY(1);
}

/* Slide in from the outside edge; the rest state keeps the --dx nudge. */
.pfeature[data-reveal] {
  opacity: 0;
  transform: translateX(calc(var(--dx) + var(--fx)));
  transition: opacity 0.85s var(--ease), transform 0.85s var(--ease);
}

.pfeature[data-reveal].is-visible {
  opacity: 1;
  transform: translateX(var(--dx));
}

.pfeature h3 {
  font-family: var(--font-body);
  font-size: var(--fs-body-sm);
  font-weight: 700;
  color: var(--ink-900);
}

.pfeature p {
  margin-top: 0.3em;
  font-size: var(--fs-body-sm);
  color: var(--ink-500);
  max-width: 26ch;
      text-align: justify;
    text-align-last: left;
    -webkit-hyphens: auto;
    hyphens: auto;
    overflow-wrap: normal;
}

.pfeature--left p {
  margin-left: auto;
   text-align-last: right;
}

/* Device ------------------------------------------------------------------ */

/*
  The render already contains the handset, its screen and the elevation rising
  out of it — there is no CSS phone frame to build. The job here is only to give
  that flat PNG somewhere to move in, which is why the perspective lives on the
  wrapper and each nested box owns exactly one transform.
*/
.passport__device {
  display: grid;
  justify-items: center;
  perspective: 1100px;
  perspective-origin: 50% 40%;
}

.passport__device[data-reveal] {
  opacity: 0;
  transform: translateY(var(--lift)) scale(0.94);
  transition: opacity 1s var(--ease), transform 1.25s var(--ease);
}

.passport__device[data-reveal].is-visible {
  opacity: 1;
  transform: translateY(0) scale(1);
}

/* Pointer parallax. --px/--py arrive from usePointerTilt in the range -1…1 and
   default to 0, so this is inert until a fine pointer moves over the section. */
.passport__tilt {
  transform: rotateX(calc(var(--py, 0) * var(--tiltX) * -1))
    rotateY(calc(var(--px, 0) * var(--tiltY)));
  transform-style: preserve-3d;
  transition: transform 0.5s ease-out;
  will-change: transform;
}

.passport__float {
  position: relative;
  width: 700px;
  animation: passportFloat 8s ease-in-out infinite;
}

.passport__phone {
  position: relative;
  display: block;
  width: 100%;
  height: auto;
  /* Grounds the render on the white background — the PNG is cut out, so
     without this it floats with no weight. */
  filter: drop-shadow(0 26px 34px rgba(6, 34, 74, 0.18));
}

/* Soft pool of light under the device, breathing against the float so the lift
   reads as distance rather than as the image sliding up and down. */
.passport__glow {
  position: absolute;
  left: 50%;
  bottom: 4%;
  translate: -50% 0;
  width: 86%;
  aspect-ratio: 2.6 / 1;
  border-radius: 50%;
  background: radial-gradient(
    ellipse at center,
    rgba(12, 58, 108, 0.2) 0%,
    rgba(12, 58, 108, 0.07) 45%,
    rgba(12, 58, 108, 0) 72%
  );
  filter: blur(6px);
  animation: passportGlow 8s ease-in-out infinite;
}

@keyframes passportFloat {
  0%, 100% { transform: translateY(calc(var(--floatY) * -0.5)); }
  50%      { transform: translateY(calc(var(--floatY) * 0.5)); }
}

@keyframes passportGlow {
  0%, 100% { opacity: 0.9; scale: 1.04 1; }
  50%      { opacity: 0.62; scale: 0.94 1; }
}

/* Small screens ----------------------------------------------------------- */


/* Ambient loops are exactly what this opts out of: the composition still
   assembles on scroll, it just stops moving once it has. */
@media (prefers-reduced-motion: reduce) {
  .passport__watermark,
  .passport__float,
  .passport__glow,
  .maskUp.is-visible .passport__title--gold,
  .passport__orbits.is-visible .passport__tracer {
    animation: none;
  }

  .passport__orbits[data-reveal],
  .passport__orbits[data-reveal].is-visible {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .passport__device[data-reveal],
  .passport__device[data-reveal].is-visible {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .passport__tilt {
    transform: none;
    transition: none;
  }

  .pfeature[data-reveal],
  .pfeature[data-reveal].is-visible {
    opacity: 1;
    transform: translateX(var(--dx));
    transition: none;
  }

  .pfeature::before {
    transform: scaleY(1);
    transition: none;
  }
}

/* -------------------------------------------- Passport — project page -- */
/*
  Same rig, different arrival. On the project page the heading is not a block
  that wipes up: the two words part around the device, the tagline drops in
  behind them, the render pushes up out of the fold rather than lifting into
  it, and the columns come in further from the outside. The idle float and the
  pointer tilt are untouched — those are what make the device feel like an
  object, and they read the same on both pages.
*/
.passport--pd {
  --lift: clamp(56px, 9vw, 120px);
  --tiltX: 6deg;
  --tiltY: 8deg;
  padding: 200px 0 30px;
 
}

/* The homepage nudges the heading into place with fixed offsets. Here it is a
   three-column row instead: word, the device's gap, word — so the two halves
   stay either side of the phone at any width, and the tagline hangs under the
   gold word the way the comp has it. */
.passport--pd .maskUp {
  top: 0;
  z-index: 5;
}

.passport--pd .maskUp h2.display {
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--pdDevice) minmax(0, 1fr);
  grid-template-rows: auto auto;
  align-items: center;
  grid-gap: 0;
  gap: 0;
  padding: 0;
}

.passport--pd .passport__title--navy {
  grid-area: 1 / 1;
  justify-self: end;
    margin-right: 445px;
    margin-left: 69px;
}

.passport--pd .passport__title--gold {
  grid-area: 1 / 3;
  justify-self: start;
}

.passport--pd .passport__title small {
  grid-area: 2 / 3;
  justify-self: start;
  top: 0;
  margin-top: 0.4rem;
}

/* The composition tucks up under the heading, and the device goes further
   still — it has to rise through the gap between the two words while the
   feature columns stay below the heading line. */
.passport--pd .passport__grid {
  margin-top: clamp(-4rem, -4vw, -1.5rem);
}

.passport--pd .passport__device {
  margin-top: clamp(-13rem, -15vw, -5rem);
}

.passport--pd .passport__title--navy,
.passport--pd .passport__title--gold {
  transition: opacity 1s var(--ease), transform 1.15s var(--ease);
}

.passport--pd .maskUp:not(.is-visible) .passport__title--navy {
  opacity: 0;
  transform: translateX(clamp(24px, 5vw, 90px));
}

.passport--pd .maskUp:not(.is-visible) .passport__title--gold {
  opacity: 0;
  transform: translateX(clamp(-90px, -5vw, -24px));
}

.passport--pd .passport__title small {
  transition: opacity 0.9s var(--ease) 0.35s, transform 0.9s var(--ease) 0.35s;
}

.passport--pd .maskUp:not(.is-visible) .passport__title small {
  opacity: 0;
  transform: translateY(-14px);
}

/* Pushes up from below the fold — the opposite of the homepage's settle. */
.passport--pd .passport__device[data-reveal] {
  transform: translateY(calc(var(--lift) * 1.4)) scale(0.9);
  transition: opacity 1.1s var(--ease), transform 1.4s var(--ease) 0.1s;
}

.passport--pd .passport__device[data-reveal].is-visible {
  transform: translateY(0) scale(1);
}

/* Further out, and staggered the other way: the outermost row leads. */
.passport--pd .pfeature--left { --fx: 72px; }
.passport--pd .pfeature--right { --fx: -72px; }

/* The homepage indents the middle row of each column; here the three sit in a
   straight stack, evenly spaced down the height of the device. */
.passport--pd .passport__col {
  gap: clamp(2rem, 5.5vw, 5rem);
}

.passport--pd .passport__col--left .pfeature:nth-child(2),
.passport--pd .passport__col--right .pfeature:nth-child(2) {
  --dx: 0px;
}

/* A tall, narrow device — the render stands out of the top of the phone and
   carries on down past the navy band. */
.passport--pd .passport__float {
  width: clamp(240px, 27vw, 520px);
}

.passport--pd .passport__device {
  position: relative;
  z-index: 2;
}

/* The band is the floor the device stands on, so it scales with the section
   rather than sitting at a fixed 100px. */
.passport--pd::after {
  height: clamp(56px, 8vw, 104px);
}

/* Wider than the section, so the outermost ring leaves the frame at both sides
   the way it does on the comp instead of closing inside it. */
.passport--pd .passport__orbits {
  top: 52%;
  width: min(1900px, 132vw);
}

.passport--pd .pfeature::before {
  transform-origin: center;
  transition: transform 0.9s var(--ease) 0.2s;
}

/* Sized off the viewport rather than pinned at 225px, so the word still spans
   the section and is still cropped by the top edge on any screen. */
.passport--pd .passport__watermark {
  top: 0;
  font-size: clamp(4.5rem, 13vw, 15rem);
}

/* Below this the three-column heading would leave a word to a line, so the
   device goes back under the type and everything stacks. */


@media (prefers-reduced-motion: reduce) {
  .passport--pd .passport__title--navy,
  .passport--pd .passport__title--gold,
  .passport--pd .passport__title small,
  .passport--pd .passport__device[data-reveal] {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* ---------------------------------------------------------------- Care -- */

.care {
  background: #063b73;
  color: #fff;
  padding-block: clamp(2.5rem, 6vw, 4.5rem);
}

.care__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: clamp(1.5rem, 4vw, 3.5rem);
}

.care__title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.8rem, 1rem + 3.6vw, 3.6rem);
  line-height: 0.98;
  text-transform: uppercase;
  text-align: right;
}

.care__title span { display: block; }
.care__title--gold { color: var(--gold-500); }

.care__aside {
  display: grid;
  grid-gap: var(--sp-4);
  gap: var(--sp-4);
  justify-items: start;
  max-width: 34ch;
  font-size: 22px;
  line-height: 1.2;
  color: rgba(255, 255, 255, 0.88);
}



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

.faq {
  background: #fff;
  padding: 80px 0 0;
}

.faq__inner {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  grid-gap: clamp(2rem, 5vw, 5rem);
  gap: clamp(2rem, 5vw, 5rem);
  align-items: start;
}

.faq__aside {
  position: relative;
  display: grid;
  justify-items: start;
  grid-gap: var(--sp-4);
  gap: var(--sp-4);
}
.faq__aside .btn {display:none;}

/*
  The brand C, sitting behind the heading as a watermark. Replaces a ring drawn
  with a 44px border and a transparent right edge, which only ever approximated
  the real letterform's cut terminals.

  The asset carries its own opacity — mid grey at roughly 10% alpha, which
  composites to #f3f3f3 on the white panel — so it is drawn at full strength and
  the reveal animates opacity to 1, not to some fraction.

  Three animations run at once, so each owns a different property, per the
  convention documented on .nriItem: fold any two into `transform` and the
  reveal's `transform: none` silently wipes the other.
    transform → the reveal's scale-in
    rotate    → the scroll-linked turn
    translate → the idle drift
*/
.faq__mark {
    position: absolute;
    left: -38%;
    top: 26%;
    width: min(518px, 34vw);
    aspect-ratio: 718 / 741;
    background: url(/media/c-logo.png) center / contain no-repeat;
    pointer-events: none;
    rotate: calc((var(--sp, 0.5) - 0.5) * 46deg);
    animation: faqMarkDrift 14s ease-in-out infinite alternate;
    filter: grayscale(100%) opacity(0.9);
}

/* Scales up rather than sliding up: the generic [data-reveal] translate would
   fight the drift, which owns `translate`. */
.faq__mark[data-reveal] {
  opacity: 0;
  transform: scale(0.86);
  transition: opacity 1.1s var(--ease), transform 1.3s var(--ease);
}

.faq__mark[data-reveal].is-visible {
  opacity: 1;
  transform: none;
}

@keyframes faqMarkDrift {
  from { translate: 0 0; }
  to   { translate: 0 -14px; }
}

.faq__title {
  position: relative;
  font-size: clamp(1.9rem, 1rem + 4vw, 3.8rem);
  line-height: 0.98;
}

.faq__title span { display: block; font-weight: 500; }

.faq__title em {
  display: block;
   font-style: normal;
  font-weight: 400;
  font-size: 0.62em;
  letter-spacing: -0.01em;
  text-transform: none;
  color: var(--navy-400);
  margin-top: 0.15em;
}

.faq__blurb {
  position: relative;
  max-width: 44ch;
   margin-bottom: 30px;
}

.faq__list {
  display: grid;
  grid-gap: var(--sp-4);
  gap: var(--sp-4);
  padding-bottom: 80px;
      position: relative;
}

/*.faq__list:after {content: ''; position: absolute; left: 0; pointer-events: none; width: 100%; height: 30%; bottom: 0; background-image: linear-gradient(to top, #fff, transparent);} */

.faqItem {
  border-radius: var(--radius);
  background: #f4f7fb;
  border: 1px solid rgba(12, 58, 108, 0.08);
  transition: background-color 0.35s var(--ease), box-shadow 0.35s var(--ease);
      opacity: 1;
      transform: translateY(0px) !important;
}

.faqItem.is-open {
  background: #f3f7fa;
  box-shadow: var(--shadow-sm);
}

.faqItem__q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  width: 100%;
  text-align: left;
  padding: clamp(1.1rem, 2.4vw, 1.6rem) clamp(1.2rem, 2.6vw, 1.8rem);
  font-family: var(--font-body);
  font-weight: 700;
  font-size: clamp(1rem, 0.9rem + 0.5vw, 1.2rem);
  line-height: 1.25;
  color: var(--navy-400);
}

.faqItem__icon {
  display: grid;
  place-items: center;
  flex: none;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--navy-500);
  color: #fff;
  transition: transform 0.35s var(--ease);
}

.faqItem.is-open .faqItem__icon {
  transform: rotate(180deg);
}

.faqItem__icon svg { width: 18px; height: 18px; }

/*
   Collapsed panel. A grid row of 0fr → 1fr animates to the content's natural
   height without measuring it in JS, which `height: auto` cannot do and
   `hidden`/`display: none` cannot transition at all.
   The inner wrapper must own the overflow for the row to clip.
*/
.faqItem__a {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.45s var(--ease);
}

.faqItem.is-open .faqItem__a {
  grid-template-rows: 1fr;
}

.faqItem__aInner {
  overflow: hidden;
}

.faqItem__a p {
  padding: 0 clamp(1.2rem, 2.6vw, 1.8rem) clamp(1.1rem, 2.4vw, 1.6rem);
  font-size: var(--fs-body-sm);
  color: var(--ink-500);
  max-width: 62ch;
  opacity: 0;
  transform: translateY(-6px);
  transition: opacity 0.3s var(--ease), transform 0.3s var(--ease);
  text-align: justify;
    text-align-last: left;
    -webkit-hyphens: auto;
    hyphens: auto;
    overflow-wrap: normal;
}

.faqItem.is-open .faqItem__a p {
  opacity: 1;
  transform: none;
  transition-delay: 0.12s;
}

@media (prefers-reduced-motion: reduce) {
  .faqItem__a,
  .faqItem__a p {
    transition-duration: 0.01ms;
  }

  /* The mark still sits behind the heading, it just stops moving. --sp goes
     unwritten here, so `rotate` already resolves to 0deg via its fallback —
     zeroed explicitly anyway so the intent survives a change to that default. */
  .faq__mark {
    animation: none;
    rotate: 0deg;
    translate: none;
  }

  .faq__mark[data-reveal],
  .faq__mark[data-reveal].is-visible {
    opacity: 1;
    transform: none;
    transition: none;
  }
}



/* ------------------------------------------------------------ Memories -- */

.memories {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  min-height: 1100px;
  display: grid;
  align-items: flex-start;
  color: #fff;
  background: #2a2118;
}
.memories h2{color: #fff;}
.memories__media {
  position: absolute;
  inset: 0;
  z-index: -2;
}

/* <picture> is inline by default, and the img's height:100% resolves against
   it — so it has to fill the media box itself. */
.memories__media picture {
  display: block;
  width: 100%;
  height: 100%;
}

.memories__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 35%;
}
 

.memories__arc {
  position: absolute;
  z-index: -1;
  left: 34%;
  top: 46%;
  translate: -50% -50%;
  width: min(460px, 46vw);
  aspect-ratio: 1;
  border-radius: 50%;
  border: 26px solid transparent;
  border-top-color: var(--gold-500);
  border-left-color: #e8541f;
  rotate: -28deg;
  opacity: 0.92;
}

.memories__inner {
  position: relative;
  display: grid;
  justify-items: start;
  grid-gap: clamp(1.5rem, 4vw, 2.5rem);
  gap: clamp(1.5rem, 4vw, 2.5rem);
  padding-block: clamp(3rem, 8vw, 5rem);
}

.memories__title {
  font-size: clamp(2rem, 1rem + 4.6vw, 4.6rem);
  line-height: 0.96;
}

.memories__title span { display: block; }


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

.footer {
  background: #01337a;
  color: rgba(255, 255, 255, 0.86);
  padding-block: clamp(3rem, 7vw, 5.5rem) clamp(2rem, 4vw, 3rem);
  position: relative;
}

.footer:after {
    content: '';
    position: absolute;
    left: 0;
    pointer-events: none;
    width: 100%;
    height: 35%;
    bottom: 0;
    background-image: linear-gradient(to top, #0b1f36, transparent);
}

.footer__inner {
  display: grid;
  grid-gap: clamp(2rem, 5vw, 3.5rem);
  gap: clamp(2rem, 5vw, 3.5rem);
      position: relative;
    z-index : 10;
    padding: 0;
}

.footer__cities {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-gap: clamp(1.5rem, 4vw, 4rem);
  gap: clamp(1.5rem, 4vw, 4rem);
}

.footerCity__name {
  font-weight: 400;
  font-size: clamp(1.4rem, 1rem + 1.4vw, 2.2rem);
  color: rgba(255, 255, 255, 0.78);
  margin-bottom: var(--sp-4);
}

/* The city heading holds a button so it can work as an accordion toggle on
   mobile. On desktop it dresses down to the plain heading: inherits the
   heading's face, no icon, and the panel is always open. */
.footerCity__toggle {
  display: inline-flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: default;
  pointer-events: none;
}

.footerCity__icon {
  display: none;
}

.footerCity__group + .footerCity__group {
  margin-top: var(--sp-4);
}

.footerCity__status {
  font-size: var(--fs-body-sm);
  font-weight: 700;
  color: #fff;
  margin-bottom: 0.25em;
}

.footerCity__group li a {
  display: block;
  font-size: var(--fs-body-sm);
  color: rgba(255, 255, 255, 0.7);
  padding-block: 1px;
  transition: color 0.25s var(--ease);
}

.footerCity__group li a:hover {
  color: var(--gold-500);
}

.footer__enquiries {
  border-top: 1px solid rgba(255, 255, 255, 0.14);
  padding-top: var(--sp-6);
  position: relative;
}

.footer__legend {
    position: absolute;
    top: 0;
    left: 15px;
    translate: 0 -50%;
    background: #01337a;
    padding-right: var(--sp-4);
    font-weight: 400;
    font-size: 30px;
    color: #94c3e8;
    padding: 0 10px;
}

.footer__contactRow {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(1.5rem, 5vw, 4rem);
  align-items: flex-start;
}

.footer__contact span {
  display: block;
  font-size: var(--fs-body-sm);
  color: rgba(255, 255, 255, 0.6);
}

.footer__contact a {
  font-size: clamp(1.05rem, 0.9rem + 0.7vw, 1.5rem);
  color: #fff;
  transition: color 0.25s var(--ease);
}

.footer__contact a:hover { color: var(--gold-500); }

.footer__social {
  margin-left: auto;
}

.footer__social span {
  display: block;
  font-size: var(--fs-body-sm);
  color: rgba(255, 255, 255, 0.6);
  margin-bottom: 0.5em;
}

.footer__social ul {
  display: flex;
  gap: var(--sp-3);
}

.social {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  color: #fff;
  transition: transform 0.3s var(--ease);
}

.social:hover { transform: translateY(-3px); }
.social svg { width: 18px; height: 18px; }

.social--facebook { background: #1877f2; }
.social--linkedin { background: #0a66c2; }
.social--x { background: #111; }
.social--instagram { background: linear-gradient(45deg, #f09433, #dc2743, #bc1888); }
.social--youtube { background: #ff0033; }

.footer__brand {
  line-height: 0.8;
}

.footer__meta {
  min-width: 0;
}

.footer__base {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.8fr);
  grid-gap: clamp(1.5rem, 4vw, 3rem);
  gap: clamp(1.5rem, 4vw, 3rem);
  align-items: center;
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  padding-top: clamp(1.5rem, 4vw, 2.5rem);
}

.footer__links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35em 0;
  font-size: var(--fs-body-sm);
}

.footer__links a {
  padding-inline: 0.7em;
   color: rgba(255, 255, 255, 0.82);
  transition: color 0.25s var(--ease);
  position: relative;
}
.footer__links a::before{content: ''; position: absolute; background: #fff; opacity: 0.5; width: 1px; height: 12px; right: 0; top: 5px;}

 
.footer__links a:last-child:before { background:none; }
.footer__links a:hover { color: var(--gold-500); }

.footer__copy {
  margin-top: var(--sp-4);
  font-size: var(--fs-body-sm);
  color: rgba(255, 255, 255, 0.55);
  padding-left: 10px;
}

/* Copyright left, design credit right, on one baseline row. */
.footer__copyRow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  flex-wrap: wrap;
}

.footer__designBy {
  margin-top: var(--sp-4);
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-size: var(--fs-body-sm);
  color: rgba(255, 255, 255, 0.55);
  text-decoration: none;
  transition: color 0.3s ease;
  display: none;
}

.footer__designBy:hover {
  color: #fff;
}

.footer__designBy img {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  object-fit: cover;
  display: block;
}



/* --------------------------------------------------------- Mobile dock --
   Gold quick-action bar pinned to the bottom on phones: home · enquiry ·
   brand badge · call · menu. Never shown above 900px. The menu button opens
   the same SiteMenu as the header burger — the state lives in Header, which
   renders the dock next to it.
   ------------------------------------------------------------------------- */

.mobileDock {
  position: fixed;
  left: 50%;
  bottom: calc(10px + env(safe-area-inset-bottom, 0px));
  translate: -50% 0;
  z-index: 95; /* over the page, under the SiteMenu overlay (110) */
  display: none;
  align-items: center;
  justify-content: space-between;
  width:98%;
  padding: 8px 20px;
  border-radius:70px;
  background: linear-gradient(180deg, #f2b13d 0%, #e39c22 100%);
  box-shadow: 0 14px 30px rgba(4, 20, 45, 0.45);
  animation: dockRise 0.6s var(--ease) 0.2s both;
  height:60px;
}

@keyframes dockRise {
  from {
    translate: -50% 140%;
    opacity: 0;
  }
  to {
    translate: -50% 0;
    opacity: 1;
  }
}

.mobileDock__btn {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  background: none;
  color: #10233c;
}

.mobileDock__btn svg {
  width: 26px;
  height: 26px;
}

/* Raised circular brand badge at the centre, breaking the bar's top edge. */
.mobileDock__brand {
  display: grid;
  place-items: center;
  width: 80px;
  height: 80px;
  margin-top:0;
  overflow: hidden;
}

.mobileDock__brand img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 50%;
}

@media (max-width: 900px) {
  .mobileDock {
    display: flex;
  }

  /* Keep the last of the footer readable above the fixed bar. */
  .footer {
    padding-bottom: calc(clamp(2rem, 4vw, 3rem) + 88px);
  }
}

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

/* ------------------------------------------------------------- SideCta -- */
/* Dark glass pill pinned to the right edge: call (highlighted white disc),
   enquire, WhatsApp — per the approved floating-stack comp. */

.sideCta {
  position: fixed;
  right: clamp(10px, 1.5vw, 10px);
  top: 50%;
  translate: 0 -50%;
  z-index: 90;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 15px;
  padding: 9px;
  border-radius: var(--radius-pill);
  background:rgb(2 14 26);
  border: 5px solid rgba(255, 255, 255, 0.05);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  box-shadow: 0 14px 34px rgba(4, 12, 26, 0.4);
}

.sideCta__btn {
  display: grid;
  place-items: center;
  width: 35px;
  height: 35px;
  border-radius: 50%;
  border: none;
  color: rgba(255, 255, 255, 0.85);
  transition: transform 0.3s var(--ease), background-color 0.3s var(--ease),
    color 0.3s var(--ease), border-color 0.3s var(--ease);
    background: rgba(255, 255, 255, 0.1);
}

/* The enquire button is a <button> (it opens the popup, not a page), so the
   UA chrome is stripped back to the shared .sideCta__btn look. */
button.sideCta__btn {
  padding: 0;
  background: none;
  font: inherit;
  cursor: pointer;
  background: rgba(255, 255, 255, 0.1);
}

.sideCta__btn svg,
.sideCta__icon {
  width: 21px;
  height: 21px;
  filter: brightness(0) invert(1);
}

/* Call and Enquire each carry two marks. Desktop keeps the inline glyphs —
   the handset and the paper plane — and the supplied files are hidden here,
   taking over inside the ≤900px block. */
.sideCta__btn--call .sideCta__icon,
.sideCta__btn--enquire .sideCta__icon {
  display: none;
}

/* The handset sits on the white --primary disc, so it keeps its navy fill
   rather than the white wash the other marks get. */
.sideCta__btn--call svg {
  filter: none;
}

.sideCta__btn:hover {
  transform: translateY(-2px) scale(1.05);
  background: rgba(255, 255, 255, 0.14);
  border-color: rgba(255, 255, 255, 0.65);
  color: #fff;
}

.sideCta__btn--primary {
  background: #fff;
  color: var(--navy-900);
}

.sideCta__btn--primary:hover {
  background: var(--gold-500);
  border-color: var(--gold-500);
  color: var(--navy-900);
}

/* Brand colours on hover — each button lights up in its own logo colour. */
.sideCta__btn--call:hover {
  background: #f8a619;
  border-color: #f8a619;
  color: #fff;
}

.sideCta__btn--enquire:hover {
  background: #229ed9;
  border-color: #229ed9;
  color: #fff;
}

.sideCta__btn--whatsapp:hover {
  background: #25d366;
  border-color: #25d366;
  color: #fff;
}

/* ------------------------------------------- SideCta: collapsed "+" stack --
   One behaviour at every width (was phone-only): a green "+" disc that fans
   WhatsApp / enquiry / call out in an arc. The doubled .sideCta.sideCta keeps
   it ahead of the older per-breakpoint .sideCta tweaks further down.
   -------------------------------------------------------------------------- */

  .sideCta,
  .sideCta.sideCta {
    position: fixed;
    top: auto;
    left: auto;
    right: 18px;
    bottom: calc(22px + env(safe-area-inset-bottom, 0px));
    translate: none;
    z-index: 96;
    display: block;
    width: 60px;
    height: 60px;
    padding: 0;
    gap: 0;
    border: 0;
    border-radius: 50%;
    background: transparent;
    box-shadow: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }

  .sideCta .sideCta__toggle {
    position: relative;
    z-index: 2;
    display: grid;
    place-items: center;
    width: 60px;
    height: 60px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: #fff;
    cursor: pointer;
    overflow: hidden;
    box-shadow: 0 10px 22px rgba(4, 20, 45, 0.28);
    transition: transform 0.3s var(--ease);
    -webkit-tap-highlight-color: transparent;
  }

  .sideCta .sideCta__toggle img {
    display: block;
    width: 100%;
    height: 100%;
    border-radius: 50%;
    transition: scale 0.3s var(--ease), opacity 0.3s var(--ease);
  }

  /* Open state: the mark settles back a touch rather than spinning — it is a
     logo, not a plus sign. */
  .sideCta.is-open .sideCta__toggle img {
    scale: 0.92;
    opacity: 0.85;
  }

  /* action discs start hidden behind the toggle */
  .sideCta .sideCta__actions .sideCta__btn,
  .sideCta .sideCta__actions .sideCta__btn--call,
  .sideCta .sideCta__actions .sideCta__btn--enquire {
    position: absolute;
    top: 50%;
    left: 50%;
    z-index: 1;
    display: grid;
    place-items: center;
    width: 40px;
    height: 40px;
    margin: -20px 0 0 -20px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: #f2a833;
    color: #10233c;
    box-shadow: 0 6px 14px rgba(0, 0, 0, 0.18);
    opacity: 0;
    scale: 0.4;
    translate: 0 0;
    pointer-events: none;
    transition: translate 0.4s var(--ease), scale 0.4s var(--ease),
      opacity 0.25s var(--ease);
  }

  .sideCta .sideCta__actions .sideCta__btn svg,
  .sideCta .sideCta__actions .sideCta__icon {
    width: 21px;
    height: 21px;
  }

  .sideCta .sideCta__actions .sideCta__btn:hover {
    background: #f2a833;
    color: #10233c;
    transform: none;
  }

  /* Phone: the supplied files replace the desktop handset and paper plane. */
  .sideCta .sideCta__btn--call svg,
  .sideCta .sideCta__btn--enquire svg {
    display: none;
  }

  .sideCta .sideCta__btn--call .sideCta__icon,
  .sideCta .sideCta__btn--enquire .sideCta__icon {
    display: block;
  }

  /* open: fan out in an arc (up-left of the "+") */
  .sideCta.is-open .sideCta__actions .sideCta__btn {
    opacity: 1;
    scale: 1;
    pointer-events: auto;
  }

  .sideCta.is-open .sideCta__actions .sideCta__btn--whatsapp {
    translate: -64px -6px;
    transition-delay: 0s;
  }

  .sideCta.is-open .sideCta__actions .sideCta__btn--enquire {
    translate: -46px -50px;
    transition-delay: 0.04s;
  }

  .sideCta.is-open .sideCta__actions .sideCta__btn--call {
    translate: 4px -66px;
    transition-delay: 0.08s;
  }

  /* Light discs, so the marks stay dark instead of the white wash. */
  .sideCta__btn svg,
  .sideCta__icon {
    filter: brightness(1) invert(0);
  }


.header.is-scrolled .logo { height: 55px;}
.header.is-scrolled .header__inner { padding: 0; min-height: 65px;}
.header.is-scrolled.header__link {  font-size: 15px;}
.displaynone{display: none !important;}

.pList{}
.project--navy .ribbon__statement.last{display: none;}
.ribbon__plate.lastImg   .ribbon__walkthrough{display: none;}
.ribbon__plate.lastImg .exbloretwoBtn  {display: block;}
.qband__cta .btn--gradient { background: linear-gradient(to right, #f6800e, #f9a51a, #f6800e) !important;}



/* Tower plate CTAs — bottom-centred over the tower render */
.ribbon__plate-cta--tower {
  right: auto;
  left: 60%;
  bottom: 60px;
   justify-items: center;
  white-space: nowrap;
}
.ribbon__plate-cta--tower  .exbloretwoBtn, .ribbon__plate-cta--tower  .btn--duo{  transform: none; opacity: 1;}

.ribbon__plate-cta--tower  .exbloretwoBtn:hover, .ribbon__plate-cta--tower  .btn--duo:hover{  transform: none;}
.ribbon__plate-cta--tower .exbloretwoBtn button {
     transform: none;  opacity: 1;  
}

.project--eternity .ribbon__plate-cta--tower {   bottom: 60%;}
.exbloretwoBtn > .btn {  opacity: 1;  transform: translateY(0); }
 .stQuote{display: none;}
 .st__track { top: 0 !important; }

@media (min-width: 1921px) and (max-width: 2500px) {
.ribbon__plate.lastImg {
    left: -462px;
}
}

@media (max-width: 1880px) { 
.ribbon__cardOut::before{  top: 392px;}
.ribbon__locus{padding-bottom: 98px;}
 .passport__watermark {  font-size: 200px;}
 .ribbon__card {  padding: 190px 0 0; }
 .ribbon__facts {  padding: 190px 0 0; }
}
 
@media (max-width: 1680px) { 
  h2.display {  font-size: 90px !important;}
.ribbon__statement h3 {  font-size: 35px;}
 .story__quote {  font-size: 25px;}
  .passport__watermark {  font-size: 190px;}
  .passport .maskUp h2.display {  padding: 0 0 0 125px; }
  .legacyStat__label {   font-size: 14px;}
  .legacyStat__num {  font-size: 120px;}
  .legacy__headline { font-size: 40px;}
  .legacy__stats {  padding: 0 48px 170px; }
  .legacy__media { left: 51%; top: 15%;  height: 76%;}
  .ribbon__plate-cta {  right: 80px;}
  .project--solitaire .ribbon__factsStatement h3, .project--imperia .ribbon__factsStatement h3 {
     font-size: 50px;}
     .btn {  padding: 8px 10px;}
     .storyVideo__play {  width: clamp(40px, 5vw, 49px);}
     .siteMenu__panel { padding: 50px 0 50px 80px;}
     .siteMenu__nav a {  font-size: 19px;}

 }

@media (max-width: 1600px) { 
  h2.display {  font-size: 75px !important;  }
  .header__link { font-size: 15px;}
      h2.display {   font-size: 80px !important;  }
      .projects__tab {  font-size: 28px;}
  .legacy__headline { font-size: 38px; line-height: 1;}
      .legacy__media {  top: 18%;}
  .legacy__stats {   padding: 0 48px 111px;  }
  .bImg__headline {  font-size: 70px;}
  .bannerText .left h2 {   font-size: 58px;}
  .ribbon__facts{ padding: 133px 0 0 70px;}
      .ribbon__cardOut::before {   top: 328px;   }
  .footer__social ul {  gap: 5px; }
 .commit__media img {  width: 42%;}
 .commit__media {  top: 16px;}
 .commit__footer {  margin: 32px 0 0;}
 .ribbon__plate.lastImg {  left: -448px; }
 .ribbon__statement {  padding: 100px 0 0 70px; }
 .project--solitaire .ribbon__facts, .project--imperia .ribbon__facts {
    margin: 0 0 160px; }
    .ribbon__card {  padding: 123px 0 0; }
    .project--solitaire .ribbon__cardOut--copy .exbloretwoBtn > .btn, .project--imperia .ribbon__cardOut--copy .exbloretwoBtn > .btn {
      opacity: 1;  transform: inherit;
}
.project--solitaire .ribbon__cardOut--facts::before, .project--imperia .ribbon__cardOut--facts::before {
     top: 255px;
}
.zero__track{gap:28px;}
.delivery__months{font-size: 30px;}
.delivery__label{font-size: 13px;}
.delivery__name{font-size: 22px;}
.delivery {  flex: 0 0 clamp(210px, 16vw, 400px);}
.section{padding-block: clamp(3.5rem, 7vw, 4rem);}
.quality__counter { font-size: 380px;}
.story__by strong{font-size: 25px;}
.story__by em {  font-size: 16px;}
.passport__col--right .pfeature:nth-child(2) { --dx: clamp(0px, 5.8vw, 39px); }
 .delivery__place{font-size: 12px;} 
  .nri::before {  background-position: 80% 0; }
  .passport__watermark {  font-size: 181px;}
.logo--ghost {  width: 90%;}
.passport .maskUp h2.display {  padding: 0 0 0 159px;  }
  }

@media (max-width: 1500px) { 
      .legacyStat__num {   font-size: 100px;  }
      .legacy__media {   top: 20%;   height: 80%;  }
        .passport .maskUp h2.display {   padding: 0 0 0 82px;  }
            .legacy__stats {    padding: 0 48px 100px; }
        .legacy { background-position: center -188px;}
            .legacy__headline {   font-size: 35px;  }
            .legacy__arc { width: min(560px, 28vw);}
        .legacy {  padding: 60px 0 0;}
   .bImg__headline {  font-size: 70px;}
      .ribbon__card {   padding: 100px 0 0;  }
  .commit__media {  top: 55px;}
  .milestone__title {  font-size: 13px;}
  .commit__footer {  margin: 62px 0 0; }
  .ribbon__facts{padding: 127px 0 0 70px;}
  .delivery__place{font-size: 12px;} 
  .delivery__months{font-size: 30px;} 
  .delivery__name{font-size: 27px;} 
   h2.display {  font-size: 85px !important;}
  .bannerText .left h2 {  font-size: 50px;  }
  .projects__marquee em {  font-size: 85px;}
      .commit__media img {    width: 48%;   }
      .delivery__months {  font-size: 45px;  }
    .delivery {flex: 0 0 clamp(210px, 20vw, 500px);}
 .quality {  padding: 80px 70px; }
 .quality__counter {  font-size: 355px;}
 .quality__ai-head{  font-size:58px;  }
 .shell {  max-width: 1300px;}
 .header__link {  font-size: 16px;}
 .footer__contactRow {  gap: 30px;}
 .project--solitaire .ribbon__factsStatement h3,
.project--imperia .ribbon__factsStatement h3 {  font-size: 45px;}
.ribbon__cardOut::before {  top: 304px;}
 .milestone {  width: 250px;}
 .project--solitaire .ribbon__cardOut--facts::before, .project--imperia .ribbon__cardOut--facts::before {   top: 250px; }
.ribbon__plate-cta { right: 20px;}
    .ribbon__facts {     padding: 107px 0 0 70px;  }
    .quality__counter{letter-spacing: -6px;}
    .siteMenu__panel {   padding: 50px 0 50px 80px;}
 }

 @media (max-width: 1440px) { 
      .legacy__media {   top: 13%;   height: 85%; }
 }


@media (max-width: 1380px) {
      .legacy__media {   top: 7%; }
      .legacy__headline {  font-size: 32px; }
      .commit__footer {      margin: 0;  }
     .commit__media img {   width: 42%;  }
         .ribbon__facts {  padding: 108px 0 0 70px;   }
      .delivery__name {  font-size: 25px;}
   .delivery__months {  font-size: 30px;  }
     .delivery__place{font-size: 11px; }
     .delivery__label {font-size: 11px; }
  .passport .maskUp h2.display {   padding: 0 0 0 136px; }
  .nriItem {  font-size: 16px;}
  .nri {  padding-block: clamp(3.5rem, 7vw, 7rem);}
 .delivery__name {  font-size: 25px;}
   .delivery__months {  font-size: 30px;  }
  .bannerText {  column-gap: 60px; }
    .quality__counter {    font-size: 330px;  }
         .quality__ai-head {    font-size: 53px;  }
           h2.display {   font-size: 70px !important;   }
           .stories__sub {  font-size: 35px; }
               .story__quote {   font-size: 20px;  }
               .story__by strong { font-size: 20px;}
               .header__link {  font-size: 14px; }
                   .passport__watermark {    font-size: 156px;  }
}

@media (max-width: 1300px) { 
    .legacy__media{left: 50%;  top:10%; }   
  .legacy__headline {  font-size: 30px;  }
  .legacy {   background-position : center -164px;  }
  .bannerText .right {  max-width: 28ch;}
    .shell {   max-width: 1200px;   }
  .project--solitaire .ribbon__facts,
.project--imperia .ribbon__facts {  margin: 0 0 185px; }
  h2.display { font-size: 70px !important;  }
  .specItem__points {  padding-left: 48px;}
  .btn {  padding: 8px 16px;}
  .bannerText .right {  padding-left: 25px;}
      .bannerText .left h2 {     font-size: 46px;   }
          .quality__counter {   font-size: 290px;  }
          .quality__ai-head{font-size: 42px;}
          .quality__copy{margin: -20px 0 0;}
          .quality__ai-body{font-size: 17px;}
          .story__body{font-size: 15px;}
          .nriItem {   font-size: 14px; }
          .nri::before {  background-position: 63% 0; }
          .passport .maskUp h2.display { padding: 0 0 0 120px; }
          .passport__float {  width: 570px;}
      
   }
@media (max-width: 1200px) {
  .legacy {   background-position: center -48px;  }
      .legacy__media {  left: 48%;  top: 26%;  height: 75%;  }
      .legacy__headline {  font-size: 30px;  }
          .legacyStat__num {  font-size: 95px;  }
          .commit__media img {  width: 44%; }
}

@media (max-width: 1100px) {
   .story {  padding: 50px 30px;}
  header{padding: 0 20px;}
  .header__inner {
    grid-template-columns: auto 1fr auto;
  }
  .commit__grid {
    padding: 85px 80px 0;
}
    .delivery__name {  font-size: 24px;  }
    .delivery__place { font-size: 13px;}
    .delivery__label { font-size: 13px;}
        .quality__counter {   font-size: 280px;  }
        .quality__copy {  margin: -7px 0 0; }
        .quality__ai-head {  font-size: 32px;  }
        .quality__ai-body { font-size: 17px;}
  .header__nav {
    display: none;
  }
      .bannerText .left h2 {
        font-size: 35px;
    }
    .bannerText .right {  max-width: 24ch;}

  .header__logo {
    grid-column: 1;
    justify-self: start;
  }
      h2.display {
        font-size: 60px !important;
    }

  .burger {
    grid-column: 3;
  }
  .passport__grid { grid-template-columns: inherit;}
  .legacy__headline {  font-size: 30px;}
  .passport__title--navy {   margin-right: 0; }
  .passport__device{order: 3;   margin: -200px 0 0;}
  .passport__col--left{order: 1; position: relative; top: 250px; right: 0;}
  .passport__col--right{order: 2;}
  .passport__watermark { font-size: 130px;}
  .commit h3 {  font-size: 23px;}
  .passport__col--right .pfeature:nth-child(2) { --dx: 0; }
  .passport__col--left .pfeature:nth-child(2) {  --dx: 0; }
  .care__aside { font-size: 20px;}
  .story__quote {   font-size: 19px;   }
  .story__by strong {    font-size: 16px;  }
  .story__by em {   font-size: 13px;}
  .header__inner {  display: flex;   width: 100%;  justify-content: center; }
  .header__nav {  display: flex;  }
  .nriItem {  font-size: 16px;}
  .footer {  padding: 30px 28px; }
  .footer__social {   margin-left: 0; }
  .legacyStat__num {  font-size: 95px;}
  .legacyStat__label {  font-size: 13px;}
  .bannerText .right p {  font-size: 13px;} 
  .logo {  height: 55px;}
      .pdHero__title {   font-size: 60px;  }
      .pi__lede {  font-size: 50px;}
      .quality__counter{font-size: 250px;}
      .footer__copy {  font-size: 14px;}
      .footer__links {  font-size : 14px; }
}


@media (max-width: 900px) {
  .quality__counter{font-size: 220px;}
  .menuCity__name { font-size: 30px;}
  .project--solitaire .ribbon__statSmall, .project--imperia .ribbon__statSmall { width: auto; }
  .project--solitaire .ribbon__statSmall, .project--imperia .ribbon__statSmall {
         width: auto;   padding: 0 0 30px 35px;   background: #02407d;  text-align: center;  color: #ffffff;  border-bottom: none; }
      .project--solitaire .ribbon__statSmall b {  color: #00407d;}
          .project--solitaire .ribbon__statSmall b {    color: #f8a619;  }

      .header__nav {  display: none;  }
  .burger {  display: block; }
.header {  display: flex;  position: fixed;    top: 0;}
.header .logo {  height: 50px; }
.header.is-hidden {  transform: inherit; }
  body{font-size: 16px;}
  .siteMenu {
    grid-template-columns: 1fr;
    grid-template-rows: auto 1fr;
    overflow-y: auto;
  }

  .siteMenu__panel {
    overflow: visible;
    padding: 30px;
  }

  .siteMenu__cities {
    grid-template-columns: 1fr;
    height: auto;
  }

  .menuCity {
    border-left: 0;
    border-top: 1px solid rgba(12, 58, 108, 0.08);
    min-height: 132px;
  }

  .menuCity__link {
    display: flex;
    align-items: center;
    padding-block: clamp(1.25rem, 4vw, 2rem);
  }

  .menuCity__watermark {
    writing-mode: horizontal-tb;
    transform: none;
    left: auto;
    right: clamp(0.5rem, 3vw, 2rem);
    bottom: auto;
    top: 0;
    translate: 0 -50%;
    font-size: clamp(2.5rem, 12vw, 5rem);
  }

  .menuCity__media {
    inset: 0;
  }

 
  .bImg {
    min-height: 100svh;
  }

  /* .image-container / .bannerText / .bottom mobile restack lives in the
     "narrow screens" block beside the homeBanner styles (~line 975). */
 
  /* ---- Projects intro: centred head + full-width tabs (mobile comp) ---- */

  .projects__intro {
    padding-block: clamp(3.5rem, 12vw, 5rem) 0;
  }

  .projects__marquee em {
    font-size: clamp(3rem, 15vw, 4.5rem);
  }

  .projects__head {
    padding-top: clamp(3rem, 12vw, 4.5rem);
    gap: var(--sp-2);
  }

  /* h2.display carries a 90px !important from the wide-screen tweaks above,
     so this needs !important too (higher specificity wins the tie). */
  .projects .projects__heading {
    font-size: clamp(3.125rem, 9vw, 3.75rem) !important;
    line-height: 1.12;
    text-transform: uppercase;
    font-weight: 700;
    letter-spacing: 0.02em;
    max-width: 16ch;
  }

  /* Comp keeps the rule above and below the tab row, all three cities on one
     line. Type shrinks with the viewport instead of the row scrolling, so
     "Bengaluru" is never clipped off the right edge. */
  .projects__tabs {
    width: min(760px, 100%);
    flex-wrap: nowrap;
    justify-content: space-between;
    gap: clamp(0.75rem, 4vw, 2.5rem);
    margin-top: var(--sp-5);
    padding-block: var(--sp-3);
    border-top: 1px solid var(--line);
    border-bottom: 1px solid var(--line);
  }

  .projects__tab {
    flex: 0 0 auto;
    white-space: nowrap;
    font-size: clamp(1.05rem, 4.6vw, 1.5rem);
    font-weight: 500;
    padding-bottom: var(--sp-2);
  }

  .projects__tab::after {
    height: 4px;
  }

  /* ---- Project ribbon → stacked mobile panel (mobile comp order):
     lede → lockup + place → walkthrough → render → blurb → 2×2 stats → CTA.
     The horizontal rig is off at this width, so the nested cardOut / card /
     facts wrappers are flattened with display:contents and every block is
     placed explicitly on one two-column grid. ---- */

  .ribbon {
    --pad: clamp(1.25rem, 5vw, 2rem);
    display: grid;
    grid-template-columns: 1fr 1fr;
    grid-gap: 0;
    gap: 0;
    height: auto;
  }

  .ribbon::before,
  .ribbon__cardOut::before {
    display: none;
  }

  .ribbon__cardOut,
  .ribbon__card,
  .ribbon__facts {
    display: contents;
  }

  /* Desktop-only blocks: closing statement, tower + aerial plates and the
     CTAs riding the aerial. */
  .ribbon__plate--tower,
  .ribbon__plate--aerial,
  .ribbon__statement,
  .ribbon__factsStatement,
  .ribbon__plate-cta {
    display: none;
  }

  /* 1 — lede */
  .ribbon__lede {
    grid-row: 1;
    grid-column: 1 / -1;
    margin: 0;
    padding: var(--pad) var(--pad) 0.75rem;
    font-size: 45px;
    line-height: 1;
    
  }
  .ribbon__lede span{display: inline; padding-right: 5px;}

  /* 2 — project lockup with the place beside it */
  .ribbon__card > div[data-reveal] {
    grid-row: 2;
    grid-column: 1;
    display: flex;
    align-items: center;
    padding: 0.5rem 0 0.5rem var(--pad);
  }

  .ribbon__card .lockup--art,
.project--solitaire .lockup--art,
.project--imperia .lockup--art {
    max-width: 65%;
  }

  .ribbon__locus {
    grid-row: 2;
    grid-column: 2;
    align-self: stretch;
    justify-self: stretch;
    padding: 0.5rem var(--pad) 0.5rem 0;
  }

  .ribbon__locus strong {
    font-size: 45px;
  }
  .ribbon__locus em {  font-size: 17px;}

  .hscroll .pinIcon {
    width: 34px;
  }

  /* 3 — walkthrough */
  .ribbon__walkthrough {
    grid-row: 3;
    grid-column: 1 / -1;
    justify-self: start;
    padding: 0.5rem var(--pad) var(--pad);
  }

  /* The light theme's aerial CTA block is hidden in this stack, so its
     copy-card twin takes over row 3. */
  .ribbon__walkthrough--mobile {
    display: inline-flex;
  }

  /* 4 — exterior render, full bleed */
  .ribbon__plate--lead {
    grid-row: 4;
    grid-column: 1 / -1;
    width: 100%;
    height: auto;
    aspect-ratio: 4 / 3;
  }

  .ribbon__plate img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  .ribbon__plate--lead::after {
    display: none;
  }

  /* 5 — blurb, centred on the navy field */
  .ribbon__blurb {
    grid-row: 5;
    grid-column: 1 / -1;
    justify-self: center;
    max-width: 32ch;
    margin: 0;
    padding: var(--pad) var(--pad) 0.5rem;
    text-align: center;
    color: #c7d3e0;
  }

  /* 6 — stats, two across, hairline dividers between the four cells */
  .ribbon__statLabel {
    grid-row: 6;
    align-self: end;
    padding: 1rem 0.5rem 0.35rem;
    text-align: center;
    opacity: 0.85;
  }

  .ribbon__statValue {
    grid-row: 7;
    padding: 0 0.5rem 1.25rem;
    text-align: center;
    border-bottom: 1px solid rgba(255, 255, 255, 0.16);
  }

  /* !important beats the light theme's inline flat gridColumn (3 / 4). */
  .ribbon__statSmall {
    grid-row: 8;
    grid-column: auto !important;
    align-self: center;
    padding: 1.25rem 0.5rem;
    text-align: center;
    padding-top: 30px;
  }

  .ribbon__facts .ribbon__statLabel:nth-child(3),
  .ribbon__facts .ribbon__statValue:nth-child(5),
  .ribbon__facts .ribbon__statSmall:nth-child(7) {
    border-left: 1px solid rgba(255, 255, 255, 0.16);
  }

  .ribbon__statValue b {
    font-size: 75px
  }

  .ribbon__statSmall b {
    font-size: 50px;
  }

  .ribbon__statValue em,
  .ribbon__statSmall em {
    font-size: 12px;
  }

  /* 7 — one gold CTA pill, centred */
  .projects .ribbon__card .exbloretwoBtn {
    grid-row: 9;
    grid-column: 1 / -1;
    justify-self: center;
    flex-direction: row;
    align-items: stretch;
    margin: 0.5rem var(--pad) var(--pad);
    border-radius: 999px;
   background-image : linear-gradient(to right, #f6800e, #f9a51a, #f6800e);
       color: #fff;
  }

  .projects .ribbon__card .exbloretwoBtn > .btn {
     color: #fff;
    font-size: 11px;
    padding: 0.9em 1.3em;
    justify-content: center;
  }

  .projects .ribbon__card .exbloretwoBtn > .btn + .btn::before {
    left: 0;
    right: auto;
    top: 28%;
    bottom: 28%;
    width: 1px;
    height: auto;
    background: rgb(255 255 255 / 40%);
  }

  /* Ghost project name drifts behind the render. */
  .ribbon__watermark {
    top: auto;
    bottom: 38%;
    left: 0;
    font-size: clamp(4.5rem, 26vw, 7rem);
    opacity: 0.05;
  }

  .project--solitaire .ribbon__watermark,
.project--imperia .ribbon__watermark {
    left: 0;
  }

  /* Light theme: white intro field above the render, navy below it. */
  .project--light .ribbon__lede,
  .project--light .ribbon__card > div[data-reveal],
  .project--light .ribbon__locus,
  .project--light .ribbon__card .ribbon__walkthrough {
    background: #f1f1f1;
  }

  .project--light .ribbon__locus {
    color: var(--ink-900);
    padding: 0.5rem var(--pad) 0.5rem 0;
  }

  /* Solitaire's desktop grid nudges (fixed widths,
row overrides) would
     break the mobile stack — reset them. */
  .project--solitaire .ribbon__statSmall, .project--imperia .ribbon__statSmall {
    grid-row: 8;
    width: auto;
    padding-top: 30px;
  }
.project--light .ribbon__blurb {
    color: #c7d3e0;
}
  .project--solitaire .ribbon__statValue,
.project--imperia .ribbon__statValue {
    width: auto;
  }
 
  /* ---- Legacy → stacked mobile panel (mobile comp):
     headline → family cutout (ring locked over it) → 2×2 stats overlapping
     the photo's foot. .legacy__inner is flattened with display:contents so
     the media (a sibling of it) can sit between headline and stats. ---- */
  .legacy {
    min-height: 0;
    display: flex;
    flex-direction: column;
    padding: clamp(2.5rem, 10vw, 4rem) 0 0;
  }

   .legacy {
        background-position: center 0;
         background-size: 140%; background-repeat: no-repeat;
 
  }

  
   .legacy:after {
        content: '';
        position: absolute;
        left: 0;
        width: 100%;
        background: linear-gradient(to bottom, transparent, #605c5b 70%);
        height:80%;
        bottom: 0;
        z-index:1;

    }

  .legacy__inner {
    display: contents;
  }

  /* 1 — headline (its .shell padding is gone with display:contents) */
  .legacy__headline {
    order: 1;
    padding: 0 var(--gutter);
    font-size: clamp(1.55rem, 6.6vw, 2.1rem);
    line-height: 1.22;
  }

  /* 2 — the cutout drops into flow between headline and stats */
.legacy__media {
        order: 2;
        position: relative;
        left: 17%;
        top: 45px;
        bottom: auto;
        transform: none;
        width: 43%;
        height: auto;
        margin-top: clamp(1.5rem, 6vw, 2.5rem);
    }

   

  .legacy__media img {
    width: 100%;
    height: auto;
  }

  /* Traced ring, sized to the phone and roughly centred on the family. */
   .legacy__arc, .legacy__arc[data-reveal] {
        left: 38%;
        top: 49%;
        width: 55vw;
        transform: translate(-50%, -50%);
    }
  /* 3 — stats pull up over the photo's foot, as in the comp */
  .legacy__stats {
    order: 3;
    position: relative;
    z-index: 3;
    grid-template-columns: 1fr 1fr;
    gap: clamp(1.5rem, 7vw, 2.5rem) var(--sp-5);
    padding: 0 var(--gutter) clamp(2.5rem, 10vw, 4rem);
    margin-top: 0;
    z-index: 100;
  }

  .legacyStat {
    align-items: center;
    gap: var(--sp-3);
  }

  .legacyStat__num {
    font-size: 105px;
  }

  .legacyStat__unit {
    font-size:55px;
  }

  .legacyStat__sup {
    font-size: 30px;
  }

  .legacyStat__label {
    font-size: 13px;
    letter-spacing: 0.08em;
    padding-top: 0;
  }
 
  /* ---- Commitment → stacked mobile panel (mobile comp):
     centred head on a light field → family cutout on navy → pillars in one
     left-aligned column → footer styled as the closing pillar.
     The desktop background jpg is a wide two-tone composition that cover-crops
     badly on a tall phone stack, so the two fields become flat colours. ---- */
 .commit {
        background-image: url(/media/commitment-family.jpg);
        background-size: 220%;
        background-position: 0 0;
        background-color : #0c2659;
    }

  /* h2.display carries a 90px !important from the wide-screen tweaks above. */
  .commit .commit__title {
    font-size: 40px !important;
    line-height: 1.12;
    text-transform: uppercase;
    font-weight: 700;
    letter-spacing: 0.02em;
  }

  .commit__sub {
    font-size: clamp(0.95rem, 4.2vw, 1.2rem);
  }

  .commit__stage {
     margin-top: clamp(1.5rem, 6vw, 2.5rem);
    padding: clamp(2rem, 8vw, 3rem) 0 clamp(1.5rem, 6vw, 2.5rem);
  }

  /* The cutout joins the flow between the head and the pillars. The wipe
     reveal still runs — it animates clip-path on the img, not position. */
  .commit__media {
    position: relative;
    inset: auto;
    top: auto;
    z-index: 1;
  }

  .commit__media img {
    width: min(88vw, 420px);
  }

  /* Pillars: one column, everything reads from the left. */
  /* ---- Mobile: the four pillars become one horizontal rail instead of a
     stack. The gutter padding doubles as the scroll gutter, so a card is
     always part-visible at the right edge. Desktop is untouched. ---- */
  .commit__grid {
    display: flex;
    flex-wrap: nowrap;
    align-items: flex-start;
    gap: var(--cg-gap);
    padding: clamp(2rem, 8vw, 3rem) var(--gutter) clamp(2.5rem, 10vw, 4rem);
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x proximity;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    scroll-padding-inline: var(--gutter);
    --cg-gap: clamp(0.875rem, 4vw, 1.5rem);
  }

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

  /* The lists stay real lists — they just lay their pillars along the rail.
     (display:contents would flatten them but drops list semantics.) */
  .commit__col {
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    gap: var(--cg-gap);
    flex: 0 0 auto;
    margin: 0;
    padding: 0;
  }

  .pillar,
  .commit__grid > .commit__footer {
    flex: 0 0 auto;
    width: min(64vw, 260px);
    scroll-snap-align: start;
  }

  .pillar--right {
    text-align: left;
  }

  .pillar--right .pillar__title,
  .pillar--right .pillar__body {
    margin-left: 0;
  }

  .commit h3 {
    font-size: clamp(1.35rem, 6vw, 1.75rem);
  }

  /* The desktop 155px lock is too tight here — cap by characters instead so
     each title still breaks after its first sentence, as in the comp. */
  .commit ul li h3 {
    width: auto;
    max-width: 45ch;
  }

  .pillar__body {
    max-width: 34ch;
  }

  /* Footer is the closing card of the rail — the rail already carries the
     side gutter and the bottom spacing, so it needs no padding of its own. */
  .commit__footer {
    text-align: left;
    margin: 0;
    padding: 0;
  }

  .commit__footer-title {
    font-family: var(--font-display);
    font-size: clamp(1.35rem, 6vw, 1.75rem);
    line-height: 1.05;
    max-width: 100%;
  }

  .commit__footer-body {
    margin-inline: 0;
    max-width: 34ch;
    font-size: 14px;
  }
 
  /* ---- Quality → stacked mobile panel (mobile comp):
     gold title → two-line sub → photo-filled 50,000+ across the width →
     lead → body + gold pill → centred AI band. ---- */
  .quality {
    padding: clamp(3rem, 10vw, 4rem) 0;
  }

  .quality__inner {
    padding: 0 var(--gutter);
  }

  .quality__head {
    display: grid;
    grid-gap: var(--sp-2);
    gap: var(--sp-2);
  }

  /* h2.display carries a 90px !important from the wide-screen tweaks above. */
  .quality .quality__title {
    font-size: 55px !important;
    text-transform: uppercase;
    font-weight: 700;
    line-height: 1.05;
  }

  .quality__sub {
    font-size: clamp(1.05rem, 4.6vw, 1.35rem);
  }

  /* The desktop numeral is a fixed 440px/384px with -30px tracking — both
     rescale to the phone width; the photo pan keeps running behind it. */
  .quality__counter {
    font-size: clamp(4.2rem, 21vw, 7rem);
    letter-spacing: -1px;
  }

  .quality__counter-comma {
    font-size: 0.55em;
  }

  /* Copy stacks: lead, then body + CTA (it's a flex row on desktop). */
  .quality__copy {
    flex-direction: column;
    align-items: flex-start;
    justify-content: flex-start;
    gap: var(--sp-5);
    margin: 0;
  }

  .quality__lead {
    font-size: clamp(1.5rem, 6.4vw, 2rem);
    max-width: 22ch;
  }

  .quality__aside {
    max-width: 40ch;
  }

  /* AI band: the three-column head becomes one centred stack around the chip;
     the desktop copy nudges (right/-100px, left/-50px) reset. */
  .quality__ai {
    padding-block: clamp(2.5rem, 10vw, 4rem);
  }

  .quality__ai-head {
    --chip-w: clamp(88px, 24vw, 130px);
    grid-template-columns: 1fr;
    gap: clamp(0.75rem, 3vw, 1.25rem);
    font-size: clamp(1.5rem, 6.6vw, 2.1rem);
  }

  .quality__ai-head span,
  .quality__ai-head span:last-child {
    text-align: center;
    left: 0;
    right: 0;
  }

  .quality__ai-body {
    font-size: clamp(1rem, 4.4vw, 1.25rem);
    max-width: 34ch;
  }
 
  .stories__head {
    position: static;
    opacity: 1;
    transform: none;
  }

  .stories__grid {
    grid-template-columns: 1fr;
    row-gap: clamp(1.25rem, 4vw, 2rem);
    margin-top: clamp(2rem, 6vw, 3rem);
  }

  .story,
  .storyVideo {
    grid-column: 1 !important;
    grid-row: auto !important;
    translate: none;
    margin-top: 0 !important;
  }
 
  /*
    The title keeps its 100px on desktop, which is the site-wide display size.
    That number comes from `h2.display { font-size: 100px !important }` at the
    top of this file — a flat px value with no responsive floor, so at phone
    widths "PASSPORT" alone is wider than the content box and the heading spills
    out of the section. Matching !important is the only way to reach past it;
    scoped to this heading so the rest of the site is untouched.
  */
  .passport__title {
    font-size: clamp(2.25rem, 9vw, 4.5rem) !important;
  }

  /* ---- mobile comp: left-aligned head → four ruled feature blocks →
     the device render closing the section over the navy base strip. ---- */
  .passport {
    padding-top: clamp(2.5rem, 10vw, 4rem);
  }

  /* The desktop head is pushed 210px down / 83px in to sit with the rig —
     back into flow here; .shell already carries the gutter. */
  .passport .maskUp {
    top: 0;
  }

  .passport .maskUp h2.display {
    padding: 0;
  }

  /* "Radiance Passport" reads as one line, tagline drops underneath. */
  .passport__title--navy {
    margin-right: 0;
  }

  .passport__title small {
    flex-basis: 100%;
    top: 0;
    margin-top: 0.4em;
  }

  .passport__watermark {
    display: none;
  }

  /* ---- Mobile: four feature cards as one horizontal rail, the render on
     the row beneath. The rail bleeds to both screen edges so a partly
     visible card signals there is more to swipe. Desktop is untouched. ---- */
  .passport__grid {
    grid-template-columns: minmax(0, 1fr);
    gap: clamp(1.5rem, 6vw, 2.25rem);
    --pg-gap: clamp(0.875rem, 4vw, 1.5rem);
  }

  .passport__rail {
    display: flex;
    flex-wrap: nowrap;
    align-items: flex-start;
    gap: var(--pg-gap);
    order: 0;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x proximity;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    margin-inline: calc(var(--gutter) * -1);
    padding-inline: var(--gutter);
    scroll-padding-inline: var(--gutter);
  }

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

  /* The lists stay real lists — they just lay their cards along the rail.
     (display:contents would flatten them but drops list semantics.) */
  .passport__col {
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    gap: var(--pg-gap);
    flex: 0 0 auto;
    margin: 0;
    padding: 0;
    top: 0;
  }

  .passport__col--left { order: 0; }
  .passport__col--right { order: 1; }

  .pfeature {
    flex: 0 0 auto;
    width: min(72vw, 300px);
    scroll-snap-align: start;
  }

  /* Next row, on its own, centred. */
  .passport__device {
    order: 1;
    margin: 0;
  }

  /* Single column, so the diagonal nudge and the mirrored alignment both go —
     everything hangs off one rule on the left. */
  .passport__col--left .pfeature:nth-child(2),
  .passport__col--right .pfeature:nth-child(2) {
    --dx: 0px;
  }

  .pfeature--left {
    text-align: left;
    padding-right: 0;
    padding-left: var(--sp-4);
    --fx: -28px;
  }

  .pfeature--left::before {
    right: auto;
    left: 0;
  }

  .pfeature--left p { margin-left: 0; }

  .pfeature p {
    max-width: 34ch;
  }

  /* The render is a fixed 700px on desktop — cap it to the phone. */
  .passport__float {
    width: min(92vw, 420px);
  }

  /* Orbits sit behind the device, which now lives at the foot. */
  .passport__orbits {   top: 81%;    width: 120%;   max-width: 120%; } 
 
  .passport--pd .maskUp h2.display {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto;
    justify-items: center;
  }

  .passport--pd .passport__title--navy,
  .passport--pd .passport__title--gold,
  .passport--pd .passport__title small {
    grid-area: auto;
    justify-self: center;
  }

  .passport--pd .passport__title small {
    text-align: center;
  }

  .passport--pd .passport__grid,
  .passport--pd .passport__device {
    margin-top: 0;
  }
  .faq__inner { grid-template-columns: 1fr; }
  .faq__mark { display: none; }
  /* ---- NRI → mobile comp: two-line gold/white head up top, the flight
     photo left visible beneath it, the staggered cards riding over the
     photo's lower half, one gold CTA pill centred at the foot. ---- */
  .nri__title,
  .nri__sub {
    font-size: clamp(1.5rem, 6.8vw, 2rem);
    line-height: 1.18;
  }

  /* Clear space over the background photo so the cabin scene reads before
     the cards arrive over its lower half. */
  .nri__list {
    max-width: 100%;
    margin-top: clamp(13rem, 58vw, 19rem);
  }

  .nriItem {
    max-width: 84%;
    padding: 20px 20px;
    gap: var(--sp-3);
    font-size: 19px;
  }

  /* One gold pill, centred — both action halves ride it in a row even below
     the 560px stack breakpoint in globals. */
  .nri__actions {
    display: flex;
    justify-content: center;
    margin-top: clamp(2rem, 8vw, 3rem);
  }

  .nri .exbloretwoBtn {
    flex-direction: row;
    align-items: stretch;
    border-radius: 999px;
    background: linear-gradient(90deg, #f6a832 0%, #e8890f 100%);
  }

  .nri .exbloretwoBtn > .btn {
    color: #fff;
    font-size: 11px;
    padding: 0.95em 1.2em;
    justify-content: center;
  }

  .nri .exbloretwoBtn > .btn + .btn::before {
    left: 0;
    right: auto;
    top: 28%;
    bottom: 28%;
    width: 1px;
    height: auto;
    background: rgba(255, 255, 255, 0.55);
  }

  /* ---- Footer → mobile comp: city accordions with + toggles, stacked
     enquiries, left-aligned links, ghost brand closing the section. ---- */
  .footer__cities {
    grid-template-columns: 1fr;
    gap: 0;
  }

  .footerCity {
    border-bottom: 1px solid rgba(255, 255, 255, 0.14);
    opacity: 1;
    transform: initial;
  }

  .footerCity__name {
    margin-bottom: 0;
    font-size: clamp(1.5rem, 6.4vw, 1.9rem);
    color: rgba(255, 255, 255, 0.9);
  }

  /* The heading becomes a live accordion toggle at this width. */
  .footerCity__toggle {
    pointer-events: auto;
    cursor: pointer;
    padding-block: clamp(0.9rem, 4vw, 1.25rem);
  }

  /* The + : two bars, the vertical one folds away when open. */
  .footerCity__icon {
    display: block;
    position: relative;
    flex: none;
    width: 16px;
    height: 16px;
  }

  .footerCity__icon::before,
  .footerCity__icon::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 50%;
    translate: -50% -50%;
    background: rgba(255, 255, 255, 0.75);
    transition: rotate 0.35s var(--ease), opacity 0.35s var(--ease);
  }

  .footerCity__icon::before {
    width: 16px;
    height: 2px;
  }

  .footerCity__icon::after {
    width: 2px;
    height: 16px;
  }

  .footerCity.is-open .footerCity__icon::after {
    rotate: 90deg;
    opacity: 0;
  }

  /* Collapse via the grid-rows trick, so height animates without JS
     measurement. */
  .footerCity__panel {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows 0.45s var(--ease);
  }

  .footerCity__panelInner {
    overflow: hidden;
  }

  .footerCity.is-open .footerCity__panel {
    grid-template-rows: 1fr;
  }

  .footerCity__panelInner .footerCity__group:last-child {
    padding-bottom: clamp(1rem, 4vw, 1.5rem);
  }

  /* Enquiries: legend on the rule, contacts stacked below. */
  .footer__enquiries {
    margin-top: clamp(1.75rem, 7vw, 2.5rem);
  }

  .footer__legend {
    left: 34%;
        padding-left: 15px;
    font-size: clamp(1.35rem, 5.8vw, 1.65rem);
  }

  .footer__contactRow {
    flex-direction: column;
    align-items: stretch;
    gap: clamp(1.25rem, 5vw, 1.75rem);
  }

  .footer__social {
    margin-left: 0;
  }

  /* Base: links + copyright first, the ghost brand closes the footer. */
  .footer__base {
    grid-template-columns: 1fr;
  }

  .footer__brand {
    order: 2;
    overflow: hidden;
  }

  .footer__brand img,
  .footer__brand svg {
    width: 100%;
    height: auto;
  }

  .footer__links {
    row-gap: 0.5em;
  }

  .footer__links a:first-child {
    padding-left: 0;
  }

  .footer__copyRow {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--sp-2);
  }

  .footer__copy {
    padding-left: 0;
  }

  .footer__designBy {
    margin-top: 0;
  }
  .memories__media img {
    width: 100%;
    height: 50%;
    object-fit: cover;
    object-position: center 35%;
}
.memories { min-height: auto;}

  /* --- Journey Wall ------------------------------------------------------
     The wall is a 3852-wide canvas placed from comp coordinates; at phone
     width there is no honest way to reproduce it, so the same milestones
     become a paged slider. Two rows filling sideways means the DOM order
     pairs them a column per era — 1949/1950, then 1980/1984 — which is how
     the wall pairs them too. Intro full width above, arrows under the cards,
     the photograph closing the section. */

  .timeline { height: auto; }

  .timeline .hscroll__wrap {
    position: static;
    height: auto;
    overflow: visible;
  }

  .timeline .hscroll__track {
    position: static;
    display: block;
    transform: none !important;
  }

  .timeline__intro {
    flex: 0 0 auto;
    width: 100%;
    height: auto;
  }

  .timeline__intro-inner {
    padding: clamp(2rem, 7vw, 4rem);
    gap: var(--sp-5);
  }

  .timeline__heading { font-size: clamp(2rem, 1.2rem + 3vw, 3.2rem); }
  .timeline__blurb { font-size: var(--fs-body-sm); }

  /* A plain column: cards, arrows, photograph. `order` puts the wave last
     without moving it in the DOM, where it belongs to the wall. */
  .timeline__rail {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    width: 100%;
    height: auto;
    padding: clamp(2rem, 8vw, 3.5rem) 0 0;
    overflow: hidden;
  }

  .timeline__list {
    order: 1;
    position: static;
    display: grid;
    grid-auto-flow: column;
    /* Just under two-thirds of the screen, so the next column always shows a
       sliver — the one thing that says the row continues. */
    grid-auto-columns: clamp(210px, 64vw, 300px);
    grid-template-rows: repeat(2, auto);
    grid-gap: clamp(1.75rem, 6vw, 2.75rem) clamp(1.25rem, 5vw, 2rem);
    gap: clamp(1.75rem, 6vw, 2.75rem) clamp(1.25rem, 5vw, 2rem);
    align-items: start;
    padding-inline: var(--gutter);
    overflow-x: auto;
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x mandatory;
    scroll-padding-inline: var(--gutter);
    scrollbar-width: none;
  }

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

  .milestone {
    position: relative;
    left: auto;
    top: auto;
    width: auto;
    padding: 0;
    scroll-snap-align: start;
  }

  .milestone__body { padding-left: 0; }
  .milestone__body + .milestone__body { margin-top: var(--sp-5); }

  /* The connector lines and dots belong to the wave; there is no wave behind
     the cards here for them to reach. */
  .milestone__stem { display: none; }

  .milestone__year { font-size: clamp(1.7rem, 1rem + 3vw, 2.4rem); }

  .milestone__title {
    font-size: 19px;
    line-height: 1.2;
    margin-top: 0.3em;
    color: #26608e;
     
  }

  .milestone__text,
  .milestone__note {
    font-size: 14px;
    line-height: 1.5;
    margin-top: 0.6em;
    
  }

  /* --- Arrows --- */
  .timeline__nav {
    order: 2;
    display: flex;
    justify-content: center;
    gap: clamp(1.5rem, 9vw, 3.25rem);
    padding: clamp(1.75rem, 7vw, 3rem) 0;
  }

  .timeline__navBtn {
    display: grid;
    place-items: center;
    width: 44px;
    height: 44px;
    padding: 0;
    border: 1px solid rgba(12, 58, 108, 0.28);
    border-radius: 50%;
    background: none;
    color: var(--navy-500);
    cursor: pointer;
    transition: opacity 0.3s var(--ease), border-color 0.3s var(--ease),
      background-color 0.3s var(--ease);
  }

  .timeline__navBtn svg { width: 20px; height: 20px; }

  .timeline__navBtn:hover:not(:disabled) {
    border-color: var(--navy-500);
    background: rgba(12, 58, 108, 0.06);
  }

  /* Dimmed rather than removed — a control that disappears at the end of the
     row moves the one beside it. */
  .timeline__navBtn:disabled {
    opacity: 0.3;
    cursor: default;
  }

  /* The photograph closes the section. */
  .timeline__wave {
    order: 3;
    position: static;
    width: 100%;
    height: auto;
    max-width: 100%;
    margin-top: 0;
  }

  /* The rail reveal is a scroll-progress effect on the pinned rig. With no
     rig there is no progress to read, so every milestone is simply present —
     otherwise the cards off the right edge would never be revealed at all. */
  .timeline[data-rail-anim] .milestone__stem,
  .timeline[data-rail-anim] .milestone__stem i,
  .timeline[data-rail-anim] .milestone__year,
  .timeline[data-rail-anim] .milestone__title,
  .timeline[data-rail-anim] .milestone__text,
  .timeline[data-rail-anim] .milestone__note {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .timeline__nav { display: flex; }

.commit__col {
        display: flex;
    }
     
  #timeline-title {
    display: block;
  }

  #timeline-title span {
    display: inline;    padding: 0 4px;
  }

  #timeline-title span:nth-child(2)::after {
    content: "";
    display: block;
  }
.sideCta .sideCta__btn--call, .sideCta .sideCta__btn--enquire{display: none;}
.sideCta__btn {  background: #18a918; }
.sideCta {   background: transparent;  border: none;   box-shadow: none;
}
.passport--pd .passport__title--navy {
    grid-area: 1 / 1;
    justify-self: end;
    margin-right: 0;
    margin-left: 0;
}
    .spTab {
         white-space: nowrap;
    }
      .memories__media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center 35%;
}
  .memories { min-height: 800px;  padding: 60px 0 0; }
  .memories::before{content: '';   position: absolute;
        left: 0;    width: 100%; background: linear-gradient(to bottom, #6d4500, transparent);  height: 40%; top: 0;}
        .memories__inner {  padding-block: 0; }
        .sideCta {  top: 76%;}
        .project--navy {
    background-image: linear-gradient(to right, #003065, #003e79);
}
.header__inner {   padding: 0;   }
 .header__inner {   justify-content:center; }
 .homeBanner .image-container{padding-top: 100px;}
 .header.is-scrolled .logo {  height:45px; }
}


/* ---------------- narrow screens ---------------- */
/* ≤900px the pin hook still runs (same scroll animation as desktop); the
   mobile-only .is-pinned tweaks sit beside the homeBanner styles. Restack it as one centred column:
   headline → circular photo → copy → 76+ stat → CTA. The desktop grids
   (.bannerText, .right, .bottom) are flattened with display:contents so
   their children can be reordered as direct flex items. */

@media (max-width: 900px) {
  .project--light .ribbon__cardOut--copy {   background-color: #fff; 
}
  .image-container {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    gap: clamp(1.5rem, 4.5vh, 2.25rem);
    min-height: 100svh;
    padding: 30px 0 50px;
    background: var(--navy-900);
  }

  .image-container .bannerText,
  .image-container .bannerText .right,
  .image-container .bottom {
    display: contents;
  }

  /* desktop-only pieces */
  .image-container .bannerText .center,
  .image-container .bottom .locations,
  .image-container .bottom .scroll {
    display: none;
  }

  /* 1 — headline */
  .image-container .bannerText .left {
    order: 1;
    text-align: center;
  }

  .image-container .bannerText .left h2 {
    font-size: 70px;
    line-height: 1.3;
    letter-spacing: 0.01em;
    text-wrap: balance;
  }

  /* 4 stacked spans flow into the mockup's two lines:
     "Homes Built on Trust." / "Radiance Living Experience." */
  .image-container .bannerText .left h2 span {
    display: inline;
    margin-right: 0.28em;
  }

  .image-container .bannerText .left h2 span:nth-child(2)::after {
    content: "\A";
    white-space: pre;
  }

  /* 2 — the photograph becomes a centred circle, not a full-bleed backdrop.
     The image itself is swapped to /images/m-intro-img.png by the <source>
     in HomeBanner.jsx — a background here sits behind the <img> bitmap and
     never shows. */
  .image-container .img {
    order: 2;
    position: static;
    inset: auto;
    width: min(66vw, 270px);
    height: min(66vw, 270px);
    border-radius: 50%;
    object-fit: cover;
  }

  /* 3 — body copy */
  .image-container .bannerText .right p {
    order: 3;
    max-width: 36ch;
    margin: 0;
    line-height: 1.65;
    color: rgba(255, 255, 255, 0.78);
  }

  /* 4 — 76+ stat */
  .image-container .bottom .years {
    order: 4;
    justify-content: center;
    gap: var(--sp-3);
  }

  .image-container .bottom .years h3 {
    font-size: 120px;
  }

  .image-container .bottom .years p {
    text-align: left;
    padding-top: 28px;;
  }

  /* 5 — CTA */
  .image-container .bannerText .right .exbloretwoBtn {
    order: 5;
    margin: 0 auto;
  }

      .image-container .bannerText .left h2 {  font-size: 58px;  line-height: 1;}
       .footer__brand img, .footer__brand svg {  width: 68%;}
       .footer {  padding: 0 28px 91px;  }
       .mobileDock img{width: 30px;}
       .mobileDock .mobileDock__brand img {width: auto;}
           h2.display {    font-size: 60px !important;   }
               .mobileDock img {   width: 25px;  }
}



@media (max-width: 900px) {
  .mobileDock {
    display: none !important;
  }

  .header .burger {
    display: grid;
  }

  .footer {
    padding-bottom: calc(clamp(2rem, 4vw, 3rem) + 24px);
  }

}

@media (prefers-reduced-motion: reduce) {
  .sideCta .sideCta__actions .sideCta__btn,
  .sideCta .sideCta__toggle img {
    transition: none;
  }
  .sideCta__btn svg, .sideCta__icon {
    filter: brightness(1) invert(0);
}
}


@media (max-width:780px) {
     .header.is-scrolled .header__inner {   min-height: 52px; }
       .header .header__inner {   min-height: 52px; }
     .header {  height: 50px; }
     .header.is-scrolled .logo {  height:40px; }
.commit__col {
        display: grid;
    }
  .siteMenu {
    grid-template-columns: 1fr;
    grid-template-rows: auto 1fr;
    overflow-y: auto;
  }

  .siteMenu__panel {
    overflow: visible;
    padding: 30px;
  }

  .siteMenu__cities {
    grid-template-columns: 1fr;
    height: auto;
  }

  .menuCity {
    border-left: 0;
    border-top: 1px solid rgba(12, 58, 108, 0.08);
    min-height: 132px;
  }

  .menuCity__link {
    display: flex;
    align-items: center;
    padding-block: clamp(1.25rem, 4vw, 2rem);
  }

  .menuCity__watermark {
    writing-mode: horizontal-tb;
    transform: none;
    left: auto;
    right: clamp(0.5rem, 3vw, 2rem);
    bottom: auto;
    top: 50%;
    translate: 0 -50%;
    font-size: clamp(2.5rem, 12vw, 5rem);
  }

  .menuCity__media {
    inset: 0;
  }

 
  .bImg {
    min-height: 100svh;
  }

  /* .image-container / .bannerText / .bottom mobile restack lives in the
     "narrow screens" block beside the homeBanner styles (~line 975). */
 
  /* ---- Projects intro: centred head + full-width tabs (mobile comp) ---- */

  .projects__intro {
    padding-block: clamp(3.5rem, 12vw, 5rem) 0;
  }

  .projects__marquee em {
    font-size: clamp(3rem, 15vw, 4.5rem);
  }

  .projects__head {
    padding-top: clamp(3rem, 12vw, 4.5rem);
    gap: var(--sp-2);
  }

  /* h2.display carries a 90px !important from the wide-screen tweaks above,
     so this needs !important too (higher specificity wins the tie). */
  .projects .projects__heading {
    font-size: clamp(3.125rem, 9vw, 3.75rem) !important;
    line-height: 1.12;
    text-transform: uppercase;
    font-weight: 700;
    letter-spacing: 0.02em;
    max-width: 16ch;
  }

  /* Same tab row as the 900px block — repeated here only because this block
     would otherwise inherit nothing and fall back to the desktop rules. */
  .projects__tabs {
    width: 100%;
    flex-wrap: nowrap;
    justify-content: space-between;
    gap: clamp(0.75rem, 4vw, 2.5rem);
    margin-top: var(--sp-5);
    padding-block: var(--sp-3);
    border-top: 1px solid var(--line);
    border-bottom: 1px solid var(--line);
  }

  .projects__tab {
    flex: 0 0 auto;
    white-space: nowrap;
    font-size: clamp(1.05rem, 4.6vw, 1.5rem);
    font-weight: 500;
    padding-bottom: var(--sp-2);
  }

  .projects__tab::after {
    height: 4px;
  }

  /* ---- Project ribbon → stacked mobile panel (mobile comp order):
     lede → lockup + place → walkthrough → render → blurb → 2×2 stats → CTA.
     The horizontal rig is off at this width, so the nested cardOut / card /
     facts wrappers are flattened with display:contents and every block is
     placed explicitly on one two-column grid. ---- */

  .ribbon {
    --pad: clamp(1.25rem, 5vw, 2rem);
    display: grid;
    grid-template-columns: 1fr 1fr;
    grid-gap: 0;
    gap: 0;
    height: auto;
  }

  .ribbon::before,
  .ribbon__cardOut::before {
    display: none;
  }

  .ribbon__cardOut,
  .ribbon__card,
  .ribbon__facts {
    display: contents;
  }

  /* Desktop-only blocks: closing statement, tower + aerial plates and the
     CTAs riding the aerial. */
  .ribbon__plate--tower,
  .ribbon__plate--aerial,
  .ribbon__statement,
  .ribbon__factsStatement,
  .ribbon__plate-cta {
    display: none;
  }

  /* 1 — lede */
  .ribbon__lede {
    grid-row: 1;
    grid-column: 1 / -1;
    margin: 0;
    padding: var(--pad) var(--pad) 0.75rem;
    font-size: clamp(1.5rem, 6.4vw, 2rem);
  }

  /* 2 — project lockup with the place beside it */
  .ribbon__card > div[data-reveal] {
    grid-row: 2;
    grid-column: 1;
    display: flex;
    align-items: center;
    padding: 0.5rem 0 0.5rem var(--pad);
  }

  .ribbon__card .lockup--art,
.project--solitaire .lockup--art,
.project--imperia .lockup--art {
    max-width: min(100%, 160px);
  }

  .ribbon__locus {
    grid-row: 2;
    grid-column: 2;
    align-self: stretch;
    justify-self: stretch;
    padding: 0.5rem var(--pad) 0.5rem 0;
  }
.project--light::before{content:""; position: absolute; background: #fff; width: 100%; height: 45%;}
  .ribbon__locus strong {
    font-size: 27px;
  }
  .legacy__headline-line {
    display: inline; padding-right: 10px;
}
.timeline {
        display: none;
    }
    .ribbon__locus em {
        font-size: 13px;
    }
    .hscroll.project--light .pinIcon {
    color: #194e83;
}
   .hscroll.project--light .ribbon__locus strong {
         color: #194e83;
    }

  .hscroll .pinIcon {
    width: 34px;
  }

  /* 3 — walkthrough */
  .ribbon__walkthrough {
    grid-row: 3;
    grid-column: 1 / -1;
    justify-self: start;
    padding: 0.5rem var(--pad) var(--pad);
  }

  /* The light theme's aerial CTA block is hidden in this stack, so its
     copy-card twin takes over row 3. */
  .ribbon__walkthrough--mobile {
    display: inline-flex;
  }

  /* 4 — exterior render, full bleed */
  .ribbon__plate--lead {
    grid-row: 4;
    grid-column: 1 / -1;
    width: 100%;
    height: auto;
    aspect-ratio: 4 / 3;
  }

  .ribbon__plate img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  .ribbon__plate--lead::after {
    display: none;
  }

  /* 5 — blurb, centred on the navy field */
  .ribbon__blurb {
    grid-row: 5;
    grid-column: 1 / -1;
    justify-self: center;
    max-width: 90%;
    margin: 0;
    padding: var(--pad) var(--pad) 0.5rem;
    text-align: center;
    color: #c7d3e0;
  }

  /* 6 — stats, two across, hairline dividers between the four cells */
  .ribbon__statLabel {
    grid-row: 6;
    align-self: end;
    padding: 1rem 0.5rem 0.35rem;
    text-align: center;
    opacity: 0.85;
  }

  .ribbon__statValue {
    grid-row: 7;
    padding: 0 0.5rem 1.25rem;
    text-align: center;
    border-bottom: 1px solid rgba(255, 255, 255, 0.16);
  }

  /* !important beats the light theme's inline flat gridColumn (3 / 4). */
  .ribbon__statSmall {
    grid-row: 8;
    grid-column: auto !important;
    align-self: center;
    padding: 1.25rem 0.5rem;
    text-align: center;
    padding-top: 30px;
  }

  .ribbon__facts .ribbon__statLabel:nth-child(3),
  .ribbon__facts .ribbon__statValue:nth-child(5),
  .ribbon__facts .ribbon__statSmall:nth-child(7) {
    border-left: 1px solid rgba(255, 255, 255, 0.16);
  }

  .ribbon__statValue b {
    font-size: 55px;
  }
   .ribbon__card .lockup--art, .project--solitaire .lockup--art, .project--imperia .lockup--art {
        max-width: min(88%, 160px);
    }

  .ribbon__statSmall b {
    font-size: 38px;
  }

  .ribbon__statValue em,
  .ribbon__statSmall em {
    font-size: 12px;
  }

  /* 7 — one gold CTA pill, centred */
  .projects .ribbon__card .exbloretwoBtn {
    grid-row: 9;
    grid-column: 1 / -1;
    justify-self: center;
    flex-direction: row;
    align-items: stretch;
    margin: 0.5rem var(--pad) var(--pad);
    border-radius: 999px;
    background-image : linear-gradient(to right, #f6800e, #f9a51a, #f6800e);
  }

  .projects .ribbon__card .exbloretwoBtn > .btn {
    color: #fff;
    font-size: 11px;
    padding: 0.9em 1.3em;
    justify-content: center;
  }

  .projects .ribbon__card .exbloretwoBtn > .btn + .btn::before {
    left: 0;
    right: auto;
    top: 28%;
    bottom: 28%;
    width: 1px;
    height: auto;
    background: rgb(255 255 255 / 40%);
  }

  /* Ghost project name drifts behind the render. */
  .ribbon__watermark {
           top: auto;     bottom: 29%; left: 0;
        font-size: clamp(4.5rem, 26vw, 7rem);  opacity: 0.04;
        display: flex;  justify-content: center;  align-items: center;  width: 100%;
  }

  .project--solitaire .ribbon__watermark,
.project--imperia .ribbon__watermark {
    left: 0;
  }

  /* Light theme: white intro field above the render, navy below it. */
  .project--light .ribbon__lede,
  .project--light .ribbon__card > div[data-reveal],
  .project--light .ribbon__locus,
  .project--light .ribbon__card .ribbon__walkthrough {
    background: #f1f1f1;
  }

  .project--light .ribbon__locus {
    color: var(--ink-900);
    padding: 0.5rem var(--pad) 0.5rem 0;
  }

  /* Solitaire's desktop grid nudges (fixed widths,
row overrides) would
     break the mobile stack — reset them. */
  .project--solitaire .ribbon__statSmall,  .project--imperia .ribbon__statSmall {
    grid-row: 8;
    width: auto;
    padding-top: 30px;
  }
.project--light .ribbon__blurb {
    color: #c7d3e0;
}
  .project--solitaire .ribbon__statValue,
.project--imperia .ribbon__statValue {
    width: auto;
  }
 
  /* ---- Legacy → stacked mobile panel (mobile comp):
     headline → family cutout (ring locked over it) → 2×2 stats overlapping
     the photo's foot. .legacy__inner is flattened with display:contents so
     the media (a sibling of it) can sit between headline and stats. ---- */
  .legacy {
    min-height: 0;
    display: flex;
    flex-direction: column;
    padding: clamp(2.5rem, 10vw, 4rem) 0 0;

  }

    .legacy {
        background-position: center 0;
        background-size: 209%;
    }

 .legacy:after {
        content: '';
        position: absolute;
        left: 0;
        width: 100%;
        height: 40%;
        bottom: 0;
    }

  .legacy__inner {
    display: contents;
  }

  /* 1 — headline (its .shell padding is gone with display:contents) */
  .legacy__headline {
    order: 1;
    padding: 0 var(--gutter);
    font-size: clamp(1.55rem, 6.6vw, 2.1rem);
    line-height: 1.22;
  }

  /* 2 — the cutout drops into flow between headline and stats */
     .legacy__media {
        order: 2;
        position: relative;
        left: 10%;
        top: 0;
        bottom: auto;
        transform: none;
        width:90%;
        height: auto;
         margin-top: 122px;
    }
  .legacy__media img {
    width: 100%;
    height: auto;
  }

  /* Traced ring, sized to the phone and roughly centred on the family. */
.legacy__arc, .legacy__arc[data-reveal] {
        left: 10%;
        top: 22%;
        width: 67vw;
        transform: translate(-50%, -50%);
    }

  /* 3 — stats pull up over the photo's foot, as in the comp */
  .legacy__stats {
    order: 3;
    position: relative;
    z-index: 3;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
    padding: 0 var(--gutter) clamp(2.5rem, 10vw, 4rem);
    margin-top: 0;
    z-index: 100;
  }

  .legacyStat {
    align-items: center;
    gap: 0;
  }

  .legacyStat__num {
    font-size: 75px;
  }

  .legacyStat__unit {
    font-size: 35px;
  }

    .legacyStat__sup {
        font-size: 19px;
        color: #fff;
        margin: -10px 0 0 0;
    }

  .legacyStat__label {
    font-size: 13px;
    letter-spacing: 0.08em;
       padding-top: 0;
        position: relative;
        top: 13px;
  }

 .story__body {
    font-size: 15px;
}
.story { padding: 80px 30px 80px;}
.passport__device[data-reveal].is-visible {
    pointer-events: none;
}
 
.pfeature[data-reveal].is-visible {
    opacity: 1;
    transform: inherit;
}
.pfeature[data-reveal] {
    opacity: 1;
    transform: inherit;
}
  /* ---- Commitment → stacked mobile panel (mobile comp):
     centred head on a light field → family cutout on navy → pillars in one
     left-aligned column → footer styled as the closing pillar.
     The desktop background jpg is a wide two-tone composition that cover-crops
     badly on a tall phone stack, so the two fields become flat colours. ---- */
 .commit {
        background-image: url(/media/commitment-family.jpg);
        background-size: 220%;
        background-position: 0 0;
        background-color : #0c2659;
    }

  /* h2.display carries a 90px !important from the wide-screen tweaks above. */
  .commit .commit__title {
    font-size: 45px !important;
    line-height: 1.12;
    text-transform: uppercase;
    font-weight: 700;
    letter-spacing: 0.02em;
  }
      .delivery {
        flex: 0 0 clamp(310px, 28vw, 500px);
    }
    .zero__track {  gap: 25px;}
  .commit {
     padding: 37px 0 0;
}

  .commit__sub {
    font-size: clamp(0.95rem, 4.2vw, 1.2rem);
  }

  .commit__stage {
     margin-top: clamp(1.5rem, 6vw, 2.5rem);
    padding: clamp(2rem, 8vw, 3rem) 0 clamp(1.5rem, 6vw, 2.5rem);
  }

  /* The cutout joins the flow between the head and the pillars. The wipe
     reveal still runs — it animates clip-path on the img, not position. */
  .commit__media {
    position: relative;
    inset: auto;
    top: auto;
    z-index: 1;
  }

  .commit__media img {
    width: min(88vw, 420px);
  }

  /* Pillars: one column, everything reads from the left. */
  /* ---- Mobile: the four pillars become one horizontal rail instead of a
     stack. The gutter padding doubles as the scroll gutter, so a card is
     always part-visible at the right edge. Desktop is untouched. ---- */
  .commit__grid {
    display: flex;
    flex-wrap: nowrap;
    align-items: flex-start;
    gap: var(--cg-gap);
    padding: clamp(2rem, 8vw, 3rem) var(--gutter) clamp(2.5rem, 10vw, 4rem);
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x proximity;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    scroll-padding-inline: var(--gutter);
    --cg-gap: clamp(0.875rem, 4vw, 1.5rem);
  }

  .commit__grid::-webkit-scrollbar {
    display: none;
  }
  .bImg__headline { font-size: 55px; line-height: 1;  padding-right:60px;}
  .image-container{padding: 30px 0 50px;}
.delivery__months{font-size: 30px;}

  /* The lists stay real lists — they just lay their pillars along the rail.
     (display:contents would flatten them but drops list semantics.) */
  .commit__col {
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    gap: var(--cg-gap);
    flex: 0 0 auto;
    margin: 0;
    padding: 0;
  }

  .pillar,
  .commit__grid > .commit__footer {
    flex: 0 0 auto;
    width: min(64vw, 260px);
    scroll-snap-align: start;
  }

  .pillar--right {
    text-align: left;
  }

  .pillar--right .pillar__title,
  .pillar--right .pillar__body {
    margin-left: 0;
  }

  .commit h3 {
    font-size: clamp(1.35rem, 6vw, 1.75rem);
  }

  /* The desktop 155px lock is too tight here — cap by characters instead so
     each title still breaks after its first sentence, as in the comp. */
  .commit ul li h3 {
    width: auto;
    max-width: 95%;
  }

  .pillar__body {
    max-width: 34ch;
  }

  /* Footer is the closing card of the rail — the rail already carries the
     side gutter and the bottom spacing, so it needs no padding of its own. */
  .commit__footer {
    text-align: left;
    margin: 0;
    padding: 0;
  }

  .commit__footer-title {
    font-family: var(--font-display);
    font-size: clamp(1.35rem, 6vw, 1.75rem);
    line-height: 1.05;
    max-width: 100%;
  }

  .commit__footer-body {
    margin-inline: 0;
    max-width: 34ch;
    font-size: 14px;
  }
 
  /* ---- Quality → stacked mobile panel (mobile comp):
     gold title → two-line sub → photo-filled 50,000+ across the width →
     lead → body + gold pill → centred AI band. ---- */
  .quality {
    padding: clamp(3rem, 10vw, 4rem) 0;
  }

  .quality__inner {
    padding: 0 var(--gutter); text-align: center;
  }

  .quality__head {
    display: grid;
    grid-gap: var(--sp-2);
    gap: var(--sp-2);
  }
  .quality__counter{margin: 0 auto;}

  /* h2.display carries a 90px !important from the wide-screen tweaks above. */
  .quality .quality__title {
    font-size: 50px !important;
    text-transform: uppercase;
    font-weight: 700;
    line-height: 1.05;
  }

  .quality__sub {
    font-size: clamp(1.05rem, 4.6vw, 1.35rem);
  }

  /* The desktop numeral is a fixed 440px/384px with -30px tracking — both
     rescale to the phone width; the photo pan keeps running behind it. */
  .quality__counter {
    font-size: clamp(4.2rem, 21vw, 7rem);
    letter-spacing: -1px;
  }

  .quality__counter-comma {
    font-size: 0.55em;
  }

  /* Copy stacks: lead, then body + CTA (it's a flex row on desktop). */
  .quality__copy {
    flex-direction: column;
    align-items: flex-start;
    justify-content: flex-start;
    gap: var(--sp-5);
    margin: 0;
  }

  .quality__lead {
    font-size: clamp(1.5rem, 6.4vw, 2rem);
    max-width: 100%;
  }

  .quality__aside {
    max-width: 100%;
  }

  .quality .exbloretwoBtn {
    margin: 0 auto;
}
.nri::before {
  background: url(/media/nri-img-m.jpg) 0 0 / cover no-repeat #515151;
        background-size: 100%;
        top: 0;
}
.nri::after{
 content: '';
        position: absolute;
        left: 0;
        width: 100%;
        background: none;
        height: 20%;
        bottom: 0;
        z-index: 1;
}
  /* AI band: the three-column head becomes one centred stack around the chip;
     the desktop copy nudges (right/-100px, left/-50px) reset. */
  .quality__ai {
    padding-block: clamp(2.5rem, 10vw, 4rem);
  }

  .quality__ai-head {
    --chip-w: clamp(88px, 24vw, 130px);
    grid-template-columns: 1fr;
    gap: clamp(0.75rem, 3vw, 1.25rem);
    font-size: 40px;
  }
  .quality__aiBoard { width: 75%;}

  .quality__ai-head span,
  .quality__ai-head span:last-child {
    text-align: center;
    left: 0;
    right: 0;
  }

  .quality__ai-body {
    font-size: clamp(1rem, 4.4vw, 1.25rem);
    max-width: 34ch;
  }
 
  .stories__head {
    position: static;
    opacity: 1;
    transform: none;
  }

  .stories__grid {
    grid-template-columns: 1fr;
    row-gap: clamp(1.25rem, 4vw, 2rem);
    margin-top: clamp(2rem, 6vw, 3rem);
  }

  .story,
  .storyVideo {
    grid-column: 1 !important;
    grid-row: auto !important;
    translate: none;
    margin-top: 0 !important;
  }
 
  /*
    The title keeps its 100px on desktop, which is the site-wide display size.
    That number comes from `h2.display { font-size: 100px !important }` at the
    top of this file — a flat px value with no responsive floor, so at phone
    widths "PASSPORT" alone is wider than the content box and the heading spills
    out of the section. Matching !important is the only way to reach past it;
    scoped to this heading so the rest of the site is untouched.
  */
  .passport__title {
    font-size: clamp(2.25rem, 9vw, 4.5rem) !important;
  }

  /* ---- mobile comp: left-aligned head → four ruled feature blocks →
     the device render closing the section over the navy base strip. ---- */
  .passport {
    padding-top: clamp(2.5rem, 10vw, 4rem);
  }

  /* The desktop head is pushed 210px down / 83px in to sit with the rig —
     back into flow here; .shell already carries the gutter. */
  .passport .maskUp {
    top: 0;
  }

  .passport .maskUp h2.display {
    padding: 0;
  }

  /* "Radiance Passport" reads as one line, tagline drops underneath. */
  .passport__title--navy {
    margin-right: 0;
  }

  .passport__title small {
    flex-basis: 100%;
    top: 0;
    margin-top: 0.4em;
    display: flex;
   gap: 2px;
  }

  .passport__watermark {
    display: none;
  }

  .story__by strong {
        font-size: 21px;
    }
  /* ---- Mobile: four feature cards as one horizontal rail, the render on
     the row beneath. The rail bleeds to both screen edges so a partly
     visible card signals there is more to swipe. Desktop is untouched. ---- */
  .passport__grid {
    grid-template-columns: minmax(0, 1fr);
    gap: clamp(1.5rem, 6vw, 2.25rem);
    --pg-gap: clamp(0.875rem, 4vw, 1.5rem);
  }

  .passport__rail {
    display: flex;
    flex-wrap: nowrap;
    align-items: flex-start;
    gap: var(--pg-gap);
    order: 0;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x proximity;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    margin-inline: calc(var(--gutter) * -1);
    padding-inline: var(--gutter);
    scroll-padding-inline: var(--gutter);
  }

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

  /* The lists stay real lists — they just lay their cards along the rail.
     (display:contents would flatten them but drops list semantics.) */
  .passport__col {
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    gap: var(--pg-gap);
    flex: 0 0 auto;
    margin: 0;
    padding: 0;
    top: 0;
  }

  .passport__col--left { order: 0; }
  .passport__col--right { order: 1; }

  .pfeature {
    flex: 0 0 auto;
    width: min(72vw, 300px);
    scroll-snap-align: start;
  }

  /* Next row, on its own, centred. */
  .passport__device {
    order: 1;
    margin: 0;
  }

  /* Single column, so the diagonal nudge and the mirrored alignment both go —
     everything hangs off one rule on the left. */
  .passport__col--left .pfeature:nth-child(2),
  .passport__col--right .pfeature:nth-child(2) {
    --dx: 0px;
  }

  .pfeature--left {
    text-align: left;
    padding-right: 0;
    padding-left: var(--sp-4);
    --fx: -28px;
  }

  .pfeature--left::before {
    right: auto;
    left: 0;
  }

  .pfeature--left p { margin-left: 0; }

  .pfeature p {
    max-width: 34ch;
  }

  /* The render is a fixed 700px on desktop — cap it to the phone. */
  .passport__float {
    width: min(92vw, 420px);
  }

  /* Orbits sit behind the device, which now lives at the foot. */
  .passport__orbits {   top: 81%;    width: 120%;   max-width: 120%; } 
 
  .passport--pd .maskUp h2.display {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto;
    justify-items: center;
  }

  .passport--pd .passport__title--navy,
  .passport--pd .passport__title--gold,
  .passport--pd .passport__title small {
    grid-area: auto;
    justify-self: center;
  }

  .passport--pd .passport__title small {
    text-align: center;
  }

  .passport--pd .passport__grid,
  .passport--pd .passport__device {
    margin-top: 0;
  }
  .faq__inner { grid-template-columns: 1fr; }
  .faq__mark { display: none; }
  /* ---- NRI → mobile comp: two-line gold/white head up top, the flight
     photo left visible beneath it, the staggered cards riding over the
     photo's lower half, one gold CTA pill centred at the foot. ---- */
  .nri__title,
  .nri__sub {
    font-size: clamp(1.5rem, 6.8vw, 2rem);
    line-height: 1.18;
  }

  /* Clear space over the background photo so the cabin scene reads before
     the cards arrive over its lower half. */
  .nri__list {
            max-width: 100%;
        margin-top: clamp(40rem, 58vw, 19rem);
        padding: 0 9%;
  }

  .nri {  background: #484a4a;}

  .nriItem {
    max-width: 84%;
        padding: 22px 20px;
     font-size: 19px;
     gap: var(--sp-3);
   }

  /* One gold pill, centred — both action halves ride it in a row even below
     the 560px stack breakpoint in globals. */
  .nri__actions {
    display: flex;
    justify-content: center;
    margin-top: clamp(2rem, 8vw, 3rem);
  }

  .nri .exbloretwoBtn {
    flex-direction: row;
    align-items: stretch;
    border-radius: 999px;
    background: linear-gradient(90deg, #f6a832 0%, #e8890f 100%);
  }

  .nri .exbloretwoBtn > .btn {
    color: #fff;
    font-size: 11px;
    padding: 0.95em 1.2em;
    justify-content: center;
  }

  .nri .exbloretwoBtn > .btn + .btn::before {
    left: 0;
    right: auto;
    top: 28%;
    bottom: 28%;
    width: 1px;
    height: auto;
    background: rgba(255, 255, 255, 0.55);
  }

  /* ---- Footer → mobile comp: city accordions with + toggles, stacked
     enquiries, left-aligned links, ghost brand closing the section. ---- */
  .footer__cities {
    grid-template-columns: 1fr;
    gap: 0;
  }

  .footerCity {
    border-bottom: 1px solid rgba(255, 255, 255, 0.14);
    opacity: 1;
    transform: initial;
  }

  .footerCity__name {
    margin-bottom: 0;
    font-size: clamp(1.5rem, 6.4vw, 1.9rem);
    color: rgba(255, 255, 255, 0.9);
  }

  /* The heading becomes a live accordion toggle at this width. */
  .footerCity__toggle {
    pointer-events: auto;
    cursor: pointer;
    padding-block: clamp(0.9rem, 4vw, 1.25rem);
  }

  /* The + : two bars, the vertical one folds away when open. */
  .footerCity__icon {
    display: block;
    position: relative;
    flex: none;
    width: 16px;
    height: 16px;
  }

  .footerCity__icon::before,
  .footerCity__icon::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 50%;
    translate: -50% -50%;
    background: rgba(255, 255, 255, 0.75);
    transition: rotate 0.35s var(--ease), opacity 0.35s var(--ease);
  }

  .footerCity__icon::before {
    width: 16px;
    height: 2px;
  }

  .footerCity__icon::after {
    width: 2px;
    height: 16px;
  }

  .footerCity.is-open .footerCity__icon::after {
    rotate: 90deg;
    opacity: 0;
  }

  /* Collapse via the grid-rows trick, so height animates without JS
     measurement. */
  .footerCity__panel {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows 0.45s var(--ease);
  }

  .footerCity__panelInner {
    overflow: hidden;
  }

  .footerCity.is-open .footerCity__panel {
    grid-template-rows: 1fr;
  }

  .footerCity__panelInner .footerCity__group:last-child {
    padding-bottom: clamp(1rem, 4vw, 1.5rem);
  }

  /* Enquiries: legend on the rule, contacts stacked below. */
  .footer__enquiries {
    margin-top: clamp(1.75rem, 7vw, 2.5rem);
  }

  .footer__legend {
    left: 0;
    padding-left: 0;
    font-size: clamp(1.35rem, 5.8vw, 1.65rem);
  }

  .footer__contactRow {
    flex-direction: column;
    align-items: stretch;
    gap: clamp(1.25rem, 5vw, 1.75rem);
  }

  .footer__social {
    margin-left: 0;
  }

  /* Base: links + copyright first, the ghost brand closes the footer. */
  .footer__base {
    grid-template-columns: 1fr;
  }

  .footer__brand {
    order: 2;
    overflow: hidden;
  }

  .footer__brand img,
  .footer__brand svg {
    width: 100%;
    height: auto;
  }

  .footer__links {
    row-gap: 0.5em;
  }

  .footer__links a:first-child {
    padding-left: 0;
  }

  .footer__copyRow {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--sp-2);
  }

  .footer__copy {
    padding-left: 0;
  }

  .footer__designBy {
    margin-top: 0;
  }
  .memories__media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center 35%;
}
  .memories { min-height: 800px;  padding: 60px 0 0; }
  .memories::before{content: '';   position: absolute;
        left: 0;    width: 100%; background: linear-gradient(to bottom, #6d4500, transparent);  height: 40%; top: 0;}
        .memories__inner {  padding-block: 0; }
        .project--light .ribbon__lede, .project--light .ribbon__card > div[data-reveal], .project--light .ribbon__locus,
         .project--light .ribbon__card .ribbon__walkthrough {
        background: #ffffff;    width: 100%;
    }

    .legacy {
    background-image: url(/media/legacy-img-m.jpg); background-size: cover;}
 
       .project--light .ribbon__card .ribbon__walkthrough{ display: flex;
    justify-content: flex-end;}
    .footer__enquiries {  text-align: center;   }
    .footer__social ul {   justify-content: center; }
        .footer__links {  row-gap: 0;   text-align: center;  display: flex;   justify-content: center;  }
            .footer__copyRow {    flex-direction: column;    align-items: center;   gap: 0;        text-align: center;  }
            .footer__contact a { font-size: 22px;}
                .footer__brand img, .footer__brand svg {    width: 68%;   margin: 0 auto;  }
                .footer__contact a { color: #7795bb;}
                .footer__links a { color: #7795bb;}
                    .stories__sub {  font-size: 25px;  }
                    .stars svg {   width: 30px;  height : 30px; }
                    .story.story--3::before {  width: 100%; }
                    .story {  padding: 80px 30px 50px;}
                    .stories__cta {  margin-top: 0; display: none;}
                    .care {  text-align: center; }
                    .care__title span { display: inline;  padding: 0 3px; }
                    .care__inner {  justify-content: center;  gap: 0; }
                   .care   .exbloretwoBtn {  margin: 0 auto; }
                       .homeBanner .image-container .bottom .years h3 {  font-size: 75px;}
                           .homeBanner .image-container .bottom .years p {   font-size: 10px; }
                               .homeBanner .image-container {    padding-top: 90px; }
                               .ribbon__lede {  font-size: 30px;}
                                 .ribbon__lede span{  display: inline; padding-right: 5px;} 
                                 .zero__ring::before {  border: solid 3px #fff;}
                                 .zero__sub {  max-width: 60%; margin: 0 auto; }
}







@media (max-width: 640px) {
  .legacyStat__num {  font-size: 64px; }
  .zero__heading {   font-size: 35px;}
      .story__quote {   font-size: 16px;  }
      h2.display {     font-size: 40px !important;  }
  .image-container .bannerText .left h2 {  font-size: 45px;  line-height: 1.2;}
  .sideCta {
    right: 10px;
    top: auto;
    /* clear the fixed mobile dock */
    bottom: calc(20% + env(safe-area-inset-bottom, 0px));
    translate: 0;
    gap: 8px;
    padding: 7px;
  }

  .sideCta__btn {
    width: 42px;
    height: 42px;
  }
 
  /* No stagger on small screens, so every card shares one walk-back. */
  /* No stagger on small screens, and a shorter drop from the rule. */
  .delivery--lift { --lift: 0px; margin-top: 50px; }
  .zero__rail { --tick: 56px; }
  .zero__arrow { display: none; }
  .delivery__thumb{border-radius: 0;}
 
  .quality__ai-head {
    --chip-w: clamp(88px, 22vw, 120px);

    grid-template-columns: 1fr;
  }
 
  /* .nri mobile rules live in the 900px block — the cards keep their
     desktop stagger there, per the mobile comp. */
 .care__title { text-align: left; }
  .care__inner { justify-content: flex-start; }
  .memories__arc { display: none; }
.exbloretwoBtn {flex-direction: inherit;}
.btn {  padding: 8px 12px;}
.exbloretwoBtn a {  font-size: 11px; }
 
[data-reveal].is-visible {
    opacity: 1;
    transform: none;
}
.maskUp[data-reveal] {
    opacity: 1;
    transform: none;
    transition: none;
}
  h2.display {  font-size: 40px !important;  }
  .passport--pd .passport__title--navy, .passport--pd .passport__title--gold, .passport--pd .passport__title small {
          justify-self: flex-start;
    }
         .passport--pd .passport__orbits {  top: 91%;}
        .exbloretwoBtn button {    font-size: 13px; }
         .exbloretwoBtn a {    font-size: 13px; }
    
}


/* =========================================================================
   Enquiry popup — "Let's Talk"
   -------------------------------------------------------------------------
   The form behind the floating enquire button (components/SideCta.jsx →
   components/EnquiryModal.jsx). White panel over the dimmed page, two
   columns of ruled fields — the same underline treatment the comp uses, not
   the boxed inputs of the contact page's form.
   ========================================================================= */

.eqModal {
  position: fixed;
  inset: 0;
  /* Above the video player, which is 1000. */
  z-index: 1100;
  display: grid;
  place-items: center;
  padding: clamp(0.75rem, 3vw, 2.5rem);
  overflow-y: auto;
  background: rgba(2, 16, 38, 0.74);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  animation: eqFade 0.28s var(--ease) both;
}

.eqModal__body {
  position: relative;
  width: min(940px, 100%);
  max-height: calc(100dvh - clamp(1.5rem, 6vw, 5rem));
  overflow-y: auto;
  padding: clamp(1.75rem, 4vw, 3.25rem) clamp(1.25rem, 4vw, 3.5rem)
    clamp(1.5rem, 3.5vw, 2.75rem);
  border-radius: 18px;
  background: #fff;
  box-shadow: 0 40px 90px rgba(2, 16, 38, 0.45);
  animation: eqRise 0.38s var(--ease) both;
}

@keyframes eqFade {
  from { opacity: 0; }
}

@keyframes eqRise {
  from { opacity: 0; transform: translateY(18px) scale(0.985); }
}

.eqModal__close {
  position: absolute;
  top: clamp(0.6rem, 1.4vw, 1rem);
  right: clamp(0.6rem, 1.4vw, 1rem);
  z-index: 2;
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: #eef2f6;
  font-size: 24px;
  line-height: 1;
  color: #0d1b2a;
  cursor: pointer;
  transition: background-color 0.3s var(--ease), transform 0.3s var(--ease);
}

.eqModal__close:hover {
  background: #dde5ec;
  transform: rotate(90deg);
}

.eqModal__title {
  margin: 0;
  /* Manrope, not the condensed display face — the comp sets this wide. */
  font-family: var(--font-body);
  font-size: clamp(1.85rem, 4vw, 2.9rem);
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: 0.01em;
  text-align: center;
  text-transform: uppercase;
  color: #111;
}

.eqModal__sub {
  max-width: 48ch;
  margin: 0.65rem auto 0;
  font-size: clamp(0.9rem, 1.05vw, 1.02rem);
  line-height: 1.55;
  text-align: center;
  color: var(--ink-700);
}

/* --- The grid -------------------------------------------------------------
   Fields are the site's own: a filled navy box with a hairline gold border,
   the label sitting above the input rather than floating out of it. Same
   language as .cField on the contact page — see contact.css — so the popup
   and the page form read as one system.
   ------------------------------------------------------------------------ */

.eqForm {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  grid-gap: clamp(0.75rem, 1.6vw, 1.1rem) clamp(0.75rem, 1.8vw, 1.4rem);
  gap: clamp(0.75rem, 1.6vw, 1.1rem) clamp(0.75rem, 1.8vw, 1.4rem);
  margin-top: clamp(1.5rem, 3vw, 2.25rem);
}

.eqForm.is-shake {
  animation: eqShake 0.42s cubic-bezier(0.36, 0.07, 0.19, 0.97);
}

@keyframes eqShake {
  10%, 90% { transform: translateX(-3px); }
  20%, 80% { transform: translateX(5px); }
  30%, 50%, 70% { transform: translateX(-8px); }
  40%, 60% { transform: translateX(8px); }
}

.eqField {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  /* Not a fixed height, unlike the page form: the popup's selects carry
     longer values and the error line has to fit under them. */
  min-height:58px;
  justify-content: center;
  padding: 0 13px;
  border: 1px solid var(--gold-500);
  border-radius: 8px;
  background: #051e3f;
  color: #fff;
  transition: border-color 0.35s var(--ease), box-shadow 0.35s var(--ease);
  margin: 0 0 8px;
}

.eqField--full {
  grid-column: 1 / -1;
}

.eqField:focus-within {
  border-color: var(--gold-400);
  box-shadow: 0 0 0 3px rgba(248, 166, 25, 0.22);
}

.eqField.is-error {
  border-color: #e5322d;
  box-shadow: 0 0 0 3px rgba(229, 50, 45, 0.18);
}

.eqField__label {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: #fff;
}

.eqField__label i {
  font-style: normal;
  color: #e5322d;
}

.eqField__input {
  width: 100%;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  font: inherit;
  font-size: clamp(0.8rem, 0.86vw, 0.95rem);
  line-height: 1.3;
  color: #fff;
}

.eqField__input:focus {
  outline: none;
}

.eqField__input::placeholder {
  color: #94a5bd;
  opacity: 1;
  transition: opacity 0.3s var(--ease);
}

.eqField:focus-within .eqField__input::placeholder {
  opacity: 0.5;
}

/* Native chevron off, a white one drawn in its place — the grey mark the
   browser supplies disappears against the navy. */
.eqField__select {
  -moz-appearance: none;
       appearance: none;
  -webkit-appearance: none;
  padding-right: 1.6rem;
  /* Muted until something is chosen, so an untouched select reads as a
     placeholder the way the text inputs beside it do. */
  color: #94a5bd;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0 center;
  background-size: 15px;
  cursor: pointer;
}

.eqField.is-chosen .eqField__select {
  color: #fff;
}

/* The dropdown itself is drawn by the OS, which does not inherit the navy —
   left light, or the options are white on white on some platforms. */
.eqField__select option {
  background: #fff;
  color: #0d1b2a;
}

/* --- Mobile, with its dialling code --------------------------------------- */

/* --- Phone control (react-international-phone) -----------------------------
   The library ships its own chrome — a bordered, light-background pill. Both
   forms here sit on navy and draw their own underline on the field wrapper,
   so the widget is stripped back to transparent and the surrounding .eqField
   / .cField keeps being the thing that looks like an input.

   Themed through the library's CSS variables rather than overridden with
   !important; open node_modules/react-international-phone/dist/style.css for
   the full list on the installed version.

   Flags come from cdnjs (twemoji SVGs), lazily, one per flag actually shown.
   To cut the third-party request entirely, pass a `flags` array of local srcs
   in PhoneField.jsx. */

.rip {
  --react-international-phone-height: auto;
  --react-international-phone-font-size: clamp(0.8rem, 0.86vw, 0.95rem);
  --react-international-phone-border-radius: 6px;
  --react-international-phone-border-color: transparent;
  --react-international-phone-background-color: transparent;
  --react-international-phone-text-color: #fff;
  --react-international-phone-country-selector-background-color: rgba(255, 255, 255, 0.12);
  --react-international-phone-country-selector-background-color-hover: rgba(255, 255, 255, 0.2);
  --react-international-phone-country-selector-arrow-color: #fff;
  --react-international-phone-selected-dropdown-item-color: var(--navy-900);
  --react-international-phone-dropdown-item-font-size: 0.9rem;
  --react-international-phone-dropdown-item-height: 32px;

  width: 100%;
  gap: 0.55rem;
  background: transparent;
}

/* The number itself — inherits the field's type, not the library's. */
.rip .rip__input,
.rip input.react-international-phone-input {
  width: 100%;
  padding: 0;
  border: 0;
  background: transparent;
  font: inherit;
  font-size: clamp(0.8rem, 0.86vw, 0.95rem);
  line-height: 1.4;
  color: #fff;
}

.rip .rip__input::placeholder {
  color: rgba(255, 255, 255, 0.45);
}

/* The flag + code chip, sized like the one it replaced. */
.rip .rip__countryBtn,
.rip .react-international-phone-country-selector-button {
  height: auto;
  padding: 0.3rem 0.45rem;
  border: 0;
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.12);
  transition: background-color 0.25s var(--ease, ease);
}

.rip .react-international-phone-country-selector-button:hover,
.rip .react-international-phone-country-selector-button:focus-visible {
  background: rgba(255, 255, 255, 0.2);
}

/*
  The dropdown is a light panel on a dark form — the alternative is white text
  on white, since the library's default item colour follows the text colour
  set above. It is also portalled nowhere: it renders inside the field, so it
  needs to sit above the rest of the form.
*/
.rip .rip__dropdown,
.rip .react-international-phone-country-selector-dropdown {
  z-index: 20;
  max-height: 260px;
  padding: 0.35rem 0;
  border: 1px solid rgba(12, 58, 108, 0.16);
  border-radius: 10px;
  background: #fff;
  box-shadow: var(--shadow);
  color: var(--ink-900);
  text-align: left;
}

.rip .react-international-phone-country-selector-dropdown__list-item {
  padding: 0.3rem 0.7rem;
  gap: 0.5rem;
}

.rip .react-international-phone-country-selector-dropdown__list-item-country-name,
.rip .react-international-phone-country-selector-dropdown__list-item-dial-code {
  color: var(--ink-900);
}

.rip .react-international-phone-country-selector-dropdown__list-item-dial-code {
  color: var(--ink-500);
}

/* Matches the red ring the field wrapper puts up. */
.rip--error .react-international-phone-country-selector-button {
  background: rgba(220, 38, 38, 0.22);
}

/* --- reCAPTCHA ------------------------------------------------------------
   Google's widget draws its own white card, so this cell drops the navy box
   rather than framing one card inside another. Empty when no site key is
   configured, and the row then closes up on its own. */
.eqField--captchaCell {
  min-height: 0;
  padding: 0;
  border: 0;
  background: none;
  justify-content: center;
}

.eqField--captchaCell:focus-within {
  box-shadow: none;
}

.eqCaptcha {
  transform-origin: left center;
}

/* --- Date and message ----------------------------------------------------
   The site-visit form's two extra controls. A native date input paints its
   own text and calendar button from the OS palette, which is dark-on-dark
   here — `color-scheme: dark` is what tells the browser to draw them light,
   rather than trying to restyle the shadow parts one by one. */
.eqField__date {
  color-scheme: dark;
  cursor: pointer;
}

/* Empty, the input shows its own dd/mm/yyyy hint; it is toned back to match
   the placeholders beside it. */
.eqField:not(.is-chosen) .eqField__date {
  color: #94a5bd;
}

.eqField__date::-webkit-calendar-picker-indicator {
  opacity: 0.75;
  cursor: pointer;
  -webkit-transition: opacity 0.3s var(--ease);
  transition: opacity 0.3s var(--ease);
}

.eqField__date:hover::-webkit-calendar-picker-indicator {
  opacity: 1;
}

.eqField__area {
  min-height: 3em;
  resize: vertical;
}

/* The message runs the width of the grid — a three-line box in a half column
   is narrower than the sentence anyone would write in it. */
.eqField--message {
  min-height: 0;
}

/* --- Consent -------------------------------------------------------------- */

.eqAgree {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.35rem;
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: #1a1a1a;
  cursor: pointer;
}

.eqAgree input {
  width: 15px;
  height: 15px;
  accent-color: var(--navy-500);
  cursor: pointer;
}

.eqAgree.is-error {
  color: #c0392b;
}

.eqConsent {
  grid-column: 1 / -1;
  margin: 0;
  font-size: clamp(0.88rem, 1vw, 0.98rem);
  line-height: 1.55;
  color: #2b3b4d;
}

.eqConsent strong {
  font-weight: 700;
  color: #0d1b2a;
}

/* --- Errors --------------------------------------------------------------- */

.eqField__err {
  position: absolute;
  left: 2px;
  top: 100%;
  margin-top: 3px;
  font-size: 0.68rem;
  line-height: 1.2;
  /* Light red — the contact form's colour, legible on the navy fill. */
  color: red;
}

/* The captcha cell has no navy behind it, so its message takes the dark red. */
.eqField--captchaCell .eqField__err {
  color: red;
}

/* --- Submit --------------------------------------------------------------- */

/* --- Honeypot -------------------------------------------------------------
   Not display:none — a fair number of bots skip inputs that are hidden that
   way, and filling this one is the whole point. Pushed off-screen instead,
   out of the tab order, and hidden from screen readers. */
.eqTrap {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

/* --- Submission failure ---------------------------------------------------
   Shown when the endpoint rejected the whole submission rather than one
   field: the server is unreachable, SMTP refused, the captcha did not verify.
   Spans the grid so it sits directly above the button. */
.eqFail {
  grid-column: 1 / -1;
  margin: 0;
  padding: 0.7em 1em;
  border: 1px solid rgba(200, 30, 45, 0.35);
  border-radius: var(--radius-sm);
  background: rgba(200, 30, 45, 0.07);
  color: #a3121f;
  font-size: var(--fs-body-sm);
  line-height: 1.5;
}

.eqForm__actions {
  grid-column: 1 / -1;
  display: flex;
  justify-content: center;
  margin-top: clamp(0.4rem, 1.4vw, 0.9rem);
}

/* The site's gold pill, as on the contact page and the two-action buttons —
   sheen on hover, tracking opens, the whole thing lifts. */
.eqSubmit {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  overflow: hidden;
  padding: 1.05em 3.2em;
  border: 0;
  border-radius: var(--radius-pill);
   font-family: inherit;
  font-size: clamp(0.72rem, 0.72vw, 0.88rem);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color:#fff;
  cursor: pointer;
  box-shadow: 0 14px 30px rgba(246, 128, 14, 0.32);
  transition: transform 0.45s var(--ease), box-shadow 0.45s var(--ease),
    letter-spacing 0.45s var(--ease);
    background-image: linear-gradient(to right, #f6800e, #f9a51a, #f6800e);
}

.eqSubmit::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(
    100deg,
    transparent 35%,
    rgba(255, 255, 255, 0.22) 50%,
    transparent 65%
  );
  transform: translateX(-100%);
  transition: transform 0.7s var(--ease);
}

.eqSubmit:hover:not(:disabled) {
  letter-spacing: 0.16em;
  transform: translateY(-2px);
  box-shadow: 0 18px 38px rgba(246, 128, 14, 0.45);
}

.eqSubmit:hover:not(:disabled)::after {
  transform: translateX(100%);
}

.eqSubmit span,
.eqSubmit svg {
  position: relative;
  z-index: 1;
}

.eqSubmit svg {
  width: 18px;
  height: 18px;
  transition: transform 0.35s var(--ease);
}

.eqSubmit:hover svg {
  transform: translateX(4px);
}

.eqSubmit:disabled {
  cursor: progress;
}

/* --- Sent ----------------------------------------------------------------- */

.eqDone {
  display: grid;
  justify-items: center;
  grid-gap: 0.5rem;
  gap: 0.5rem;
  padding: clamp(1.75rem, 4vw, 3rem) 0 clamp(0.5rem, 2vw, 1rem);
  text-align: center;
}

.eqDone__mark {
  width: 58px;
  height: 58px;
  margin-bottom: 0.35rem;
  fill: none;
  stroke: var(--navy-500);
  stroke-width: 2.5;
  stroke-linecap: round;
}

.eqDone__ring {
  stroke-dasharray: 145;
  animation: eqDraw 0.6s var(--ease) both;
}

.eqDone__tick {
  stroke-dasharray: 40;
  animation: eqDraw 0.4s var(--ease) 0.45s both;
}

@keyframes eqDraw {
  from { stroke-dashoffset: 160; }
  to { stroke-dashoffset: 0; }
}

.eqDone__title {
  margin: 0;
  font-size: clamp(1.1rem, 1.8vw, 1.45rem);
  font-weight: 700;
  color: #0d1b2a;
}

.eqDone__body {
  max-width: 42ch;
  margin: 0;
  font-size: 0.98rem;
  line-height: 1.6;
  color: var(--ink-700);
}

.eqDone__again {
  margin-top: 0.6rem;
  padding: 0;
  border: 0;
  background: none;
  font-family: inherit;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--navy-500);
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}



/* --- Facts card: hidden until the ribbon starts sliding -------------------
   Whole facts panel (card, watermark, statement) stays invisible until
   useHorizontalScroll flags the section `is-hstarted` (track has moved),
   then fades in. Desktop only — below 900px the panels stack. */
@media (min-width: 901px) {
  .hscroll:not(.is-hstarted) .ribbon__cardOut--facts,
  .hscroll:not(.is-hstarted) .ribbon__facts,
  .hscroll:not(.is-hstarted) .ribbon__factsStatement {
    opacity: 0 !important;
    visibility: hidden !important;
    pointer-events: none;
  }
  .hscroll.is-hstarted .ribbon__cardOut--facts,
  .hscroll.is-hstarted .ribbon__facts,
  .hscroll.is-hstarted .ribbon__factsStatement {
    visibility: visible;
    transition: opacity 0.8s var(--ease), transform 1s var(--ease), visibility 0s;
  }

  /* Only .ribbon__facts: adds a small slide (translateY) on top of the
     existing show/hide behaviour, which is untouched above. */
  .hscroll:not(.is-hstarted) .ribbon__cardOut .ribbon__facts,
  .hscroll[data-ribbon-anim]:not(.is-hstarted) .ribbon__cardOut .ribbon__facts,
  .hscroll[data-ribbon-anim]:not(.is-hstarted) .ribbon__cardOut.is-in .ribbon__facts {
    transform: translateY(-20px) !important;
  }
  .hscroll.is-hstarted .ribbon__cardOut .ribbon__facts,
  .hscroll[data-ribbon-anim].is-hstarted .ribbon__cardOut .ribbon__facts,
  .hscroll[data-ribbon-anim].is-hstarted .ribbon__cardOut.is-in .ribbon__facts {
    transform: translateY(0) !important;
    transition: opacity 0.8s var(--ease), transform 1s var(--ease), visibility 0s !important;
  }

}

/* --- Narrow --------------------------------------------------------------- */

@media (max-width: 720px) {
  /* One column: two ruled fields side by side leave neither enough width for
     a placeholder like "Enter Your Mobile Number". */
  .eqForm {
    grid-template-columns: minmax(0, 1fr);
  }

  .eqModal__body {
    padding-top: clamp(2.25rem, 8vw, 3rem);
  }

  /* The widget has a fixed 304px width, which overflows a small phone. */
  .eqCaptcha {
    transform: scale(0.86);
    transform-origin: left center;
  }
 
 .ribbon__blurb {    padding-top: 50px;   }
      .ribbon {  padding: 10px 0 30px;  }
        .project--solitaire .ribbon__watermark, .project--imperia .ribbon__watermark { bottom: 33%;
         text-align: center;
        width: 100%;
    }
.sideCta__btn svg, .sideCta__icon {
     filter: brightness(1) invert(0);
}

    .memories::before {   background: transparent;  }
    .memories {   background: #6d4601;  }
    .memories__media img {
        width: 100%;
        height: 100%;
        object-fit: contain;
        object-position: center bottom;
    }
        .memories {   padding: 50px 0 0; }
  
}

@media (prefers-reduced-motion: reduce) {
  .eqModal,
  .eqModal__body,
  .eqForm.is-shake,
  .eqDone__ring,
  .eqDone__tick {
    animation: none;
  }
     

    
}

@media (max-width: 530px) {
   .stars svg {   width: 25px;   height: 25px;   }
.rating__source {  font-size: 16px;}
.googleG {  width: 55px;  height: 55px;}
.rating__link { font-size: 14px;}
  .footer__legend {
    left: 24%;
        padding-left: 15px; 
  }
  .logo {  height: 56px;}
  .homeBanner .image-container .bannerText .left {  margin-top: 50px;}
      .homeBanner .image-container .bottom .years p {  font-size: 12px;}
  .homeBanner.is-pinned .image-container .img {
    opacity: var(--wash);
    scale: calc(4.1 - 2.8 * var(--zoom));}
      .projects .projects__heading {
        max-width: 100%;
    }
    .project--solitaire .ribbon__statSmall, .project--imperia .ribbon__statSmall {  padding: 20px 0 30px 7px;}

    /* All three cities stay on one line at phone widths. overflow-x is kept
       only as a safety net for a longer city list; with three tabs the row
       fits, so nothing scrolls and nothing is clipped. */
    .projects__tabs {
        width: 100%;
        justify-content: space-between;
        flex-wrap: nowrap;
        gap: clamp(0.5rem, 3vw, 1rem);
        overflow-x: auto;
        overflow-y: hidden;
        white-space: nowrap;
        padding-block: var(--sp-3);
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
    }

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

    .projects__tabs > * {
        flex: 0 0 auto;
    }
    .menuCity .menuCity__media img {
         filter: none;
        transform: none;
        opacity: 0.5; 
    }
    .menuCity__name { color: #fff;}
    .menuCity__media img {  width: 46%;  height: 104%;  mix-blend-mode: darken; }
       .menuCity__watermark {   opacity: 0.5;}
       .menuCity .menuCity__media img {  opacity: 0.1; float: right;      object-position: center 46%;}
       .menuCity.is-active .menuCity__media img {   opacity: 0.1; float: right; }
       .siteMenu__nav a {  font-size: 18px;}
       .projects .ribbon__card .exbloretwoBtn button.btn{display: none;}
           .homeBanner .image-container .bannerText .right .exbloretwoBtn {   display: none;  }
          .projects .exbloretwoBtn  {  align-self: center;  max-width: 78%;   justify-content: center; }
        .memories__inner h2{margin: 0;}
        .delivery.delivery--lift::before { top: -108px; height: 102px;}
        .faq__list {  padding-bottom: 20px;}
        .faq__list:after { background-image: none; }
        .zero__heading {   gap: 5px; }
 .zero__ring {  margin-right: 5px; margin-left: -3px;}
     .legacy__media {
        margin-top: 19px;
    }
  }


@media (max-width: 450px) {
  .passport h2.display span{display: inline; padding-right: 0;}
  .nri__list {
        margin-top: clamp(27rem, 58vw, 19rem); 
    }
   .nriItem {
    max-width: 84%;
    padding: 14px 20px;
    gap: var(--sp-3);
    font-size: 15px;
  }
   .bImg__headline {   padding-right:40%;   font-size: 45px;}
 .exbloretwoBtn button {    font-size: 11px; }
   .exbloretwoBtn a {    font-size: 11px; }
   
  .legacy:after {
        height: 41%;
    }
    #timeline-title span {
        padding: 0 3px;
    }
    .milestone__year {
        font-size: 40px;
    }
    .timeline__wave {  width: 230%;  max-width: 230%;   margin-top: -60px;  }
        .timeline__nav {
         z-index: 99;
    }
    .pillar__body {
        max-width: 90%;
    }
    
        .commit h3 {
        font-size: 27px;
    }
        .commit ul li h3 {
        width: auto;
        max-width: 100%;
        font-size: 27px;  padding-right: 27px;
    }
        .story {
        padding: 40px 30px 50px;
    }
   
    .zero__track { gap: 12px;}
    .pfeature p {
        max-width: 90%;
        font-size: 14px;
    }
    .pfeature h3 {  font-size: 20px;}
      
        .nri__list {   max-width: 100%;}
        .maskUp[data-reveal] {    margin: 0; }
        .care__aside {
        font-size: 16px;  max-width: 90%; margin: 0 auto; 
    }
        .care .maskUp[data-reveal] {    margin: 0 auto; }
        .legacyStat__unit {   font-size: 40px;  }
        .legacyStat__label {  font-size: 10px;    }
            .legacy__headline {  font-size: 27px; line-height: 1;}
                .ribbon__lede {  font-size: 27px; line-height: 1;}
                  .commit .commit__title {  font-size: 37px !important;}
                  .legacy__arc, .legacy__arc[data-reveal] {  top: 25%;}
        .memories {   min-height: 595px;   padding:50px 0 0;}
               .bannerOpen__frame { width:100%; border-radius: 0;}
                      .bannerOpen__card { border-radius: 0; }
                          .legacy {  background-position: center -34px;}
                          .legacyStat{   opacity: 1; transform: none;}
                              .nri__title, .nri__sub {  font-size: 18px;}
                              h2.display span{display: inline-block; padding-right: 5px;}
                                  .story__by strong {  font-size: 18px;  }
                               .delivery {  flex: 0 0 clamp(200px, 28vw, 500px); }
                                   .legacy__arc, .legacy__arc[data-reveal] {   width: 78vw;}
                                   .legacyStat__unit {  top: 0;}
                                   .pr__note {  font-size: 8px;}
                                   .ribbon__watermark { bottom: 375px; font-size: 78px;  opacity: 0.04;   display: flex;    justify-content: center;  left: auto;  width: 100%; }
                                         .project--solitaire .ribbon__watermark, .project--imperia .ribbon__watermark { bottom: 375px;}
                                         .exbloretwoBtn > .btn{width: 300px; max-width: 100%;}
                                             .zero__heading {  font-size: 25px; }
                                                 .zero__sub {  max-width: 100%;}
                                                 .delivery__name{font-size: 18px;}
                                                 .delivery__place{font-size: 8px; line-height: 1;}
                                                 .delivery__label {font-size: 10px; line-height: 1;}
                                                 .delivery__months{font-size: 20px;}
                                                 .stories__head {  margin: 0 0 60px; }
                                                 .story::before {  width: 100%;}
                                                 .homeBanner {  background: #0a1d49;  }
                                                   .passport__title small {  flex-wrap: wrap;  }
  .passport__title small .passport__cta {
    flex: 0 0 100%;
    display: block;
    margin-top: 14px;
    justify-self: auto;
  }
                                                     
}


@media (max-width: 380px) {
      .legacy__media {   margin-top: 19px;  left: 12%;  }
  .zero__heading {  font-size: 27px; }
   .legacy__media {  top: -35px;}
  h2.display {   font-size: 35px !important;   }
  .companies__sub {  font-size: 18px;   margin: 0;  }
      .leaders__sub {  font-size: 22px;  margin: 0; }
    .story__quote {    font-size: 15px;  }
        .legacyStat__num {   font-size: 55px;  }
            .legacy {   background-position: center -58px;  }
  }

@media (max-width: 365px) {
  .legacy {
        background-position: center -15px;
    }
  }

/* ======================================================= quick contact ==
   ≤900px: the bottom .mobileDock is retired and the header burger returns.
   The SideCta "+" stack itself now runs at every width — see the
   collapsed "+" stack block up in the SideCta section.
   ========================================================================= */


.sideCta__actions {
  display: contents;
}





/* Testimonials header: faded look (matches the sample) from the moment it pins (sticky). */
.stories__head.is-stuck { opacity: 0.25 !important; transition: opacity 0.3s ease; }

/* Passport: CTA under the tagline */
.passport__title small .passport__cta { margin-top: 18px; justify-self: start; }
.passport__title small .passport__cta a { text-transform: uppercase; }

/* Passport CTA: on mobile the tagline is a flex row — force the button onto
   its own line beneath the tagline. */
 
