/* ==========================================================================
   V15 Vantage — 180 Degrees Consulting Delft–Rotterdam
   Vanilla CSS. No framework, no build step. Opens as a plain file.

   Layering inside the hero (all self-contained, nothing position:fixed —
   so the bottom-blur can never bleed onto the content below, with or
   without JavaScript):
     0  .hero__media    photo layers (parallax wrapper + Ken Burns img)
     2  .hero__blur     bottom-only backdrop blur, masked, no darkening
     3  .hero__inner    bottom-aligned hero content
     40 .site-header    sticky navbar
     90 .mobile-menu    slide-down overlay
   ========================================================================== */

/* Inter (300–700) is requested from Google Fonts by a <link> in each page's
   <head>, not by an @import here. An @import chains HTML -> styles.css ->
   font CSS -> font files, delaying first paint by a whole round trip. */

/* --------------------------------------------------------------- tokens -- */

:root {
  --green: #78b038;          /* brand mark — decorative / large surfaces only */
  --green-deep: #4a7322;     /* AA-safe on white for text */
  --green-darkest: #3d6b1c;

  --night: #0a0f16;          /* sampled from the hero set's darkest water */
  --night-2: #111823;
  --ink: #0e1411;
  --paper: #fafbf9;
  --paper-2: #f1f4ef;
  --line: #dfe4da;
  --muted: #5c6660;

  --wrap: 1240px;
  --nav-h: 74px;

  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
}

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

html {
  scroll-behavior: smooth;
  /* the sticky navbar must not cover the target of a scroll-anchor link */
  scroll-padding-top: calc(var(--nav-h) + 16px);
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  font-family: Inter, "Segoe UI", system-ui, -apple-system, sans-serif;
  font-size: 17px;
  line-height: 1.65;
  color: var(--ink);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 { line-height: 1.12; letter-spacing: -0.022em; font-weight: 600; margin: 0; }
p { margin: 0 0 1rem; }
img { max-width: 100%; display: block; }
a { color: var(--green-deep); }

.wrap { width: min(100% - 3rem, var(--wrap)); margin-inline: auto; }

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--ink); color: #fff; padding: 0.75rem 1.15rem;
  border-radius: 0 0 10px 0; font-weight: 600; text-decoration: none;
}
.skip:focus { left: 0; }

:where(a, button, input, textarea, summary):focus-visible {
  outline: 2px solid var(--green);
  outline-offset: 3px;
  border-radius: 4px;
}
/* on the photo, the brand green alone is too low-contrast for a focus ring */
.hero :where(a, button, input):focus-visible,
.site-header :where(a, button, input):focus-visible,
.mobile-menu :where(a, button, input):focus-visible {
  outline: 2px solid #fff;
  outline-offset: 3px;
}

/* ------------------------------------------------------- liquid glass -- */
/* Reusable. Used by: nav search pill, profile button, hamburger, secondary
   hero CTA, prev/next city buttons, the search + member panels.            */

.liquid-glass {
  position: relative;
  overflow: hidden;
  background: rgba(255, 255, 255, 0.01);
  background-blend-mode: luminosity;
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
  border: none;
  box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.1);
}

/* thin gradient-stroke border: a padded gradient box, dual-masked so only
   the padding ring paints and the fill is punched out */
.liquid-glass::before {
  content: "";
  position: absolute;
  inset: 0;
  padding: 1.4px;
  border-radius: inherit;
  background: linear-gradient(
    160deg,
    rgba(255, 255, 255, 0.45) 0%,
    rgba(255, 255, 255, 0) 40%,
    rgba(255, 255, 255, 0) 60%,
    rgba(255, 255, 255, 0.45) 100%
  );
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  pointer-events: none;
}

/* ---------------------------------------------------------- animation -- */

@keyframes blurFadeUp {
  from { opacity: 0; filter: blur(20px); transform: translateY(40px); }
  to   { opacity: 1; filter: blur(0);    transform: translateY(0); }
}

/* staggered entrance — base state is invisible so the delay reads as a hold */
[data-fade] {
  opacity: 0;
  animation: blurFadeUp 1s var(--ease-out) forwards;
}
[data-fade="0"]   { animation-delay: 0ms; }
[data-fade="100"] { animation-delay: 100ms; }
[data-fade="200"] { animation-delay: 200ms; }
[data-fade="300"] { animation-delay: 300ms; }
[data-fade="350"] { animation-delay: 350ms; }
[data-fade="400"] { animation-delay: 400ms; }
[data-fade="500"] { animation-delay: 500ms; }
[data-fade="600"] { animation-delay: 600ms; }
[data-fade="700"] { animation-delay: 700ms; }
[data-fade="800"] { animation-delay: 800ms; }
[data-fade="900"] { animation-delay: 900ms; }

@keyframes kenBurns {
  from { transform: scale(1.02) translate3d(0, 0, 0); }
  to   { transform: scale(1.13) translate3d(-1.2%, -1.6%, 0); }
}

/* ------------------------------------------------ scroll choreography -- */
/*
   Native CSS scroll-driven animation. No JavaScript, no library, no build
   step, and nothing to keep in sync on the main thread — the browser runs
   these off the compositor.

   Everything here is additive: the base state of every element is visible and
   in place. A browser without `animation-timeline` support simply shows the
   finished state, which is the page exactly as it was. Reduced motion opts
   out at the @media level, so nothing is animated and nothing starts hidden.

   `view()` measures each element against the viewport, so a grid of cards
   staggers itself for free — later cards enter later. No per-item delays.
*/

@keyframes revealUp {
  from { opacity: 0; transform: translateY(26px); }
  to   { opacity: 1; transform: translateY(0); }
}

@keyframes heroExit {
  /* hero copy lifts away and dims as the section scrolls out from under it */
  from { opacity: 1; transform: translateY(0); }
  to   { opacity: 0; transform: translateY(-70px); }
}

@keyframes railGrow {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {

    /* --- content reveals. Selectors target the existing structure, so no
           markup had to change and nothing can fall out of sync with it. --- */
    .section-head,
    .prose,
    .fact-panel,
    .card,
    .timeline-step,
    .service-list article,
    .proof-strip div,
    .person,
    .cta-panel > *,
    .intake-form,
    .guide-body > * {
      animation: revealUp 1ms linear both;
      animation-timeline: view();
      animation-range: entry 4% cover 22%;
    }

    /* --- the hero hands off to the page instead of just scrolling away.
           Staged heroes are excluded: their contents are pinned, so a view()
           timeline would sit frozen while the section is stuck. They use the
           eased --hero-p that drives the dolly instead, so copy and camera
           move on exactly the same clock. --- */
    .hero:not(.hero--stage) .hero__inner {
      animation: heroExit 1ms linear both;
      animation-timeline: view();
      animation-range: exit 0% exit 85%;
    }

    /* --- a hairline that draws itself across each section head --- */
    .section-head::after {
      content: "";
      display: block;
      height: 1px;
      margin-top: 1.6rem;
      background: linear-gradient(90deg, var(--green) 0%, rgba(120, 176, 56, 0) 70%);
      transform-origin: left center;
      animation: railGrow 1ms linear both;
      animation-timeline: view();
      animation-range: entry 10% cover 30%;
    }
    .section--dark .section-head::after {
      background: linear-gradient(90deg, #a7d16a 0%, rgba(167, 209, 106, 0) 70%);
    }
  }
}

/* ------------------------------------------------------------- navbar -- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 40;
  height: var(--nav-h);
  display: flex;
  align-items: center;
  /* Dark glass at all times, and opaque enough that white nav text clears AA
     even when what sits behind it is the near-white page body rather than a
     night photo — the guide has no hero, and every page's header crosses
     light sections on scroll. */
  background: rgba(10, 15, 22, 0.8);
  -webkit-backdrop-filter: blur(14px) saturate(1.3);
  backdrop-filter: blur(14px) saturate(1.3);
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  transition: background 0.4s var(--ease-out), border-color 0.4s var(--ease-out);
}
.site-header.is-scrolled {
  background: rgba(10, 15, 22, 0.92);
  border-bottom-color: rgba(255, 255, 255, 0.12);
}

.nav-shell {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  width: min(100% - 2.5rem, var(--wrap));
  margin-inline: auto;
}

.brand {
  display: flex; align-items: center; gap: 0.65rem;
  text-decoration: none; color: #fff; flex-shrink: 0;
}
.brand img { width: 34px; height: 24px; object-fit: contain; }
.brand span { display: flex; flex-direction: column; line-height: 1.18; }
.brand strong { font-size: 0.845rem; font-weight: 600; letter-spacing: -0.01em; }
.brand small { font-size: 0.68rem; color: rgba(255, 255, 255, 0.62); letter-spacing: 0.06em; text-transform: uppercase; }

.main-nav {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  margin-inline: auto;
  min-width: 0;   /* flex items default to min-width:auto and refuse to shrink */
}
.main-nav a {
  text-decoration: none;
  font-size: 0.875rem;
  font-weight: 400;
  color: rgba(255, 255, 255, 0.74);
  padding: 0.5rem 0.8rem;
  border-radius: 999px;
  white-space: nowrap;
  transition: color 0.25s var(--ease-out), background 0.25s var(--ease-out);
}
.main-nav a:hover { color: #fff; }

/* NAV DIFFERENTIATOR — this variant's device:
   scroll-anchor links are plain text; own-page links are glass pills with a
   green status dot. Consistent across all six pages.                        */
.main-nav .nav-page {
  color: rgba(255, 255, 255, 0.92);
  font-weight: 500;
  background: rgba(255, 255, 255, 0.055);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.13);
  padding-left: 1.6rem;
}
.main-nav .nav-page::before {
  content: "";
  position: absolute;
  left: 0.75rem; top: 50%;
  width: 5px; height: 5px; margin-top: -2.5px;
  border-radius: 50%;
  background: var(--green);
  opacity: 0.55;
  transition: opacity 0.25s var(--ease-out), box-shadow 0.25s var(--ease-out);
}
.main-nav .nav-page { position: relative; }
.main-nav .nav-page:hover { background: rgba(255, 255, 255, 0.1); }
.main-nav .nav-page:hover::before { opacity: 1; }
.main-nav .nav-page[aria-current="page"] {
  background: rgba(120, 176, 56, 0.17);
  box-shadow: inset 0 0 0 1px rgba(120, 176, 56, 0.42);
  color: #fff;
}
.main-nav .nav-page[aria-current="page"]::before {
  opacity: 1;
  box-shadow: 0 0 0 3px rgba(120, 176, 56, 0.25);
}

.nav-tools { display: flex; align-items: center; gap: 0.55rem; flex-shrink: 0; }

.nav-search {
  display: flex; align-items: center; gap: 0.5rem;
  height: 38px; padding: 0 0.95rem;
  border-radius: 999px;
  color: rgba(255, 255, 255, 0.72);
  font: inherit; font-size: 0.82rem;
  cursor: pointer;
  min-width: 148px;
  transition: color 0.25s var(--ease-out);
}
.nav-search:hover { color: #fff; }
.nav-profile,
.nav-toggle {
  display: flex; align-items: center; justify-content: center;
  width: 38px; height: 38px;
  border-radius: 50%;
  color: rgba(255, 255, 255, 0.82);
  cursor: pointer;
  padding: 0;
  transition: color 0.25s var(--ease-out);
}
.nav-profile:hover, .nav-toggle:hover { color: #fff; }
.nav-toggle { display: none; border-radius: 12px; }

.ico { width: 17px; height: 17px; stroke: currentColor; fill: none; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; flex-shrink: 0; }

/* --------------------------------------------------------------- hero -- */

.hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;              /* contains the parallax overscan */
  min-height: 100vh;
  min-height: 100svh;
  margin-top: calc(-1 * var(--nav-h));   /* photo runs up behind the navbar */
  padding-top: var(--nav-h);
  display: flex;
  flex-direction: column;
  justify-content: flex-end;     /* hero content is bottom-aligned */
  background: var(--night);      /* shows through before the photo decodes */
}
.hero--inner { min-height: 86vh; min-height: 86svh; }

/* ------------------------------------------------------- scroll stage -- */
/*
   The hero gets a scroll runway so the camera has somewhere to travel: the
   section is two viewports tall and its contents pin to the top for the first
   one. Scrolling the second viewport dollies into the photograph instead of
   just sliding it away.

   Gated on reduced-motion at the CSS level rather than on a JS class, so the
   page height is settled at first paint and nothing shifts once scripts run.
   With reduced motion the runway disappears entirely and the hero is a plain
   one-viewport section again — no dead scroll to wade through.
*/
@media (prefers-reduced-motion: no-preference) {
  /* The section becomes a plain block: as a flex column with
     justify-content:flex-end it shoved the sticky child to the far end of the
     runway, leaving the top of the page empty. The stage is the flex context
     now, and it carries the nav padding too. */
  .hero--stage {
    min-height: 0;
    height: 200vh;
    height: 200svh;
    display: block;
    padding-top: 0;
    /* `overflow: hidden` on an ancestor silently disables position:sticky on
       its descendants — the stage scrolled away instead of pinning. The clip
       is no longer needed here anyway: .hero__stage does it now. */
    overflow: visible;
  }
  .hero--stage.hero--inner { height: 186vh; height: 186svh; }
  .hero--stage .hero__stage {
    position: sticky;
    top: 0;
    height: 100vh;
    height: 100svh;
    overflow: hidden;
    padding-top: var(--nav-h);
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
  }
  /* the photo must fill the pinned stage, not the two-viewport section */
  .hero--stage .hero__media { top: 0; height: 100%; }

  /* Copy recedes as the camera pushes in, on the same eased clock as the
     dolly. --hero-p is written by hero-controller.js; the fallback of 0
     means an un-upgraded page simply shows the copy in place. */
  .hero--stage .hero__inner {
    opacity: clamp(0, calc(1 - var(--hero-p, 0) * 1.45), 1);
    transform: translate3d(0, calc(var(--hero-p, 0) * -70px), 0);
    will-change: opacity, transform;
  }
  .hero--stage .hero__scroll {
    opacity: clamp(0, calc(1 - var(--hero-p, 0) * 1.8), 1);
  }

  /* Without WebGL the dolly still happens, just without depth separation:
     a plain scale on the photo driven by the same progress value. */
  .hero--stage:not(.is-webgl) .hero__img {
    transform: scale(calc(1.02 + var(--hero-p, 0) * 0.38));
    transform-origin: center 45%;
  }
  .hero--stage:not(.is-webgl) .hero__img { animation: none; }
}

/* scroll indicator — SCROLL, a progress rail, and a percentage */
.hero__scroll {
  position: absolute;
  left: 0; right: 0; bottom: 1.5rem;
  z-index: 4;
  width: min(100% - 3rem, var(--wrap));
  margin-inline: auto;
  display: flex;
  align-items: center;
  gap: 0.9rem;
  font-size: 0.68rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.72);
  text-shadow: 0 1px 10px rgba(0, 0, 0, 0.6);
  pointer-events: none;
}
.hero__scroll-track {
  flex: 1;
  max-width: 260px;
  height: 1px;
  background: rgba(255, 255, 255, 0.28);
  position: relative;
  overflow: hidden;
}
.hero__scroll-fill {
  position: absolute;
  inset: 0;
  background: var(--green);
  transform: scaleX(0);
  transform-origin: left center;
}
.hero__scroll-count { font-variant-numeric: tabular-nums; min-width: 3.2em; }
.hero[data-tone="light"] .hero__scroll {
  color: #2c352f;
  text-shadow: 0 1px 10px rgba(255, 255, 255, 0.8);
}
.hero[data-tone="light"] .hero__scroll-track { background: rgba(0, 0, 0, 0.22); }
.no-js .hero__scroll { display: none; }
@media (prefers-reduced-motion: reduce) { .hero__scroll { display: none; } }

/* parallax wrapper — JS writes transform here only. 15% overscan top and
   bottom gives the parallax somewhere to travel without exposing an edge. */
.hero__media {
  position: absolute;
  left: 0; right: 0;
  top: -15%;
  height: 130%;
  z-index: 0;
  will-change: transform;
}

/* Ken Burns lives on the img itself, so the two transforms never collide */
.hero__img {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: center 42%;
  transform: scale(1.02);
  animation: kenBurns 38s ease-in-out infinite alternate;
}
.hero__img--incoming { opacity: 0; }
/* crossfade is opacity-only — never triggers layout */
.hero__img { transition: opacity 0.62s var(--ease-out); }

.hero.is-paused .hero__img { animation-play-state: paused; }

/* ---------------------------------------------------------- depth hero -- */
/* hero-depth.js mounts a WebGL canvas that renders the photo through its
   depth map. It only ever appears on top of a working <img>, so removing it
   returns the page to the CSS pan with no other change. */

.hero__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  z-index: 1;
}

/* With the shader doing the parallax, the wrapper no longer needs its 15%
   overscan and the img no longer needs a 1.13 zoom. Dropping both is a real
   sharpness gain: the photo is sampled near 1:1 instead of magnified ~1.3x
   before the display even scales it. */
.hero.is-webgl .hero__media {
  top: 0;
  height: 100%;
  transform: none !important;
  will-change: auto;
}
/* the <img> layers stay in the DOM — they carry the alt text and are the
   fallback the moment WebGL goes away — but they are not painted */
.hero.is-webgl .hero__img {
  opacity: 0 !important;
  animation: none !important;
}

/* bottom-only blur. Blur, no darkening — the mask fades it out by mid-frame.
   Sits above the photo and below the content.                              */
.hero__blur {
  position: absolute;
  inset: 0;
  z-index: 2;
  -webkit-backdrop-filter: blur(26px);
  backdrop-filter: blur(26px);
  -webkit-mask-image: linear-gradient(to top, black 0%, transparent 45%);
  mask-image: linear-gradient(to top, black 0%, transparent 45%);
  pointer-events: none;
}

/* a very light scrim under the text only — the spec forbids darkening the
   photo, so this is confined to the text column and stays subtle. It is the
   difference between "legible" and "nearly legible" on the fog frame. */
.hero__inner {
  position: relative;
  z-index: 3;
  width: min(100% - 3rem, var(--wrap));
  margin-inline: auto;
  padding-block: 3rem 3.4rem;
  color: #fff;
}

/* The pool spans near-black night frames and a near-white fog frame. White
   copy survives the dark end unaided but disappears on the light end, so
   everything in the hero carries a shadow. This darkens glyph edges only —
   the photograph itself is never tinted, per the blur-only rule above. */
.hero__meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0.55rem 0.9rem;
  font-size: 0.775rem; letter-spacing: 0.1em; text-transform: uppercase;
  color: rgba(255, 255, 255, 0.92);
  margin-bottom: 1.35rem;
  font-weight: 500;
  text-shadow: 0 1px 14px rgba(0, 0, 0, 0.65);
}
.hero__meta .dot { width: 4px; height: 4px; border-radius: 50%; background: var(--green); flex-shrink: 0; }
.hero__meta .tag {
  padding: 0.28rem 0.7rem; border-radius: 999px;
  background: rgba(120, 176, 56, 0.2);
  box-shadow: inset 0 0 0 1px rgba(120, 176, 56, 0.45);
  color: #eaf5dc; letter-spacing: 0.08em;
}

.hero h1 {
  font-size: clamp(2.6rem, 6.4vw, 5.1rem);
  font-weight: 600;
  max-width: 17ch;
  margin-bottom: 1.15rem;
  text-shadow: 0 2px 26px rgba(0, 0, 0, 0.62), 0 1px 3px rgba(0, 0, 0, 0.3);
}
.hero h1 em { font-style: normal; color: #c6e39a; }

.hero__lede {
  font-size: clamp(1.02rem, 1.5vw, 1.2rem);
  font-weight: 300;
  line-height: 1.6;
  max-width: 60ch;
  color: #fff;
  text-shadow: 0 1px 16px rgba(0, 0, 0, 0.7), 0 1px 3px rgba(0, 0, 0, 0.35);
  margin-bottom: 1.9rem;
}

.hero__actions { display: flex; flex-wrap: wrap; gap: 0.7rem; align-items: center; }

.btn {
  display: inline-flex; align-items: center; gap: 0.5rem;
  padding: 0.82rem 1.5rem;
  border-radius: 999px;
  font-size: 0.9rem; font-weight: 500;
  text-decoration: none;
  cursor: pointer;
  border: none;
  white-space: nowrap;
  transition: transform 0.25s var(--ease-out), background 0.25s var(--ease-out), box-shadow 0.25s var(--ease-out);
}
.btn--solid { background: #fff; color: #0d1210; }
.btn--solid:hover { background: #eef2ea; transform: translateY(-1px); }
.btn--glass { color: #fff; }

/* Hero-scoped legibility floor. The reusable .liquid-glass fill is
   rgba(255,255,255,0.01) by design, which reads as nothing when the frame
   behind it is the near-white fog photo. Controls sitting directly on the
   photography get a neutral tint so they stay operable across all eight
   frames; the .liquid-glass class itself is unchanged. */
.hero .btn--glass,
.hero .city-switch__btn {
  background: rgba(10, 15, 22, 0.34);
  text-shadow: 0 1px 12px rgba(0, 0, 0, 0.6);
}
.hero .btn--glass:hover,
.hero .city-switch__btn:hover:not(:disabled) {
  background: rgba(10, 15, 22, 0.5);
  transform: translateY(-1px);
}

/* ---------------------------------------------------------- light frame --
   Two frames in the pool are too bright for white copy: the fog render, which
   is near-white end to end, and the Delft Markt golden hour, whose sky sits
   behind the text column. No amount of text shadow gets white copy to AA over
   either, and darkening the photo is ruled out, so the hero inverts to dark
   type for those frames. Set from the POOL entry's `tone`.

   The small-text colours are near-black rather than the mid-greys this block
   originally carried. Those greys were tuned against the near-white fog frame
   and cleared AA there, but the golden-hour frame is mid-tone, not white — it
   measured 4.37:1 for the meta row, 4.15:1 for the lede and 3.81:1 for the
   counter, all short of 4.5. Going darker costs nothing on the fog frame,
   where more contrast is only ever an improvement. */

.hero[data-tone="light"] .hero__meta { color: #10160f; text-shadow: 0 1px 10px rgba(255, 255, 255, 0.75); }
.hero[data-tone="light"] .hero__meta .tag {
  background: rgba(74, 115, 34, 0.16);
  box-shadow: inset 0 0 0 1px rgba(61, 107, 28, 0.5);
  color: #33540f;
}
.hero[data-tone="light"] h1 {
  color: #10160f;
  text-shadow: 0 1px 14px rgba(255, 255, 255, 0.8);
}
.hero[data-tone="light"] h1 em { color: var(--green-darkest); }
.hero[data-tone="light"] .hero__lede {
  color: #141a13;
  text-shadow: 0 1px 12px rgba(255, 255, 255, 0.85);
}
.hero[data-tone="light"] .btn--solid { background: #10160f; color: #fff; }
.hero[data-tone="light"] .btn--solid:hover { background: #232b26; }
.hero[data-tone="light"] .city-switch__now { color: #10160f; text-shadow: 0 1px 10px rgba(255, 255, 255, 0.8); }
.hero[data-tone="light"] .city-switch__now strong { color: #10160f; }
/* the glass tint that reads over a night frame lands at mid-grey over a
   white one, which drops white labels under AA — deepen it here */
.hero[data-tone="light"] .btn--glass,
.hero[data-tone="light"] .city-switch__btn { background: rgba(10, 15, 22, 0.62); }
.hero[data-tone="light"] .btn--glass:hover,
.hero[data-tone="light"] .city-switch__btn:hover:not(:disabled) { background: rgba(10, 15, 22, 0.74); }

/* ------------------------------------------------- city cycling control -- */

.city-switch {
  display: flex; align-items: center; gap: 0.85rem;
  margin-top: 2.3rem;
  flex-wrap: wrap;
}
.city-switch__btn {
  display: flex; align-items: center; gap: 0.4rem;
  height: 40px; padding: 0 1.05rem;
  border-radius: 999px;
  color: rgba(255, 255, 255, 0.86);
  font: inherit; font-size: 0.8rem; font-weight: 500;
  cursor: pointer;
  transition: color 0.25s var(--ease-out), background 0.25s var(--ease-out);
}
.city-switch__btn:hover:not(:disabled) { color: #fff; background: rgba(255, 255, 255, 0.09); }
.city-switch__btn:disabled { opacity: 0.45; cursor: default; }

.city-switch__now {
  display: flex; flex-direction: column; gap: 0.1rem;
  font-size: 0.74rem; line-height: 1.3;
  color: rgba(255, 255, 255, 0.8);
  letter-spacing: 0.055em;
  text-shadow: 0 1px 12px rgba(0, 0, 0, 0.65);
}
.city-switch__now strong {
  font-size: 0.8rem; font-weight: 500; color: #fff;
  letter-spacing: 0.02em;
}
.city-switch__count { font-variant-numeric: tabular-nums; }

/* JS-only affordances stay hidden until JS confirms it is running */
.no-js .city-switch,
.no-js .nav-search,
.no-js .nav-profile,
.no-js .nav-toggle { display: none; }

/* ------------------------------------------------------- mobile menu -- */

.mobile-menu {
  position: fixed;
  top: var(--nav-h); left: 0;
  /* matches the scroll-lock's scrollbar compensation so the fixed menu
     stays flush with the body edge instead of jumping when it opens */
  right: var(--sbw, 0px);
  z-index: 90;
  background: rgba(10, 15, 22, 0.95);
  -webkit-backdrop-filter: blur(18px) saturate(1.4);
  backdrop-filter: blur(18px) saturate(1.4);
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
  padding: 1.1rem 0 1.5rem;
  /* closed state: collapsed and non-interactive, never in flow, so opening
     it cannot shift a single pixel of page layout */
  transform: translateY(-12px);
  opacity: 0;
  visibility: hidden;
  transition: transform 0.34s var(--ease-out), opacity 0.28s var(--ease-out), visibility 0s linear 0.34s;
  max-height: calc(100dvh - var(--nav-h));
  overflow-y: auto;
}
.mobile-menu.is-open {
  transform: translateY(0);
  opacity: 1;
  visibility: visible;
  transition: transform 0.38s var(--ease-out), opacity 0.3s var(--ease-out), visibility 0s;
}

.mobile-menu__inner { width: min(100% - 2.5rem, var(--wrap)); margin-inline: auto; }

.mobile-menu a {
  display: block;
  padding: 0.72rem 0.15rem;
  color: rgba(255, 255, 255, 0.82);
  text-decoration: none;
  font-size: 1.02rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.07);
  opacity: 0;
  transform: translateY(-8px);
}
.mobile-menu.is-open a { animation: blurFadeUp 0.5s var(--ease-out) forwards; }
.mobile-menu.is-open a:nth-child(1) { animation-delay: 40ms; }
.mobile-menu.is-open a:nth-child(2) { animation-delay: 80ms; }
.mobile-menu.is-open a:nth-child(3) { animation-delay: 120ms; }
.mobile-menu.is-open a:nth-child(4) { animation-delay: 160ms; }
.mobile-menu.is-open a:nth-child(5) { animation-delay: 200ms; }
.mobile-menu.is-open a:nth-child(6) { animation-delay: 240ms; }
.mobile-menu.is-open a:nth-child(7) { animation-delay: 280ms; }

.mobile-menu .nav-page {
  color: #fff; font-weight: 500;
  padding-left: 1.15rem;
  position: relative;
}
.mobile-menu .nav-page::before {
  content: "";
  position: absolute; left: 0; top: 50%;
  width: 5px; height: 5px; margin-top: -2.5px;
  border-radius: 50%; background: var(--green);
}
.mobile-menu .nav-page[aria-current="page"] { color: #c6e39a; }

.mobile-menu__tools {
  display: flex; gap: 0.6rem; align-items: center;
  margin-top: 1.2rem;
  opacity: 0;
}
.mobile-menu.is-open .mobile-menu__tools {
  animation: blurFadeUp 0.5s var(--ease-out) 320ms forwards;
}
.mobile-menu__tools .nav-search { flex: 1; }

/* ------------------------------------------- search / member panels -- */

.panel {
  position: fixed;
  z-index: 95;
  top: calc(var(--nav-h) + 10px);
  right: max(1.25rem, calc((100vw - var(--wrap)) / 2));
  width: min(calc(100vw - 2.5rem), 400px);
  border-radius: 16px;
  background: rgba(12, 18, 26, 0.93);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.45), inset 0 1px 1px rgba(255, 255, 255, 0.1);
  color: #fff;
  padding: 0.9rem;
  opacity: 0; visibility: hidden; transform: translateY(-8px);
  pointer-events: none;
  transition: opacity 0.24s var(--ease-out), transform 0.24s var(--ease-out), visibility 0s linear 0.24s;
}
/* the backdrop filter is attached only while open — a hidden element that
   still declares one keeps compositing the area behind it */
.panel.is-open {
  opacity: 1; visibility: visible; transform: translateY(0);
  pointer-events: auto;
  -webkit-backdrop-filter: blur(20px) saturate(1.4);
  backdrop-filter: blur(20px) saturate(1.4);
  transition: opacity 0.26s var(--ease-out), transform 0.26s var(--ease-out), visibility 0s;
}

.panel input[type="search"] {
  width: 100%;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 10px;
  padding: 0.65rem 0.85rem;
  color: #fff;
  font: inherit; font-size: 0.92rem;
}
.panel input[type="search"]::placeholder { color: rgba(255, 255, 255, 0.45); }
.panel__results { list-style: none; margin: 0.6rem 0 0; padding: 0; max-height: 46vh; overflow-y: auto; }
.panel__results li { margin: 0; }
.panel__results a {
  display: block; padding: 0.55rem 0.7rem; border-radius: 9px;
  color: rgba(255, 255, 255, 0.88); text-decoration: none; font-size: 0.9rem;
}
.panel__results a small { display: block; font-size: 0.74rem; color: rgba(255, 255, 255, 0.5); }
.panel__results a:hover, .panel__results a:focus-visible { background: rgba(255, 255, 255, 0.09); }
.panel__empty { padding: 0.7rem; font-size: 0.86rem; color: rgba(255, 255, 255, 0.55); }
.panel__note { font-size: 0.83rem; line-height: 1.55; color: rgba(255, 255, 255, 0.72); margin: 0.35rem 0 0.7rem; }
.panel h2 { font-size: 0.95rem; margin-bottom: 0.15rem; }
.panel a.panel__mail { color: #c6e39a; font-size: 0.87rem; }

/* ------------------------------------------------------------ sections -- */

.section { padding: 5.5rem 0; }
.section--wash { background: var(--paper-2); }
.section--mist { background: linear-gradient(180deg, var(--paper) 0%, var(--paper-2) 100%); }
.section--dark { background: var(--night); color: #fff; }
.section--dark a { color: #c6e39a; }

.section-head { max-width: 62ch; margin-bottom: 2.6rem; }
.section-head h2, .prose h2 { font-size: clamp(1.75rem, 3.1vw, 2.5rem); margin-bottom: 0.9rem; }
.eyebrow {
  font-size: 0.755rem; letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--green-deep); font-weight: 600; margin-bottom: 0.7rem;
}
.section--dark .eyebrow { color: #a7d16a; }
.lede { font-size: 1.1rem; color: #333c36; }
.section--dark .lede { color: rgba(255, 255, 255, 0.86); }

.split { display: grid; grid-template-columns: 1.5fr 1fr; gap: 3.5rem; align-items: start; }
.grid { display: grid; gap: 1.15rem; }
.grid--2 { grid-template-columns: repeat(2, 1fr); }
.grid--3 { grid-template-columns: repeat(3, 1fr); }

.card {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 1.6rem;
  transition: transform 0.3s var(--ease-out), box-shadow 0.3s var(--ease-out);
}
.card h3 { font-size: 1.08rem; margin-bottom: 0.5rem; }
.card p { font-size: 0.94rem; color: var(--muted); margin-bottom: 0; }
.card--lift:hover { transform: translateY(-3px); box-shadow: 0 14px 34px rgba(14, 20, 17, 0.09); }
.card-index {
  display: block; font-size: 0.76rem; font-weight: 700; letter-spacing: 0.1em;
  color: var(--green-deep); margin-bottom: 0.85rem;
}

.fact-panel { background: #fff; border: 1px solid var(--line); border-radius: 14px; padding: 1.6rem; }
.fact-list, .hero-facts { margin: 0; display: grid; gap: 1rem; }
.fact-list div, .hero-facts div { display: grid; gap: 0.15rem; }
.fact-list dt, .hero-facts dt {
  font-size: 0.73rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted); font-weight: 600;
}
.fact-list dd, .hero-facts dd { margin: 0; font-size: 0.97rem; font-weight: 500; }

.proof-strip { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.15rem; }
.proof-strip div { background: #fff; border: 1px solid var(--line); border-radius: 14px; padding: 1.4rem; }
.proof-strip strong { display: block; font-size: 1.85rem; font-weight: 600; letter-spacing: -0.03em; }
.proof-strip span { font-size: 0.85rem; color: var(--muted); }

.placeholder {
  display: inline-block;
  font-size: 0.8rem; font-weight: 500;
  color: var(--muted);
  background: repeating-linear-gradient(-45deg, #f4f6f2 0 8px, #ecefe8 8px 16px);
  border: 1px dashed #c3cbbd;
  border-radius: 8px;
  padding: 0.42rem 0.8rem;
}
.section--dark .placeholder,
.panel .placeholder {
  color: rgba(255, 255, 255, 0.82);
  background: repeating-linear-gradient(-45deg, rgba(255,255,255,0.05) 0 8px, rgba(255,255,255,0.02) 8px 16px);
  border-color: rgba(255, 255, 255, 0.25);
}

.button {
  display: inline-flex; align-items: center; gap: 0.5rem;
  padding: 0.8rem 1.5rem; border-radius: 999px;
  font-size: 0.92rem; font-weight: 500; text-decoration: none;
  transition: transform 0.25s var(--ease-out), background 0.25s var(--ease-out);
  border: none; cursor: pointer;
}
.button--deep { background: var(--green-deep); color: #fff; }
.button--deep:hover { background: var(--green-darkest); transform: translateY(-1px); }
.button--outline { border: 1px solid var(--line); color: var(--ink); background: #fff; }
.button--outline:hover { background: var(--paper-2); }
.button:disabled { opacity: 0.55; cursor: not-allowed; transform: none; }
.button-row { display: flex; flex-wrap: wrap; gap: 0.7rem; }

.quality-rule { display: grid; grid-template-columns: 1fr 1.2fr; gap: 3rem; align-items: start; }
.quality-quote { font-size: clamp(1.5rem, 2.7vw, 2.15rem); font-weight: 500; }
.quality-copy p { color: rgba(255, 255, 255, 0.82); }

.work-steps { display: grid; gap: 0.55rem; margin-top: 1.1rem; }
.work-steps div { display: flex; justify-content: space-between; gap: 1rem; font-size: 0.87rem; border-top: 1px solid var(--line); padding-top: 0.55rem; }
.work-steps span { color: var(--muted); }

.role-card .role-label {
  display: inline-block; font-size: 0.73rem; letter-spacing: 0.1em; text-transform: uppercase;
  font-weight: 700; color: var(--green-deep);
  background: rgba(120, 176, 56, 0.13); border-radius: 999px; padding: 0.3rem 0.75rem;
  margin-bottom: 0.9rem;
}

.team-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.15rem; }
.person { text-align: center; }
.person h3 { font-size: 0.97rem; margin-bottom: 0.25rem; }
.person p { font-size: 0.82rem; color: var(--muted); }
.person a { font-size: 0.8rem; word-break: break-word; }
.portrait-slot {
  aspect-ratio: 1; border-radius: 14px;
  background: repeating-linear-gradient(-45deg, #f4f6f2 0 8px, #ecefe8 8px 16px);
  border: 1px dashed #c3cbbd;
  display: flex; align-items: center; justify-content: center;
  margin-bottom: 0.85rem;
}
.portrait-slot span { font-size: 1.25rem; font-weight: 600; color: #9aa695; letter-spacing: 0.05em; }

.timeline { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.15rem; }
.timeline-step { background: #fff; border: 1px solid var(--line); border-radius: 14px; padding: 1.5rem; }
.timeline-step span { font-size: 0.73rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--green-deep); font-weight: 600; }
.timeline-step h3 { font-size: 1.02rem; margin: 0.6rem 0 0.45rem; }
.timeline-step p { font-size: 0.9rem; color: var(--muted); margin: 0; }

.service-list { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0 2.5rem; }
.service-list article { border-top: 1px solid var(--line); padding: 1.4rem 0; }
.service-list h3 { font-size: 1.03rem; margin-bottom: 0.4rem; }
.service-list p { font-size: 0.92rem; color: var(--muted); margin: 0; }

.form-layout { display: grid; grid-template-columns: 1fr 1fr; gap: 3.5rem; align-items: start; }
.intake-form { background: #fff; border: 1px solid var(--line); border-radius: 14px; padding: 1.8rem; display: grid; gap: 1rem; }
.field { display: grid; gap: 0.35rem; }
.field label { font-size: 0.83rem; font-weight: 500; }
.field input, .field textarea {
  font: inherit; font-size: 0.94rem;
  padding: 0.65rem 0.8rem;
  border: 1px solid var(--line); border-radius: 9px;
  background: var(--paper); color: var(--ink);
}
.field textarea { min-height: 110px; resize: vertical; }
.form-note { font-size: 0.82rem; color: var(--muted); margin: 0; }

.cta-panel { display: grid; grid-template-columns: 1.6fr auto; gap: 2.5rem; align-items: center; }
.testimonial blockquote { margin: 0 0 0.9rem; }
.testimonial footer { font-size: 0.82rem; color: var(--muted); }

/* --------------------------------------------------------------- guide -- */

.guide-body { max-width: 74ch; }
.guide-body h2 { font-size: clamp(1.5rem, 2.6vw, 2rem); margin: 2.8rem 0 0.9rem; }
.guide-body h3 { font-size: 1.1rem; margin: 1.8rem 0 0.6rem; }
.guide-body ul, .guide-body ol { padding-left: 1.15rem; }
.guide-body li { margin-bottom: 0.5rem; }
.guide-body code {
  font-family: ui-monospace, "Cascadia Code", Consolas, monospace;
  font-size: 0.87em; background: var(--paper-2); border: 1px solid var(--line);
  border-radius: 5px; padding: 0.1rem 0.35rem;
}
.ledger { width: 100%; border-collapse: collapse; margin: 1.2rem 0; font-size: 0.88rem; }
.ledger th, .ledger td { text-align: left; padding: 0.6rem 0.7rem; border-bottom: 1px solid var(--line); vertical-align: top; }
.ledger th { font-size: 0.74rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); }
.table-scroll { overflow-x: auto; }
.notice {
  border-left: 3px solid var(--green);
  background: var(--paper-2);
  padding: 1.1rem 1.3rem;
  border-radius: 0 10px 10px 0;
  margin: 1.4rem 0;
}
.notice p:last-child { margin-bottom: 0; }

/* -------------------------------------------------------------- footer -- */

.site-footer { background: var(--night); color: rgba(255, 255, 255, 0.72); padding: 4rem 0 2rem; }
.footer-grid { display: grid; grid-template-columns: 1.5fr 1fr 1fr; gap: 2.5rem; }
.footer-lockup { width: 200px; height: auto; margin-bottom: 1rem; }
.site-footer h2 { font-size: 0.78rem; letter-spacing: 0.12em; text-transform: uppercase; color: rgba(255, 255, 255, 0.55); margin-bottom: 0.9rem; }
.site-footer p { font-size: 0.9rem; }
.footer-links { display: grid; gap: 0.5rem; }
.footer-links a { color: rgba(255, 255, 255, 0.82); text-decoration: none; font-size: 0.9rem; }
.footer-links a:hover { color: #fff; text-decoration: underline; }
.footer-legal {
  display: flex; justify-content: space-between; flex-wrap: wrap; gap: 0.6rem;
  margin-top: 3rem; padding-top: 1.5rem;
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  font-size: 0.82rem; color: rgba(255, 255, 255, 0.66);
}
/* the AI-disclosure link lives here; the default link green is far too dark
   against the footer's near-black */
.footer-legal a { color: #a7d16a; }
.footer-legal a:hover { color: #c6e39a; }

/* ---------------------------------------------------------- responsive -- */

@media (max-width: 1023px) {
  .main-nav { display: none; }
  .nav-toggle { display: flex; }
  /* scoped to the header — the same two controls are repeated inside the
     mobile menu and must stay visible there */
  .site-header .nav-search,
  .site-header .nav-profile { display: none; }
  .nav-shell { justify-content: space-between; }
  .nav-tools { margin-left: auto; }
}
@media (min-width: 1024px) {
  .mobile-menu { display: none; }
}

/* Between the lg breakpoint and ~1180px the full nav plus a labelled search
   pill is wider than the viewport. Collapse the pill to its icon rather than
   letting the bar overflow. */
@media (min-width: 1024px) and (max-width: 1179px) {
  .nav-search {
    min-width: 0;
    width: 38px;
    padding: 0;
    justify-content: center;
  }
  .nav-search span { display: none; }
  .main-nav { gap: 0.15rem; }
  .main-nav a { padding: 0.5rem 0.62rem; font-size: 0.83rem; }
  .main-nav .nav-page { padding-left: 1.35rem; }
  .main-nav .nav-page::before { left: 0.6rem; }
  .nav-shell { gap: 1rem; }
}

@media (max-width: 900px) {
  .split, .form-layout, .quality-rule, .cta-panel { grid-template-columns: 1fr; gap: 2.2rem; }
  .grid--3, .timeline { grid-template-columns: repeat(2, 1fr); }
  .team-grid { grid-template-columns: repeat(3, 1fr); }
  .proof-strip { grid-template-columns: repeat(2, 1fr); }
  .service-list { grid-template-columns: 1fr; gap: 0; }
  .footer-grid { grid-template-columns: 1fr 1fr; }
  .cta-panel { justify-items: start; }
}

@media (max-width: 620px) {
  body { font-size: 16px; }
  .section { padding: 3.75rem 0; }
  .grid--2, .grid--3, .timeline, .proof-strip { grid-template-columns: 1fr; }
  .team-grid { grid-template-columns: repeat(2, 1fr); }
  .footer-grid { grid-template-columns: 1fr; gap: 2rem; }
  .hero__inner { padding-block: 2.2rem 2.6rem; }
  .hero h1 { max-width: 100%; }
  .city-switch { gap: 0.5rem; }
  .city-switch__now { order: 3; width: 100%; }
  .btn { flex: 1 1 auto; justify-content: center; }
  .footer-legal { flex-direction: column; }
}

/* Touch pointers get the 44px targets the rest of the repo standardised on;
   the 38px sizing is a mouse-only affordance. */
@media (pointer: coarse) {
  .nav-toggle, .nav-profile { width: 44px; height: 44px; }
  .nav-search { height: 44px; }
  .city-switch__btn { height: 44px; padding: 0 1.2rem; }
  .mobile-menu a { padding-block: 0.85rem; }
}

/* ------------------------------------------------------ reduced motion -- */
/* Every motion this variant adds is switched off here: the Ken Burns pan,
   the parallax (JS also stops writing transforms), the entrance stagger,
   and the crossfade. What remains is a static, correctly-cropped frame.   */

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

  .hero__img {
    animation: none !important;
    transform: none !important;
    object-position: center 45%;
  }
  .hero__media { transform: none !important; }
  .hero__img { transition: none !important; }

  [data-fade],
  .mobile-menu.is-open a,
  .mobile-menu a,
  .mobile-menu__tools,
  .mobile-menu.is-open .mobile-menu__tools {
    animation: none !important;
    opacity: 1;
    filter: none;
    transform: none;
  }

  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* Windows high-contrast / forced colours: drop the glass, keep the structure */
@media (forced-colors: active) {
  .liquid-glass::before { display: none; }
  .liquid-glass { border: 1px solid ButtonBorder; }
  .hero__blur { display: none; }
}
