/* ============================================================================
   Valad — responsive layer
   ----------------------------------------------------------------------------
   Built on the same principles as the Hector site's responsive.css.

   The desktop composition is the approved source of truth and is left
   untouched: every rule in this file lives inside a max-width media query.

   Because the design is authored with inline `style` attributes, structural
   overrides need `!important` to win the cascade (an important author rule
   beats a normal inline declaration). Several sections are also driven by
   JavaScript that writes inline styles on scroll — those need `!important`
   too, which is why the header and the lifecycle panels are pinned rather
   than left to the script below the desktop tier.

   Breakpoints — these are valad.io's own, read out of the media queries Framer
   emits on the live site, so a visitor crossing between the two never meets a
   reflow at a width one site recomposes at and the other does not:

     desktop  >= 1200         untouched baseline, 80px gutter
     tablet   810 - 1199.98   40px gutter, desktop type scale retained
     mobile   <= 809.98       20px gutter, reduced type scale

   The tablet tier deliberately carries no type overrides. valad.io holds its
   full desktop scale down to 810 (its hero is still 64px at 834px wide) and
   only changes the gutter, so this file does the same.

   Type note (see CLAUDE.md): letter-spacing stays at 0 everywhere. Positive
   tracking is only ever used on small uppercase eyebrow/label text, so no rule
   here introduces negative tracking.
   ========================================================================== */


/* --------------------------------------------------------------------------
   0. Breakpoint tokens
   The gutter and header height are consumed by inline styles in the markup as
   var(--valad-gutter) / var(--valad-header-h); re-pointing them here moves
   every section's horizontal padding at once.

   The bar holds 94px through desktop and tablet and comes down to 92px on
   mobile, which is what valad.io measures at 390.
   -------------------------------------------------------------------------- */
@media (max-width: 1199.98px) {
  /* Gutter only. The vertical scale in valad-system.css deliberately does not
     move here: valad.io runs its desktop rhythm unchanged at 810 — 200/130,
     160/200, 180/90, 80/120 and 120/120 all measure identically at 1440 and at
     810 — and only narrows the sides. */
  :root { --valad-gutter: 40px; }
}
@media (max-width: 809.98px) {
  :root { --valad-gutter: 20px; --valad-header-h: 92px; }

  /* Mobile is where valad.io does compress the rhythm. Measured at 390 against
     the same sections at 1440: 200→100, 160→100, 220→120, 150→120, 120→40,
     while the already-small 80 and 180 steps hold. It is roughly 0.6x on the
     large steps, tapering to 1x on the small ones, which is what this is —
     the top of the scale collapses hardest so a phone is not scrolling through
     220px of empty paper between every section. */
  :root {
    --v-space-xs:   50px;
    --v-space-sm:   60px;
    --v-space-md:   80px;
    --v-space-lg:  100px;
    --v-space-xl:  100px;
    --v-space-2xl: 120px;
    --v-space-3xl: 120px;

    /* The wipe comes down with the rhythm it sits in. Six 9px bands is a 54px
       strip against 100px of top padding, holding the same proportion of the
       section's opening the 84px strip holds at 1440. */
    --wipe-band: 9px;
  }
}


/* --------------------------------------------------------------------------
   1. Global safety net
   -------------------------------------------------------------------------- */
@media (max-width: 1199.98px) {
  /* `clip`, never `hidden`: overflow-x:hidden turns the viewport into a scroll
     container, which silently kills every position:sticky on the page — the
     homepage sector scroller and both About scrollers depend on it. `clip`
     contains a stray pixel without creating that scroll container. */
  html, body { max-width: 100%; overflow-x: clip; }
  img, video, canvas, svg { max-width: 100%; }
  /* Media that is explicitly placed by the layout keeps its own dimensions. */
  img[style*="position: absolute"], img[style*="position:absolute"],
  video[style*="position: absolute"], video[style*="position:absolute"],
  canvas[style*="position: absolute"], canvas[style*="position:absolute"] { max-width: none; }
}

/* Mobile type scale ---------------------------------------------------------
   Read directly off valad.io's mobile view at 375px and mapped step-for-step
   onto the ladder the markup now uses. valad.io's own readings:

     desktop  64  40  36  32  28  26  24  20  18  16  15  14  13  12
     mobile   39  32  28  24  24  22  18  18  18  14  15  14  13  12

   Every step is a measured pair, not a derived one — valad.io's mobile view was
   read element by element and matched to its desktop counterpart:
     64→39  "Institutional Assets, Built End-to-End"  (39px / 42.9px)
     40→32  "Our Assets"
     32→24  "Join our consortium of partners…"
     28→24  "Partnering with industry-leading platforms…"
     26→22  "Institutional analytics for commercial real estate"
     24→18  "Global Asset Management"
     20→18  "Private Credit Origination"
     16→14  "Institutional-grade intelligence for real estate…"
   15, 14, 13 and 12 do not move at all.

   Keyed off the inline serialisation because the composition is authored with
   style attributes; both spellings are matched since the pages carry a mix of
   hand-written and editor-written styles. Line height moves with the size —
   valad.io runs display tight (1.1) and body loose (1.5-1.6) at every width. */
@media (max-width: 809.98px) {
  [style*="font-size:64px"], [style*="font-size: 64px"] { font-size: 39px !important; line-height: 1.1 !important; }
  [style*="font-size:40px"], [style*="font-size: 40px"] { font-size: 32px !important; }
  [style*="font-size:36px"], [style*="font-size: 36px"] { font-size: 28px !important; }
  [style*="font-size:32px"], [style*="font-size: 32px"] { font-size: 24px !important; }
  [style*="font-size:28px"], [style*="font-size: 28px"] { font-size: 24px !important; }
  [style*="font-size:26px"], [style*="font-size: 26px"] { font-size: 22px !important; }
  [style*="font-size:24px"], [style*="font-size: 24px"] { font-size: 18px !important; }
  [style*="font-size:20px"], [style*="font-size: 20px"] { font-size: 18px !important; }
  [style*="font-size:16px"], [style*="font-size: 16px"] { font-size: 14px !important; }
}

/* Uppercase labels — one size for the whole family.
   The tracked, uppercase eyebrows and micro-labels are authored at 12, 13 and
   14px with no system behind the split: the Offices eyebrow and the sector
   counters sit at 12, "Our values" at 13, and the rest of the section eyebrows
   (HOW WE OPERATE, NEWS & INSIGHT, OUR MISSION), the story dates, the team
   roles and the footer column headings at 14 — large enough on a phone to
   compete with the copy they are meant to label. The whole family collapses
   onto the 12px the Offices eyebrow already uses, which is the only size
   valad.io shows this text at on mobile. That also takes the stat captions
   under section 4 from 13 to 12, so the caps run at one size everywhere.
   `uppercase` only ever appears in a text-transform, so it is a safe hook; both
   spellings of the declaration are matched as above. Tracking is untouched —
   positive tracking on small uppercase labels is the one case CLAUDE.md allows,
   and it is what keeps them legible at 12px. */
@media (max-width: 809.98px) {
  [style*="uppercase"][style*="font-size:14px"],
  [style*="uppercase"][style*="font-size: 14px"],
  [style*="uppercase"][style*="font-size:13px"],
  [style*="uppercase"][style*="font-size: 13px"] { font-size: 12px !important; }
}

/* Hero lede — every page opens with a 64px headline over a short standfirst,
   and the homepage sets that standfirst at 18px desktop / 15px mobile. 18px has
   no entry in the map above (valad.io does not move it), so the interior pages
   would otherwise hold 18px on a phone while the homepage dropped to 15px.
   The hook is on the paragraph itself; the homepage's own lede is nested inside
   a wrapper and keeps its existing rule in section 3. Contact is the exception
   and opts out in section 7 — its headline is empty, so the lede is the only
   thing in that hero and is set as a headline rather than a standfirst. */
@media (max-width: 809.98px) {
  .r-page-lede { font-size: 15px !important; line-height: 1.6 !important; }
}


/* --------------------------------------------------------------------------
   2. Header + mobile navigation
   The toggle is a plain uncontrolled checkbox so it survives re-renders and
   works with no JavaScript at all.
   -------------------------------------------------------------------------- */
.r-navtoggle { position: absolute; opacity: 0; pointer-events: none; width: 0; height: 0; margin: 0; }
.r-navbtn { display: none; }

/* Tablet keeps valad.io's real tablet header: the horizontal nav stays, only
   the gutter tightens (handled by --valad-gutter in section 0). The nav gap
   comes in from 50/32 so four items still clear the CTA at 810. */
@media (max-width: 1199.98px) and (min-width: 810px) {
  .r-header .r-nav { padding-left: 32px !important; gap: 22px !important; }
}

/* Mobile: valad.io drops its nav entirely at 809 because its three items are
   in-page anchors. Ours are four separate pages, so the links have to survive
   — they move into the full-screen overlay rather than disappearing. */
@media (max-width: 809.98px) {
  .r-header {
    display: flex !important;
    align-items: center !important;
    justify-content: space-between !important;
    gap: 10px !important;
    height: var(--valad-header-h) !important;
    padding: 24px var(--valad-gutter) !important;
    box-sizing: border-box !important;
    z-index: 60 !important;
  }
  /* The bar is transparent over the hero here exactly as it is on desktop, so
     the background is left to the scroll state and only the blur is pinned off.
     That is not a performance call: `backdrop-filter` makes the header a
     containing block for fixed-position descendants, so the full-screen nav
     overlay nested inside it resolves `inset: 0` against the bar instead of the
     viewport. The scrolled plate is nearly opaque and reads fine without it. */
  /* Two foregrounds, not one. `--r-nav-fg` is the overlay's ink, which always
     sits on `--r-nav-bg`; `--r-bar-fg` is the ink on the bar itself, which sits
     on whatever the hero happens to be. They agree on every page except About,
     where the bar is over a dark photograph until it takes its plate. */
  .r-header--light {
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
    /* White, matching the scrolled bar on desktop — the overlay used to open on
       the paper tint, which read as grey against the bar it drops from. */
    --r-nav-bg: #FFFFFF;
    --r-nav-fg: #141414;
    --r-bar-fg: #141414;
    /* Sub-nav rows reuse the desktop mega panel's markup (icon, title,
       description), which is authored in fixed dark-on-white ink since it
       only ever ran inside its own white dropdown. Inside the overlay it can
       run on either --r-nav-bg, so the row furniture reads off these instead. */
    --r-nav-dim: rgba(20, 20, 20, .45);
    --r-nav-desc: rgba(20, 20, 20, .55);
    --r-nav-border: rgba(20, 20, 20, .16);
    --r-nav-rule: rgba(20, 20, 20, .13);
  }
  .r-header--dark {
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
    --r-nav-bg: #141414;
    --r-nav-fg: #FFFFFF;
    --r-bar-fg: #FFFFFF;
    --r-nav-dim: rgba(243, 242, 238, .45);
    --r-nav-desc: rgba(243, 242, 238, .55);
    --r-nav-border: rgba(243, 242, 238, .22);
    --r-nav-rule: rgba(243, 242, 238, .16);
  }
  .r-header--hero-dark:not(.r-header--solid) { --r-bar-fg: #FFFFFF; }

  /* The bar carries the gutter now, so the logo adds none of its own — and the
     wordmark stays 22px at every width, exactly as it does on valad.io. */
  .r-header .r-logo {
    order: 0;
    height: auto !important;
    padding: 0 !important;
    position: relative;
    z-index: 62;
  }
  .r-header--light .r-logo img { filter: none !important; }
  .r-header--dark  .r-logo img { filter: invert(1) brightness(1.7) !important; }
  /* Once the overlay is open the wordmark is on the panel, not on the hero, so
     About's inversion has to come back off. The logo is before the toggle in
     the markup and no sibling combinator reaches backwards, hence `:has()`. */
  .r-header--light:has(.r-navtoggle:checked) .r-logo img { filter: none !important; }
  html[data-nav-open] .r-header--light .r-logo img { filter: none !important; }

  .r-navbtn { order: 3; margin-right: 0; margin-left: auto; }

  /* Bare three-line mark — no pill, no plate. Sized to sit with the 22px
     wordmark rather than tower over it. */
  .r-navbtn {
    display: inline-flex !important;
    flex-direction: column;
    justify-content: center;
    gap: 3.5px;
    width: 22px;
    height: 22px;
    flex: none;
    padding: 0;
    margin-left: 10px;
    background: none;
    border-radius: 0;
    cursor: pointer;
    position: relative;
    z-index: 62;
    color: var(--r-bar-fg, #141414);
    -webkit-tap-highlight-color: transparent;
  }
  /* Open, the mark is an X drawn on the panel rather than on the hero. */
  :is(.r-navtoggle:checked ~ .r-navbtn, html[data-nav-open] .r-navbtn) { color: var(--r-nav-fg, #141414); }
  /* The visual mark stays 22px; this restores a 44px touch area around it. */
  .r-navbtn::after { content: ""; position: absolute; inset: -11px; }
  .r-navbtn span {
    display: block;
    height: 1.5px;
    width: 100%;
    background: currentColor;
    border-radius: 2px;
    transition: transform 260ms cubic-bezier(.4, 0, .2, 1), opacity 180ms ease;
  }

  /* Full-screen navigation overlay */
  .r-header .r-nav {
    position: fixed !important;
    inset: 0;
    z-index: 61;
    display: flex !important;
    flex-direction: column !important;
    align-items: stretch !important;
    /* Was centred, back when the four top-level links were all this ever
       held — a short list, always shorter than the screen. The sub-nav rows
       (icon, title, description, feature card) mean About and Portfolio now
       routinely overflow a phone's height on their own. Centring overflowing
       flex content pushes its start above the container's own scroll origin,
       which is a fixed height above y=0 that `overflow-y: auto` cannot
       scroll back up to — so with `center` the top of the list, "About"
       itself, becomes permanently unreachable the moment the list no longer
       fits. Anchored top instead, so scrolling from 0 always reaches
       everything, and padded down to clear the bar rather than relying on
       centring to do it. */
    justify-content: flex-start !important;
    gap: 0 !important;
    /* Bottom padding reserves the CTA's strip so the links do not run into it
       on a short screen; top padding clears the fixed bar the overlay sits
       under, now that content starts at the top instead of floating centred
       past it. */
    padding: calc(var(--valad-header-h) + 20px) var(--valad-gutter) clamp(110px, 18vh, 170px) !important;
    background: var(--r-nav-bg, #EDECE8);
    opacity: 0;
    visibility: hidden;
    transform: translateY(-8px);
    overscroll-behavior: contain;
    transition: opacity 260ms ease, transform 320ms cubic-bezier(.4, 0, .2, 1), visibility 320ms;
    /* The sub-nav rows below can run the list taller than the screen,
       especially at 390 with both "About" and "Portfolio" expanded — this is
       the one place that's allowed to scroll rather than clip or overlap the
       CTA strip the bottom padding reserves. */
    overflow-y: auto;
  }
  :is(.r-navtoggle:checked ~ .r-nav, html[data-nav-open] .r-nav) { opacity: 1; visibility: visible; transform: none; }

  /* A row, not a headline. The first pass set these at 32px/450 — the mobile
     display step, borrowed on the reasoning that valad.io has no overlay of
     its own to copy. It reads wrong against the rest of the site: 32px is
     the size a page's own H2 runs at, and 450 is heavier than any display
     type here (the site sets 300 everywhere and varies size, not weight), so
     four of them stacked came out chunkier and louder than anything they
     link to. 24px at 300 is the same editorial voice as the pages behind it,
     and each row is now a flex line with its affordance pushed to the far
     edge rather than a word with a mark stuck to it. */
  .r-header .r-nav > a {
    display: flex !important;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 13px 0 !important;
    font-weight: 300 !important;
    font-size: 24px !important;
    line-height: 1.25 !important;
    letter-spacing: 0 !important;
    color: var(--r-nav-fg, #141414) !important;
    border-bottom: none !important;
    opacity: 0;
    transform: translateY(10px);
    transition: opacity 260ms ease, transform 320ms cubic-bezier(.4, 0, .2, 1);
  }
  /* These push into a panel rather than dropping one open, so the chevron
     points the way the level moves — right, not down. Same 45deg box the
     desktop caret is drawn from (valad-system.css), turned the other way and
     sat on the row's far edge by the flex line above rather than tucked
     against the label with a negative margin. */
  .r-header .r-nav > a[href="about.html"]::after,
  .r-header .r-nav > a[href="portfolio.html"]::after {
    margin: 0 !important;
    width: 8px;
    height: 8px;
    opacity: .5;
    transform: rotate(-45deg) !important;
  }
  :is(.r-navtoggle:checked ~ .r-nav > a, html[data-nav-open] .r-nav > a) { opacity: 1; transform: none; }
  /* Stagger the items in behind the panel. `:nth-of-type` rather than
     `:nth-child` — the sub-nav blocks are now siblings interspersed between
     these anchors, and child-position counting would reassign each link's
     delay to whichever one now sits at that raw offset instead of its own. */
  :is(.r-navtoggle:checked ~ .r-nav > a:nth-of-type(1), html[data-nav-open] .r-nav > a:nth-of-type(1)) { transition-delay: 60ms; }
  :is(.r-navtoggle:checked ~ .r-nav > a:nth-of-type(2), html[data-nav-open] .r-nav > a:nth-of-type(2)) { transition-delay: 100ms; }
  :is(.r-navtoggle:checked ~ .r-nav > a:nth-of-type(3), html[data-nav-open] .r-nav > a:nth-of-type(3)) { transition-delay: 140ms; }
  :is(.r-navtoggle:checked ~ .r-nav > a:nth-of-type(4), html[data-nav-open] .r-nav > a:nth-of-type(4)) { transition-delay: 180ms; }
  :is(.r-navtoggle:checked ~ .r-nav > a:nth-of-type(5), html[data-nav-open] .r-nav > a:nth-of-type(5)) { transition-delay: 220ms; }

  /* Sub-nav — the desktop dropdown's own markup (`.r-mega-*`, built by the
     same megaHTML() call), reflowed from its two-column panel into one
     column that sits in the overlay's normal flow under "About" and
     "Portfolio". The row and feature-card styling (icon box, arrow-on-hover,
     description, image card) is inherited as-is from valad-system.css —
     only the layout and the ink colour are overridden here, via the
     --r-nav-* tokens set on .r-header--light/--dark above, so a row reads
     correctly whichever colour the overlay opens on. */
  @keyframes rNavSubIn {
    from { opacity: 0; transform: translateX(14px); }
    to   { opacity: 1; transform: none; }
  }
  /* Drill-down, not an accordion: the panel replaces the level above it
     rather than expanding inside it. Gated on the root's `data-nav-sub` as
     well as the block's own `.is-open` so that clearing the root attribute
     alone — which is what closing the whole overlay does — is enough to
     return to the top level, with no second place that has to be kept in
     step. `display` cannot transition, so the entrance is an animation; it
     slides in from the right, which is the direction the level moved. */
  .r-nav-sub { display: none !important; }
  html[data-nav-sub] .r-nav-sub.is-open {
    display: flex !important;
    flex-direction: column !important;
    padding: 0 0 8px !important;
    animation: rNavSubIn 280ms cubic-bezier(.22, .61, .36, 1) both;
  }
  /* Drilled in, the panel is the whole overlay: the top-level links, the
     current-page rule beside one of them, and the CTA all belong to the
     level that was left behind. The CTA especially — it is a page-level
     action, not part of either menu. */
  html[data-nav-sub] .r-header .r-nav > a { display: none !important; }
  html[data-nav-sub] .r-header .r-cta { display: none !important; }

  /* Back control — the only chrome the panel carries, standing in for the
     parent link's own label. */
  .r-nav-back {
    display: inline-flex !important;
    align-items: center;
    gap: 10px;
    align-self: flex-start;
    margin: 0 0 22px !important;
    padding: 6px 0 !important;
    background: none;
    border: 0;
    cursor: pointer;
    font-family: 'Saans', 'Saans Fallback', Helvetica, Arial, sans-serif;
    font-size: 15px;
    letter-spacing: 0;
    color: var(--r-nav-fg, #141414);
    -webkit-tap-highlight-color: transparent;
  }
  .r-nav-back svg { flex: 0 0 auto; }
  /* Restores a 44px touch target around a control drawn at its type size. */
  .r-nav-back { position: relative; }
  .r-nav-back::after { content: ""; position: absolute; inset: -12px -16px; }

  .r-nav-sub .r-mega-inner {
    display: flex !important;
    flex-direction: column !important;
    gap: 0 !important;
    padding: 0 !important;
  }
  .r-nav-sub .r-mega-group {
    display: flex !important;
    flex-direction: column !important;
    gap: 14px !important;
    padding: 16px 0 !important;
    border-bottom: 1px solid var(--r-nav-rule) !important;
  }
  .r-nav-sub .r-mega-group:first-child { padding-top: 0 !important; }
  .r-nav-sub .r-mega-label {
    font-size: 11px !important;
    color: var(--r-nav-dim) !important;
    padding-top: 0 !important;
  }
  .r-nav-sub .r-mega-items {
    display: flex !important;
    flex-direction: column !important;
    gap: 16px !important;
  }
  .r-nav-sub .r-mega-item { color: var(--r-nav-fg) !important; grid-template-columns: 28px minmax(0, 1fr) !important; gap: 0 12px !important; }
  .r-nav-sub .r-mega-icon { width: 28px !important; height: 28px !important; border-color: var(--r-nav-border) !important; }
  .r-nav-sub .r-mega-icon svg { width: 15px !important; height: 15px !important; }
  /* The icon glyph's stroke is authored #141414 inline in the SVG markup —
     fine on the desktop panel's fixed white background, invisible on a dark
     overlay without this. */
  .r-nav-sub .r-mega-icon svg path { stroke: var(--r-nav-fg) !important; }
  /* A step below the 17px first tried here. These rows are the panel's whole
     content once drilled in, so they do not have to hold their own against
     the 32px top-level links the way they would in a list beneath them —
     and at 17px with a description under each, seven rows and a feature card
     ran well past a phone screen before the card was even reachable. */
  .r-nav-sub .r-mega-head { font-size: 15px !important; line-height: 1.35 !important; color: var(--r-nav-fg) !important; }
  .r-nav-sub .r-mega-head svg { width: 13px !important; height: 13px !important; }
  .r-nav-sub .r-mega-head svg path { stroke: var(--r-nav-fg) !important; }
  .r-nav-sub .r-mega-desc { margin-top: 2px !important; max-width: none !important; font-size: 13px !important; line-height: 1.45 !important; color: var(--r-nav-desc) !important; }

  .r-nav-sub .r-mega-feature { padding: 20px 0 0 !important; }
  .r-nav-sub .r-mega-feature-label { font-size: 11px !important; color: var(--r-nav-dim) !important; }
  .r-nav-sub .r-mega-feature-card { margin-top: 16px !important; color: var(--r-nav-fg) !important; }
  .r-nav-sub .r-mega-feature-head { margin-top: 12px !important; font-size: 15px !important; line-height: 1.35 !important; color: var(--r-nav-fg) !important; }

  /* The bar's own row stays put while the overlay scrolls under it: the
     wordmark and the X are `position: fixed` at z-62 (above the overlay's
     61), so without a plate of their own the panel's rows scroll up and
     pass visibly *through* them — a row of type crossing the wordmark and
     coming out the other side. This is that plate: the bar's height, filled
     in the overlay's own colour, sitting between the two. `pointer-events:
     none` so it never takes the tap meant for the X behind it, and the two
     marks lift to 63 so they stay above it.

     Keyed off `:has(:checked)` as well as the root attribute, the same pair
     every other open-state rule in this block uses, so it still holds with
     the script blocked. */
  .r-header:has(.r-navtoggle:checked)::before,
  html[data-nav-open] .r-header::before {
    content: "";
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: var(--valad-header-h);
    background: var(--r-nav-bg, #FFFFFF);
    z-index: 62;
    pointer-events: none;
  }
  :is(.r-navtoggle:checked ~ .r-navbtn, html[data-nav-open] .r-navbtn),
  .r-header:has(.r-navtoggle:checked) .r-logo,
  html[data-nav-open] .r-header .r-logo { z-index: 63; }

  /* Current page: a rule in the accent, standing in for the desktop underline
     that the overlay drops. Marked with a class rather than keyed off the inline
     border — the runtime rewrites inline styles (#BAD2FF comes back out as
     `rgb(186, 210, 255)`) and drops `data-current`, but it preserves classes. */
  .r-header .r-nav > a.r-current { padding-left: 22px !important; position: relative; }
  .r-header .r-nav > a.r-current::before {
    content: "";
    position: absolute;
    left: 0;
    top: 50%;
    width: 12px;
    height: 1.5px;
    background: #BAD2FF;
  }

  /* Hamburger -> X (sits above the overlay so it also closes it) */
  :is(.r-navtoggle:checked ~ .r-navbtn span:nth-child(1), html[data-nav-open] .r-navbtn span:nth-child(1)) { transform: translateY(5px) rotate(45deg); }
  :is(.r-navtoggle:checked ~ .r-navbtn span:nth-child(2), html[data-nav-open] .r-navbtn span:nth-child(2)) { opacity: 0; }
  :is(.r-navtoggle:checked ~ .r-navbtn span:nth-child(3), html[data-nav-open] .r-navbtn span:nth-child(3)) { transform: translateY(-5px) rotate(-45deg); }

  /* The CTA belongs to the menu on mobile, not to the bar. Its label is long
     ("Digital Assets Division" against valad.io's "Get in contact") and sharing
     the bar with the wordmark and the burger meant shrinking it below its
     desktop size to fit 375px. Inside the overlay it can be full width at its
     proper size, and the bar is left as wordmark + burger.

     It is a sibling of the toggle and comes after `.r-nav` in the markup, so it
     can be revealed by the same `:checked` selector and paints over the panel
     without needing a z-index above the burger. Taken out of flow rather than
     reparented — `.r-cta` is the anchor itself on the inner pages and a wrapper
     div on the homepage and Careers, and moving either in the DOM would mean
     rebuilding the desktop header grid on six pages. */
  .r-header .r-cta {
    position: fixed !important;
    left: var(--valad-gutter);
    right: var(--valad-gutter);
    bottom: clamp(48px, 11vh, 96px);
    z-index: 61;
    display: flex !important;
    margin: 0 !important;
    padding: 0 !important;
    opacity: 0;
    visibility: hidden;
    transform: translateY(10px);
    transition: opacity 260ms ease, transform 320ms cubic-bezier(.4, 0, .2, 1), visibility 320ms;
  }
  /* Last in after the five links, which run 60ms to 220ms. */
  :is(.r-navtoggle:checked ~ .r-cta, html[data-nav-open] .r-cta) {
    opacity: 1;
    visibility: visible;
    transform: none;
    transition-delay: 260ms;
  }
  .r-header a.r-cta, .r-header .r-cta > a {
    flex: 1;
    display: flex !important;
    align-items: center !important;
    justify-content: center !important;
    height: 52px !important;
    padding: 0 22px !important;
    border-radius: 60px !important;
    font-size: 15px !important;
  }
}


/* --------------------------------------------------------------------------
   3. Generic layout collapse utilities
   -------------------------------------------------------------------------- */
@media (max-width: 1199.98px) {
  /* Two equal-ish editorial columns. */
  .r-2col       { grid-template-columns: minmax(0, 1fr) !important; gap: clamp(28px, 5vw, 48px) !important; }
  /* Label column + content column ("HOW WE OPERATE" + heading). */
  .r-2col-label { grid-template-columns: minmax(0, 1fr) !important; gap: 14px !important; }
  /* Term + definition rows. */
  .r-2col-def   { grid-template-columns: minmax(0, 1fr) !important; gap: 12px !important; }
  .r-3col       { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
  .r-4col       { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
  .r-unstick    { position: static !important; top: auto !important; }
  .r-stack      { flex-direction: column !important; }
}
@media (max-width: 809.98px) {
  .r-2col     { gap: 26px !important; }
  .r-3col     { grid-template-columns: minmax(0, 1fr) !important; }
  .r-hide-m   { display: none !important; }
}

/* Touch targets: any link/button that reads as a control gets a floor. */
@media (max-width: 1199.98px) {
  .r-tap { min-height: 44px; display: inline-flex !important; align-items: center; }
}

/* Footer — shared by all six pages -----------------------------------------
   valad.io keeps four footer columns all the way down to 810 and only pairs
   them at mobile. Its 9-track grid resolves to 222/140/140/140 on the 715px
   tablet inner width; the `1.55fr 1fr 1fr 1fr` this site uses resolves to
   219/141/141/141 on the same width, so the desktop grid is simply left to
   run through the tablet tier rather than being restated.

   At mobile valad.io moves to a four-track grid whose columns span two tracks
   each, landing the pair at 163px on a 350px inner width. Two equal tracks
   with the same 24px column gap resolve to the identical 163px, so the simpler
   track model is kept and only the gap is matched: 40px between rows, 24px
   between columns. */
@media (max-width: 809.98px) {
  /* The tagline row and its Contact Us pill have been removed from the footer
     on every page, so the rules that sized and stacked them have gone with
     them — as has the tagline-to-grid clearance at both tiers, since the
     columns now open the footer directly under its own 80px of padding. */
  /* Company and Explore sit side by side; "What we do" takes the full width
     under them. Three link groups cannot divide evenly across two tracks, so
     something has to give — and it is better that the odd one out is the group
     whose labels actually need the width. "Development Management" does not
     fit a 156px column at 15px and breaks over two lines, which reads as four
     entries rather than two; full width sets both on one line.

     Link spacing comes in from 32px to 20px. At four links a group that is
     the single biggest contributor to footer height, and 32px was tuned for a
     two-track desktop layout where the columns run side by side rather than
     stacking. */
  .r-foot-nav { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; gap: 34px 24px !important; }
  .r-foot-nav > div:first-child { grid-column: 1 / -1; }
  .r-foot-nav > div:last-child { grid-column: 1 / -1; }
  .r-foot-nav > div { gap: 20px !important; }
  .r-foot-addr { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; gap: 40px 24px !important; }
  /* valad.io drops its column inset from 24px to 16px here. */
  .r-foot-nav > div, .r-foot-addr > div { padding-top: 16px !important; }
  .r-foot-addr > div { font-size: 13px !important; }
}


/* ==========================================================================
   4. Homepage
   ========================================================================== */

/* Hero --------------------------------------------------------------------- */

/* The mobile-only pill CTA + stat row that lives in the hero markup. Off
   everywhere except the phone composition below. */
.r-hero-m { display: none; }

@media (max-width: 1199.98px) {
  /* The headline's inner span is authored `position:absolute; font-size:80px`,
     which takes it out of flow and hard-codes a size the phone can't hold. */
  [data-screen-label="Hero"] h1 span span {
    position: static !important;
    font-size: 64px !important;
  }
}

/* Phone composition: a vertically centred left-aligned text block — headline
   then standfirst — with a row of three stats split by hairline rules pinned to
   the bottom edge. The hero's photo and gradient are both absolutely
   positioned, so turning the section itself into a flex column only picks up
   the text layers, which are un-pinned back into flow in DOM order. */
@media (max-width: 809.98px) {
  [data-screen-label="Hero"] {
    /* The small-viewport unit so mobile browser chrome can't clip the hero. */
    height: 100svh !important;
    min-height: 560px !important;
    display: flex !important;
    flex-direction: column;
    justify-content: center;
    align-items: stretch;
    /* Top pad clears the fixed header and the bottom pad reserves the stat
       row's footprint, so `center` centres the text in what's actually left
       rather than in the raw section box. */
    padding: var(--valad-header-h) var(--valad-gutter) calc(118px + env(safe-area-inset-bottom, 0px)) !important;
  }
  /* The scroll cue is pinned to the corner the stat row now occupies. */
  [data-screen-label="Hero"] a[href="#about"] { display: none !important; }
  /* Empty spacer div the desktop layout parks at 66%. */
  [data-screen-label="Hero"] > div:not([style*="linear-gradient"]):empty { display: none !important; }
  /* The desktop scrim only has to carry a single line of standfirst; the phone
     stack runs four blocks deep over the brightest part of the photograph. */
  [data-screen-label="Hero"] > div[style*="linear-gradient"] {
    background: linear-gradient(180deg,
      rgba(14, 14, 13, .46) 0%,
      rgba(14, 14, 13, .16) 26%,
      rgba(14, 14, 13, .58) 62%,
      rgba(14, 14, 13, .90) 100%) !important;
  }

  [data-screen-label="Hero"] h1 {
    position: static !important;
    transform: none !important;
    padding: 0 !important;
    margin: 0 0 16px !important;
    text-align: left !important;
    /* valad.io holds one leading ratio at every width — 64/70.4 on desktop and
       39/42.9 on mobile are both 1.10. This was .98, which is tighter than the
       cap height, so the two hero lines closed up and nearly touched at 390. */
    line-height: 1.1 !important;
  }
  [data-screen-label="Hero"] h1 span span { font-size: 39px !important; }

  [data-screen-label="Hero"] .r-hero-lede {
    position: static !important;
    max-width: none !important;
    margin: 0 !important;
    padding-left: 0 !important;
    border-left: 0 !important;
  }
  /* The lede is 15px/24px at every width now, matching valad.io's hero, so
     mobile no longer has to step it down from a larger desktop size. */

  /* Out of flow so the centred text block above is unaffected by its height. */
  .r-hero-m {
    display: block;
    position: absolute;
    left: var(--valad-gutter);
    right: var(--valad-gutter);
    bottom: calc(26px + env(safe-area-inset-bottom, 0px));
    animation: fadeIn 900ms ease 1250ms both;
  }
  .r-hero-m-stats {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
  .r-hero-m-stats > div {
    padding: 2px 10px 0 0;
    min-width: 0;
  }
  .r-hero-m-stats > div + div {
    border-left: 1px solid rgba(247, 245, 240, .26);
    padding-left: 12px;
  }
  .r-hero-m-stats span {
    display: block;
    font-family: var(--valad-font);
    letter-spacing: 0;
    text-wrap: pretty;
  }
  /* Two lines' worth of room whether or not the value wraps ("UK & Europe"
     does at this column width), so the three labels share a baseline. */
  .r-hero-m-stats span:first-child {
    font-size: 18px;
    line-height: 1.1;
    min-height: 2.2em;
    color: #FFFFFF;
    margin-bottom: 6px;
  }
  .r-hero-m-stats span:last-child {
    font-size: 13px;
    line-height: 1.28;
    color: rgba(247, 245, 240, .62);
  }
}

/* Thesis ------------------------------------------------------------------- */
@media (max-width: 1199.98px) {
  /* The sticky standfirst has nothing to sit beside once the columns stack. */
  .r-thesis-copy { position: static !important; top: auto !important; }
  .r-thesis-copy p { max-width: none !important; }
  /* The cards keep the desktop composition: portrait proportion, number at the
     top, label at the foot, and the second column dropped against the first.
     Only the height comes down — five 320-520px cards is a minute of scrolling
     for five numbers — and the offset is left to the authored inline
     clamp(30px,7vh,72px) so the stagger survives at every width. */
  .r-stats > div > div { min-height: clamp(240px, 34vh, 310px) !important; padding: 24px !important; }
}
@media (max-width: 809.98px) {
  .r-stats { gap: 6px !important; }
  .r-stats > div { gap: 6px !important; }
  .r-stats > div > div { min-height: 244px !important; padding: 20px !important; }
  /* Two 162px-wide cards can't hold a 30px number and its label. */
  .r-stats > div > div > div:first-child { font-size: 26px !important; }
  .r-stats > div > div > div:last-child  { font-size: 13px !important; }
}

/* Sectors — the 760vh pinned scroller ------------------------------------- *
   The desktop stage is a five-part composition: an index rail on the left, the
   sector name centred at the top, a copy column and a facts column flanking a
   centred image mosaic. Below 1024 the flanking columns compute to about 100px
   wide (their width is `50% - half the mosaic - a gutter`), so the stage is
   re-stacked vertically instead: name, mosaic, copy, facts. The index rail is
   dropped — the name already says which sector is on screen.                 */
@media (max-width: 1199.98px) {
  .r-sec-index { display: none !important; }

  /* The name was anchored at 11vh, which on a 844px phone puts it 88px down —
     under the header as it then stood at 92px. Measured, it left 13px of air
     above the name and 47px below it, which is what made it read trapped. The
     bar has since come down to 70px, so the clearances below are floors rather
     than the tight fits they were tuned as. The ceiling here is the
     mosaic below it, and the mosaic is not free to move: layoutMark() pins it to
     the name's bottom edge + 56px, so pushing the name down pushes the mosaic
     into the bottom-anchored copy block. The budget is therefore whatever slack
     sits between the mosaic and the copy, and that slack scales with viewport
     height — a 700px phone has only ~18px of it, an 844px phone has ~58px.
     Hence a vh-led anchor with a low floor: tall viewports get real air above
     the name, short ones keep the spacing they already had. The mosaic also
     gives up height to widen the budget — see #markBox below.

     This is the tablet value; phones have a looser budget and override it in
     the 809 block. At 900x800 it clears the header by 30px, where the old 11vh
     anchor put the name 6px *behind* it. */
  .r-sec-names { top: clamp(104px, 15.5vh, 170px) !important; padding: 0 var(--valad-gutter); }

  /* The mosaic is sized off its own height; cap it against the viewport width
     too so it can never be wider than the phone.

     Down from 44vh/380px. The stage is a fixed vertical stack — name, mosaic,
     copy, facts — inside one viewport, and layoutMark() pins the mosaic to the
     name, so the air added above the name has to come out of the mosaic or the
     stack collides. At 900x800 that is 272px of mosaic against 37px of
     mosaic-to-copy clearance; at 900x700, 238px against 6px. */
  #markBox {
    --mk: min(34vh, 300px, 84vw);
    height: var(--mk) !important;
    width: calc(var(--mk) * 0.936) !important;
  }

  .r-sec-copy, .r-sec-facts {
    left: var(--valad-gutter) !important;
    right: var(--valad-gutter) !important;
    width: auto !important;
    top: auto !important;
    transform: none !important;
    height: 0 !important;
  }
  /* Steeper than the 19vh it replaces. The three gaps in the stack — mosaic to
     copy, copy to facts — do not shrink at the same rate as the viewport, so a
     shallow slope left 900x700 with 2px above the copy and 28px going spare
     below it. 33vh-112px holds 152px at 800 (unchanged) and pulls the copy down
     to 119px at 700, which splits that stack ~16/14 instead of ~2/28. */
  .r-sec-copy  { bottom: clamp(100px, 33vh - 112px, 200px) !important; }
  .r-sec-facts { bottom: clamp(34px, 7vh, 70px) !important; }

  .r-sec-copy > div {
    align-items: center !important;
    text-align: center !important;
    gap: 12px !important;
  }
  .r-sec-copy > div > a { align-self: center !important; }
  .r-sec-copy p { font-size: 16px !important; line-height: 1.6 !important; }

  /* Facts turn from a right-aligned stack into a single row of four. */
  .r-sec-facts > div {
    flex-direction: row !important;
    justify-content: space-between !important;
    align-items: flex-start !important;
    gap: clamp(8px, 2vw, 20px) !important;
    text-align: center !important;
  }
  .r-sec-facts > div > div { flex: 1 1 0; min-width: 0; align-items: center !important; }
  .r-sec-facts > div > div > div:first-child { font-size: 12px !important; }
  .r-sec-facts > div > div > div:last-child  { font-size: 18px !important; }

  #sectorFinale { bottom: clamp(34px, 7vh, 70px) !important; }
}
@media (max-width: 809.98px) {
  #markBox { --mk: min(28vh, 240px, 84vw); }

  /* Phones drop the facts row lower and carry a narrower mosaic than tablets,
     so there is more room to spend above the name — 47px of air on an 844px
     phone against the tablet's 30px. Floor kept at 114px for short handsets. */
  .r-sec-names { top: clamp(114px, 16.5vh, 180px) !important; }
  /* The inherited anchor left the copy hugging the facts row — 38px of air
     above it, 114px below. Re-anchored to centre it in the gap between the
     mosaic's bottom edge and the facts row. Both of those scale linearly with
     viewport height (the mosaic is 28vh, the facts sit at 7vh), so the midpoint
     between them is linear in vh too and this holds at any phone height.

     Re-tuned from -50px when the name moved down: the mosaic follows the name,
     which on a 700px phone closed the mosaic-to-copy gap to 5px while leaving
     63px unused below the copy. -75px spends that slack on the gap that was
     actually tight, giving ~30/38 on a 700px phone and ~75/75 on an 844px one. */
  .r-sec-copy { bottom: calc(32.5vh - 75px) !important; }
  .r-sec-copy p { font-size: 15px !important; }
  .r-sec-copy > div > div:first-child { font-size: 12px !important; }
  .r-sec-facts > div > div > div:last-child { font-size: 15px !important; }
  /* In the finale the mark lands at the top of the stage and the caption was
     left 291px below it, adrift with only 57px under it. Raised to sit ~15vh
     under the mark, which also brings the pair close to optically centred.
     Linear in vh for the same reason as the copy anchor above. */
  #sectorFinale { bottom: calc(52.6vh - 201px) !important; }
  #sectorFinale > div:last-child { font-size: 13px !important; padding: 0 24px; }
}

/* Sectors, short desktop windows ------------------------------------------- *
   The index rail and the copy column share the left gutter, but they are
   anchored to different things: the rail hangs off the top of the stage
   (21vh) while the copy is vertically centred. They pass through each other
   as the window gets shorter — at 1440x720 the rail runs 151-297 and the copy
   starts at 259, printing "Commercial" through "Sector 05". They only clear
   each other above ~950px of viewport height, which is taller than most
   laptops.

   Fix by anchoring the rail to its bottom edge instead, 24px above the copy.
   Every copy block is exactly 202px tall, so the copy's top edge is a fixed
   50vh - 101px and the rail's bottom edge is 50vh - 125px — i.e. an offset of
   50% + 125px, whatever the rail's own height turns out to be. The max() is
   what preserves the tall-window design: past ~930px the old 190px top is the
   lower of the two and wins back.                                            */
@media (min-width: 1200px) {
  .r-sec-index {
    top: auto !important;
    bottom: max(calc(50% + 125px), calc(100% - 336px)) !important;
  }
}
/* Below ~780px the rail's 146px stops clearing the header by a readable
   margin — measured at 750 against the 94px bar it had 10px, and the 70px bar
   only moves that floor down — so the type tightens to a 119px stack, which
   buys back ~27px. Below ~710px even that is through the header and the rail
   goes entirely: the sector name at the top of the stage already says which
   one is on screen, which is the same call the sub-1200px layout makes. */
@media (min-width: 1200px) and (max-height: 779.98px) {
  .r-sec-index { gap: 6px !important; }
  .r-sec-index > div { font-size: 16px !important; }
}
@media (min-width: 1200px) and (max-height: 709.98px) {
  .r-sec-index { display: none !important; }
}

/* In the finale the mark shrinks and lifts 5vh, but the caption pair stayed put
   at 8vh/96px off the floor, leaving only 43px under the mark against 72px of
   floor below it. Dropped so the mark can breathe: ~61px above, ~54px below at
   900. Desktop only — the sub-1200px layouts re-anchor this block themselves. */
@media (min-width: 1200px) {
  #sectorFinale { bottom: clamp(34px, 6vh, 72px) !important; }
}

/* Partners ----------------------------------------------------------------- */
@media (max-width: 1199.98px) {
  .r-logo-grid > div { min-height: clamp(110px, 15vw, 150px) !important; }
  /* Three columns all the way down, overriding the shared `.r-4col` two-up.
     Nine partners divide evenly by three and by nothing else useful: at two
     columns the ninth would sit alone on a fifth row. Holding three also keeps
     the grid the shape valad.io runs at every width.

     The per-cell borders that used to be redrawn here are gone — the rules are
     the grid's own background showing through its 1px gaps, which lands them
     correctly at any column count without being restated per breakpoint. */
  .r-logo-grid { grid-template-columns: repeat(3, minmax(0, 1fr)) !important; }
}
@media (max-width: 809.98px) {
  .r-logo-grid > div { min-height: 96px !important; padding: 18px 12px !important; }
  /* A third of the 350 column is ~115px, and 24px of that is padding, so the
     mark has to come in from the 104px it could take at two-up. */
  .r-logo-grid img   { height: 18px !important; max-width: 88px !important; }
}

/* How it works — the lifecycle panels -------------------------------------- *
   Six equal panels share one 415px-tall row and a script animates flex-grow to
   expand the active one. Below 1200 valad.io swaps that row for a single
   stacked variant — the same one for tablet and mobile — so this tier rebuilds
   it the same way: every panel stays a box, full width, icon then text — the
   closed ones a faint tint on the dark ground, the open one filled white with
   its description showing. Width has no free space to distribute,
   so the flex-grow the script animates does nothing here; the open state is
   read off the [data-active] attribute it also writes, and every colour it
   sets inline has to be overridden because it keeps writing them at all
   widths.                                                                    */
@media (max-width: 1199.98px) {
  #chainRow { flex-direction: column !important; gap: 12px !important; }
  #chainRow > [data-panel] {
    height: auto !important;
    flex: none !important;
    flex-direction: row !important;
    align-items: center;
    justify-content: flex-start !important;
    gap: 20px;
    padding: 20px !important;
    background: rgba(243,242,238,.04) !important;
    transition: background-color 620ms ease;
  }
  #chainRow > [data-panel][data-active] {
    align-items: flex-start;
    background: #FFFFFF !important;
  }

  /* Same square hairline box as the desktop row and the About panel — only the
     size steps down. The fills that used to be restated here are gone: the box
     is transparent now and the panel is read through the border instead. */
  #chainRow [data-icon] {
    width: 40px !important;
    height: 40px !important;
    border-radius: 0 !important;
    opacity: 1 !important;
    background: transparent !important;
    border: 1px solid rgba(255,255,255,.22);
  }
  #chainRow [data-icon] svg { stroke: #fff !important; }
  #chainRow [data-active] [data-icon] { border-color: rgba(20,20,20,.18); }
  #chainRow [data-active] [data-icon] svg { stroke: #141414 !important; }

  /* The text column is the panel's only other child. Its authored 20px gap is
     dropped and re-applied as padding on the description, so a closed row does
     not carry 20px of dead space above its collapsed body. */
  #chainRow > [data-panel] > div:not([data-icon]) {
    flex: 1 1 0;
    min-width: 0;
    gap: 0 !important;
  }
  #chainRow > [data-panel][data-active] > div:not([data-icon]) { padding-top: 8px; }

  #chainRow [data-title] { color: #FFFFFF !important; }
  #chainRow [data-active] [data-title] { color: #141414 !important; }

  #chainRow [data-body] {
    max-width: none !important;
    opacity: 0 !important;
    max-height: 0 !important;
    padding-top: 0 !important;
    color: rgba(20,20,20,.5) !important;
    transition: opacity 420ms ease,
                max-height 560ms cubic-bezier(.22,.61,.36,1),
                padding-top 560ms cubic-bezier(.22,.61,.36,1) !important;
  }
  #chainRow [data-active] [data-body] {
    opacity: 1 !important;
    max-height: 200px !important;
    padding-top: 14px !important;
  }
}

/* News cards --------------------------------------------------------------- *
   The same card runs on the homepage teaser and in the News page grid, both
   authored at 20px. The global map would take it to 18px, which is where the
   body copy sits — the headline has to stay a step clear of it, so both
   instances are pinned rather than just the homepage one.                     */
@media (max-width: 809.98px) {
  [data-screen-label="News"] [data-news-card] h3,
  #storyGrid > a h3 { font-size: 20px !important; }
}

/* Team carousel ------------------------------------------------------------ */
@media (max-width: 1199.98px) {
  /* Three to the row between 810 and 1199. The card count is the only thing
     that moves across breakpoints on valad.io's partner slideshow — four at
     1440, three at 810, one at 390 — while the 365px image height holds
     throughout. Measured at 810: 237x365 in a 730 column, which is
     (730 - 2x10) / 3.

     Without this the tablet tier fell through to the desktop four-up and put
     four cards in a 730 column: 175x365, a 0.48 sliver against the 0.85 the
     card is meant to be. The mobile rule below overrides this in turn. */
  #teamRow > div { flex: 0 0 calc((100% - 20px) / 3) !important; }
}
@media (max-width: 809.98px) {
  /* One card to the content column, which is what valad.io's partner slideshow
     does at this width: measured 350x365 at 390 — the full 350 column, on the
     same 10px gap, with the neighbour showing only as a sliver past the gutter.
     This was `min(76vw, 300px)`, i.e. 296 at 390, so the headshots ran a card
     size small against the original. The 365px image height is unchanged from
     desktop on both sites; only the width moves. No scroll snapping: the row
     carries its gutter as padding, and a mandatory snap immediately eats it by
     aligning the first card to the snapport edge. */
  #teamRow > div { flex: 0 0 100% !important; }
}

/* The homepage's Offices map section has been removed, and with it the only
   user of `.r-officesmap` — its breakpoint rules went with it. Contact's map is
   `.r-contactmap`, a separate component on contact-map.js, and is unaffected. */


/* ==========================================================================
   5. About
   ========================================================================== */

/* Values scroller ---------------------------------------------------------- */
@media (max-width: 1199.98px) {
  .r-val-names {
    left: var(--valad-gutter) !important;
    right: var(--valad-gutter) !important;
    top: clamp(96px, 15vh, 150px) !important;
    transform: none !important;
  }
  .r-val-quotes {
    left: var(--valad-gutter) !important;
    right: var(--valad-gutter) !important;
    width: auto !important;
    bottom: clamp(70px, 12vh, 130px) !important;
    height: 190px !important;
  }
}
@media (max-width: 809.98px) {
  /* Scoped to the value names themselves — the unscoped `> div` also caught
     the "Our values" eyebrow above them, blowing a 13px uppercase label up to
     26px and taking its .08em tracking with it. The names now sit at 36px on
     desktop — the homepage's display step — so they land on 28px here, the
     step 36px maps to everywhere else on mobile. */
  .r-val-names > div[data-vname] { font-size: 28px !important; }
  .r-val-quotes { height: 210px !important; }
  .r-val-quotes p { font-size: 18px !important; }
}

/* Journey scroller --------------------------------------------------------- *
   The stage text is 28px on desktop now, which the global map already steps to
   24px here, so this tier only has the panel height left to set.              */
@media (max-width: 1199.98px) { .r-journey-stage { height: 300px !important; } }
@media (max-width: 809.98px)  { .r-journey-stage { height: 340px !important; } }

/* Careers teaser ----------------------------------------------------------- */
@media (max-width: 1199.98px) {
  .r-teaser { grid-template-columns: minmax(0, 1fr) !important; }
  .r-teaser > div:first-child { aspect-ratio: 16/9 !important; }
}


/* ==========================================================================
   6. Portfolio + News (shared filter / grid / modal patterns)
   ========================================================================== */

@media (max-width: 1199.98px) {
  .r-filters { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; gap: clamp(20px, 4vw, 40px) !important; }
  #assetGrid { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
  #storyGrid { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
  /* Cell borders are authored per-cell for the desktop column count, so they
     land in the wrong places once the grid is 2-up. Redrawn for two columns. */
  #assetGrid > a, #storyGrid > a {
    border-right: 1px solid rgba(20,20,20,.18) !important;
    border-bottom: 1px solid rgba(20,20,20,.18) !important;
  }
  #assetGrid > a:nth-child(2n), #storyGrid > a:nth-child(2n) { border-right: none !important; }
  .r-lead-story { grid-template-columns: minmax(0, 1fr) !important; }
  .r-lead-story > div:first-child { border-right: none !important; border-bottom: 1px solid rgba(20,20,20,.18) !important; }
}
@media (max-width: 809.98px) {
  .r-filters { grid-template-columns: minmax(0, 1fr) !important; gap: 22px !important; }
  #storyGrid { grid-template-columns: minmax(0, 1fr) !important; }
  #storyGrid > a { border-right: none !important; }
  /* The lead story is a step above the grid cards and has to stay that way: the
     global map takes its 24px to 18px, which is below the 20px the story cards
     hold here. 22px keeps the two ranked in the right order. */
  .r-lead-story h2 { font-size: 22px !important; }
}

/* Detail drawers ----------------------------------------------------------- *
   The drawer is a right-hand panel at 84vw split into image | copy. Below 1024
   it becomes the whole screen with the image stacked on top of the copy.      */
@media (max-width: 1199.98px) {
  .r-modal-panel {
    width: 100% !important;
    grid-template-columns: minmax(0, 1fr) !important;
    grid-template-rows: auto minmax(0, 1fr) !important;
    box-shadow: none !important;
  }
  .r-modal-img { height: clamp(200px, 34vh, 320px) !important; }
  .r-modal-panel > div:last-child { justify-content: flex-start !important; padding: 34px 24px 44px !important; }
  .r-modal-panel > div:last-child > p { max-width: none !important; }
}
@media (max-width: 809.98px) {
  /* The drawer title is 24px on desktop, which the global map would take to
     18px — smaller than the 20px card the drawer was opened from. It holds the
     card's size instead. */
  .r-modal-panel h3 { font-size: 20px !important; }
  /* Three metadata columns divided by rules do not fit; they wrap instead. */
  .r-modal-meta { flex-wrap: wrap !important; gap: 20px 26px !important; }
  .r-modal-meta > div { padding-right: 26px !important; }
  .r-modal-meta > div:last-child { border-right: none !important; }
}

/* Leadership + Partners grids ----------------------------------------------- *
   Leadership carries a name, role and a line of description per card, so it
   follows the text-bearing `.r-3col` collapse (2-up, then 1-up) rather than
   the image-only asset grid's steady 2-up. Partners is the same nine-logo,
   three-column shape the homepage's own partner strip holds at every width —
   see `.r-logo-grid` above — so it only shrinks, it never re-columns.        */
@media (max-width: 1199.98px) {
  #leaderGrid { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
  #leaderGrid > a {
    border-right: 1px solid rgba(20,20,20,.18) !important;
    border-bottom: 1px solid rgba(20,20,20,.18) !important;
  }
  #leaderGrid > a:nth-child(2n) { border-right: none !important; }
  /* An odd card count leaves the last one alone on its row with nothing in the
     cell beside it, and the two-up rule above only spares the even positions —
     so that card drew a divider down the middle of a half-empty row. */
  #leaderGrid > a:last-child { border-right: none !important; }
  #partnerGrid > a { min-height: clamp(150px, 22vw, 200px) !important; }
}
@media (max-width: 809.98px) {
  #leaderGrid { grid-template-columns: minmax(0, 1fr) !important; }
  #leaderGrid > a { border-right: none !important; }
  #partnerGrid > a { min-height: 130px !important; padding: 18px !important; }
  #partnerGrid img { max-width: 60% !important; }
}


/* valad.io "Our Assets" picker ------------------------------------------------
   Desktop: four tracks, list and figure each spanning two. Only the active row
   shows its description — the rest collapse to their title, which is what makes
   the list read as an index rather than six paragraphs. Collapsing uses
   grid-template-rows so the description sizes itself; `overflow:hidden` on the
   wrapper is what hides it at 0fr.                                            */
.r-assets-def { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 500ms cubic-bezier(.22,.61,.36,1); }
.r-assets-def > p { min-height: 0; }
.r-assets-row[data-active] .r-assets-def { grid-template-rows: 1fr; }
.r-assets-term { transition: opacity 400ms ease; opacity: .45; }
.r-assets-row[data-active] .r-assets-term { opacity: 1; }
.r-assets-row:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }

/* Narrow: valad.io drops the grid entirely for a single flex column at 24px,
   and the figure follows the list rather than leading it — the reading order
   is heading, index, image. An earlier pass here pulled the figure up with
   `order:-1` on the reasoning that trailing it buries it; that is a different
   composition from the reference, so it is gone.

   The figure is height-clamped rather than ratio-locked, which is what keeps a
   portrait crop from running most of a phone screen tall: valad.io sets a
   320px floor and a 520px ceiling and lets the ratio pick between them. */
@media (max-width: 1199.98px) {
  .r-assets-grid { display: flex !important; flex-direction: column !important; gap: 24px !important; }
  .r-assets-col, .r-assets-fig { width: 100% !important; }
  .r-assets-col { gap: clamp(40px, 7vh, 90px) !important; }
  .r-assets-fig { min-height: 320px; max-height: 520px; }
}
@media (max-width: 809.98px) {
  .r-assets-row { flex-direction: column !important; gap: 10px !important; padding: 18px 0 !important; }
  .r-assets-row > div { flex: none !important; width: 100% !important; }
  /* Full bleed. Measured on the reference at 375: the section carries no
     horizontal padding at all and its content sits at x=20 with a 335 measure
     — one 20px inset, not the gutter plus a card pad on top of it, which is
     what made this read boxed-in and narrow next to the rest of the page.
     The card keeps its fill and loses its margin, so the panel runs edge to
     edge and only the type is inset. */
  /* Section padding goes entirely, not just the sides. Keeping the vertical
     padding left a band of the section's own ground below the card, and since
     the card is a shade off that ground it read as a stripe under the image
     rather than as space — the image looked like it ran into the section
     below. The card now fills the section edge to edge and top to bottom, so
     the panel is one tone, and its own padding is what spaces the contents.
     That is how the reference reads at this width: a single full-bleed panel,
     not a card sitting on a visible ground. */
  [data-asset-picker] { padding: 0 !important; }
  /* No bottom padding: the reference measures `50px 0 0` on this section at
     375, so the figure — last in the column — runs flush to the section's
     bottom edge and hands straight over to whatever follows. The 20px sides
     still apply to it; it is the vertical edge that bleeds, not the horizontal
     one. */
  .r-assets-card { max-width: none !important; padding: 48px 20px 0 !important; }
  /* Display steps down here, as it does across the site; the terms and their
     descriptions hold their desktop sizes on the reference. */
  .r-assets-card h2 { font-size: 32px !important; }
  /* The site's global mobile map steps 20px down to 18px, which is right for
     body copy and wrong here — these are the index's labels and the reference
     holds them at 20px on a 375 screen. Descriptions stay at 15px either way. */
  .r-assets-term { font-size: 20px !important; }
}


/* ==========================================================================
   7. Contact
   ========================================================================== */
@media (max-width: 1199.98px) {
  .r-contactmap { height: min(400px, 46vh) !important; }
}
@media (max-width: 809.98px) {
  /* The opening section is held to the screen so the closing band starts below
     the fold. It ran 754px in an 844px window, which left the band's top 90px
     showing on load — and the band's first render bleeds off its own top edge,
     so what appeared under the addresses was a slice of photograph. `svh` is
     the viewport with the browser chrome expanded, which is the state a page
     loads in, so this is the height that matters for the first glance; it is
     the same unit the hero is held to. Extra space falls below the content
     rather than recentring it, since the section closes on 0 bottom padding.
     Scoped by class: `[data-screen-label="Contact"]` also matches the closing
     band section on the homepage, which must not grow. */
  .r-contact-lead {
    min-height: 100vh;
    min-height: 100svh;
    box-sizing: border-box;
    /* Centred rather than left to sit at the top: the section is now taller
       than its content, and as a plain block all of that slack collected into
       one dead gap under the addresses. Centring splits it above and below, so
       the page reads as composed to the screen rather than padded out. The
       100px top padding still clears the fixed header first — `center` works on
       what is left after it. */
    display: flex;
    flex-direction: column;
    justify-content: center;
  }
  .r-contactmap { height: min(300px, 38vh) !important; }
  /* Contact's hero headline is empty, so "Get in touch at contact@valad.io" is
     the page's opening line rather than a standfirst under one. It is authored
     at the 32px the enquiry heading below it uses, and takes that heading's
     mobile size with it — the shared `.r-page-lede` rule in section 2 would
     otherwise pull it back to the 15px the other three pages want. */
  [data-screen-label="Contact"] .r-page-lede {
    font-size: 24px !important;
    line-height: 1.3 !important;
  }
  /* The city row and the address row are two separate grids that read as one
     table, so both keep three columns — dropping one to a single column would
     break the pairing. They shrink instead. */
  .r-offices { grid-template-columns: repeat(3, minmax(0, 1fr)) !important; gap: 10px !important; }
  .r-offices-cities > div { font-size: 14px !important; }
  .r-offices-addr > div   { font-size: 12px !important; line-height: 1.45 !important; }
}


/* ==========================================================================
   8. Careers
   ========================================================================== */
@media (max-width: 1199.98px) {
  .r-careers-intro { align-items: start !important; }
  .r-careers-intro > div:last-child { justify-content: flex-start !important; }
  .r-life > div:first-child { min-height: clamp(240px, 40vh, 380px) !important; }
}

/* ── News cards on mobile: scroll-stacked deck ───────────────────────────
   Each card gets its own tall wrapper and is sticky inside it — the same
   structure valad.io uses for its product cards, and the reason theirs
   works. The first attempt made the three cards siblings of one flex
   parent with no spare height: sticky then has nowhere to travel, and
   sticky-inside-flex is exactly the combination iOS Safari mishandles,
   which is why the section rendered blank on an iPhone while measuring
   correctly in every emulator.

   The wrapper is display:contents on desktop, so the three-up grid above
   this breakpoint is untouched. */
.r-news-stack { display: contents; }

@media (max-width: 809.98px) {
  /* Block flow, not flex: sticky-inside-flex is the combination iOS Safari
     mishandles. The cards share this one containing block so an early card
     stays pinned while the next rides up over it — that overlap IS the
     deck. Per-card wrappers were tried first and cannot work: each card
     releases at its own wrapper's end, so they never overlap. */
  .r-news-grid {
    display: block !important;
    /* Keep the z-index ladder below inside this element. Without a
       stacking context of its own, the cards' z-indexes are resolved
       against the page root and a pinned card can paint over neighbouring
       sections instead of only over its siblings. */
    isolation: isolate;
    position: relative;
    z-index: 0;
    /* No trailing padding. A sticky card's travel comes from whatever
       follows it inside the same containing block, so cards 1 and 2 are
       held up by the height of the cards after them — the deck needs no
       manufactured space at the end. */
    padding-bottom: 0 !important;
  }
  .r-news-stack { display: contents; }

  .r-news-grid [data-news-card] {
    position: -webkit-sticky;
    position: sticky;
    margin-bottom: 22px;
    /* Must be opaque: a stacked card sits on top of the one before it, and
       a transparent card lets the buried card's text show through — which
       reads as overlapping text, not as a deck. */
    background: #EDECE8;
    border: 1px solid rgba(20, 20, 20, .10);
    padding: 0 0 24px;
    box-shadow: 0 -8px 24px rgba(20, 20, 20, .06);
  }
  /* Stepped offsets leave a sliver of each buried card visible. */
  .r-news-grid [data-news-card]:nth-of-type(1) { top: 78px; }
  /* The z-index ladder is what makes the deck read: each card must paint
     over the one before it. Without it a later card can land behind an
     earlier one, showing as text bleeding through from underneath. */
  .r-news-stack:nth-child(1) [data-news-card] { top: 78px; z-index: 1; }
  .r-news-stack:nth-child(2) [data-news-card] { top: 94px; z-index: 2; }
  .r-news-stack:nth-child(3) [data-news-card] { top: 110px; z-index: 3; }
  /* The last card is the one that would need padding beneath it to have
     anywhere to travel. Leaving it in normal flow removes that need
     entirely: it simply rides up over the two pinned cards and completes
     the stack, and the section ends level with it. */
  .r-news-stack:last-child [data-news-card] {
    /* relative, not static: it stays in normal flow and needs no travel
       space, but remains a positioned element so its z-index applies. As
       static it painted beneath the pinned cards above it, which showed
       as their text bleeding through. */
    position: relative;
    /* top must be reset: on a relatively positioned element it offsets the
       card visually without adding to layout height, so the 110px sticky
       offset pushed it out of the section and over the one below. */
    top: auto;
    margin-bottom: 0;
  }
  /* Close the section on the same gap it opens with (the divider-to-first-card
     distance), rather than the section's larger desktop padding. The scale's
     smallest step is that gap to within a few pixels, so this stays on the
     token rather than keeping a lone hand-tuned value for one edge. */
  #news { padding-bottom: var(--v-space-xs) !important; }

  /* Image flush to the card's top and sides; text inset instead. */
  .r-news-grid [data-news-card] > div:first-child { width: 100%; }
  .r-news-grid [data-news-card] > :not(:first-child) {
    padding-left: 18px;
    padding-right: 18px;
  }
  /* A transformed sticky element becomes a containing block and stops
     pinning, so the reveal here is a fade only. */
  .r-news-grid [data-news-card][data-reveal] { transform: none !important; }
}

/* Closing CTA band ----------------------------------------------------------
   valad.io keeps 80px of side padding on this band at 810 even though its other
   sections drop to 40, and the band grows from 632px to ~872px as the headline
   wraps. Below 810 it comes in to the 20px gutter and 875px, with the headline
   at 24px/33.6px -- the same 1.4 ratio it holds on desktop. */
@media (max-width: 1199.98px) {
  .r-cta-band { height: 872px; padding: 200px 80px; }
  /* The four renders are placed for the 1425x632 desktop plate. The plate here
     is 240px taller and much narrower, so the two that sit inboard are pushed
     down into the band's own deeper margins rather than being left overlapping
     the copy, and the pair that bleed off an edge keep their anchors.

     B is the exception, and only became visible once the stray brace above this
     block stopped swallowing the whole tier. Its left:74 anchor clears the copy
     at 1425 because a 404px headline centres at x 510-915, well to its right.
     At 795 that same headline centres at x 196-600 and lands on top of it —
     measured 17,336px of overlap on the headline and 2,469 on the buttons. The
     copy wins on z-index so it stays legible, but dark text over a photograph
     is not the composition. B already bleeds off the bottom, so dropping it
     below the button row keeps its anchor and its bleed and clears the copy. */
  .r-cta-band-fig--b { top: 560px; }
  .r-cta-band-fig--c { top: 500px; right: 40px; }
  .r-cta-band-fig--d { top: 40px; left: 40px; }
}
@media (max-width: 809.98px) {
  .r-cta-band { height: 875px; padding: 200px var(--valad-gutter); }
  .r-cta-band-head { font-size: 24px; line-height: 33.6px; max-width: 350px; }

  /* The renders are held still at this width. header-scroll.js still computes
     the scroll progress and writes `--cta-v` inline on the band, so pinning it
     to 0 needs `!important` to beat that — an author `!important` outranks a
     normal inline declaration, which is the one case where it does.

     Doing it here rather than by branching in the script means it is the
     breakpoint that decides, so it stays correct through a resize in either
     direction with no stale value left behind on the element. Zero is the
     resting state the CSS already falls back to, and the mobile geometry above
     was measured off valad.io at rest, so frozen is the composition as read. */
  .r-cta-band { --cta-v: 0 !important; }
  /* An earlier note here reasoned that at 390 the plate was too narrow for a
     faithful scatter, so C and D were dropped and A and B were shrunk. Measured
     against the live site at 390, that was wrong on both counts: valad.io keeps
     all four renders, and runs them *larger* than we did, not smaller. Read off
     its 390x875 plate, as offsets from the plate's own box:

       A  325x258   top   -8   right -164   (bleeds off the top and right)
       B  231x314   top  627   left   -60   (bleeds off the left and bottom)
       C  113x140   top  699   right   34
       D  117x114   top  119   left    46

     The scatter works at this width because the copy occupies a band across
     the middle -- headline at 320, buttons from 466 -- and all four sit clear
     of it: D and A finish by 250, C and B start at 627. So the plate reads as
     four objects on paper here exactly as it does at 1440. */
  .r-cta-band-fig--a { width: 325px; height: 258px; right: -164px; top:  -8px; }
  .r-cta-band-fig--b { width: 231px; height: 314px; left:   -60px; top: 627px; }
  .r-cta-band-fig--c { width: 113px; height: 140px; right:   34px; top: 699px; }
  .r-cta-band-fig--d { width: 117px; height: 114px; left:    46px; top: 119px; }

  /* valad.io stacks the band's buttons at this width rather than running them
     as a row -- measured 53px apart, which is the 48px button on the same 4px
     gap the row uses. Only the two-button pages (About, Contact) differ. */
  .r-cta-band-actions { flex-direction: column; align-items: center; }
}
