/* v4 — dark hero, services grid, method rail, Zürich footer map */
.stg-banner{position:sticky; top:0; z-index:200; text-align:center; padding:7px 12px;
  font-family:var(--mono); font-size:10px; letter-spacing:.18em; text-transform:uppercase;
  background:var(--accent); color:var(--paper)}

/* ---------- 01 · HERO ----------
   The panel used to be dark in both themes, which is why several things around
   it were hard-coded light. It now follows the theme: white in light mode, the
   original graphite in dark mode. Everything inside the hero reads from these
   four tokens, so flipping them here carries the map, labels, rail and phone
   link with it — only the CTA, the rail hover wash and the nav overrides needed
   their own dark-mode branch.
   The light panel is a warm off-white, not #FFFFFF. Pure white is a neutral
   grey-white; set against the warm --paper (#F2EFE9) of the sections below it
   read as two different colour temperatures meeting at a hard edge. #FBF9F5 is
   the same hue family as --paper, just lighter, so the hero still separates as
   a panel but the seam reads as one tonal step instead of a clash. */
.hx{--hxbg:#FBF9F5; --hxink:#101214; --hxmut:#5C6169; --hxhair:rgba(16,18,20,.14);
  background:var(--hxbg); color:var(--hxink);
  padding:calc(var(--nav-h) + clamp(30px,5.5vh,68px)) 0 clamp(48px,8vh,104px);
  overflow:hidden; position:relative; width:100%; margin:0; box-sizing:border-box;
  min-height:100vh; min-height:100svh; display:flex; flex-direction:column; justify-content:center}
html[data-theme="dark"] .hx{--hxbg:#16181c; --hxink:#ECE9E2; --hxmut:#98A1AB;
  --hxhair:rgba(236,233,226,.16)}
/* Seamless at every size — no white edge, no gap on resize */
.hx + .sec{border-top:0; margin-top:0}
.hx-map{max-width:100%}
/* .wrap carries margin:0 auto. As a flex item of .hx that auto margin disables
   cross-axis stretch, so the wrap collapsed to its max-content width and got
   centred — meaning the hero's left edge drifted with the length of the copy
   and no longer lined up with the nav or the sections below. An explicit width
   restores the normal .wrap behaviour. */
/* flex:1 lets the wrap fill the hero panel so the rail can be pinned to the
   bottom instead of sitting just under the copy with dead space beneath it. */
.hx .wrap{display:flex; flex-direction:column; width:100%; flex:1}
.hx-kicker{display:flex; align-items:center; gap:14px; font-family:var(--mono);
  font-size:10.5px; letter-spacing:.26em; color:var(--hxmut); text-transform:uppercase}
.hx-kicker i{width:38px; height:1px; background:var(--hxmut); opacity:.6}
/* Hero: the map is a faded backdrop BEHIND the copy, pushed up and to the right. */
.hx .wrap{position:relative}
.hx-kicker, .hx-copy, .hx-rail{position:relative; z-index:2}

/* ---- Hero entrance ----------------------------------------------------------
   The generic .rv gave every element the same delay, distance and duration, so
   the headline and the lead arrived together and the full-width map slid the
   same 18px as the button. Here each element gets its own timing: larger things
   travel further and settle slower, and the four steps are spaced far enough
   apart to read as a sequence rather than one block appearing at once. */
.hx .rv{transition-duration:1.15s; transition-timing-function:var(--ease-reveal)}
.hx-h.rv{transform:translate3d(0,26px,0); transition-duration:1.35s; transition-delay:.10s}
.hx-lead.rv{transform:translate3d(0,20px,0); transition-duration:1.25s; transition-delay:.26s}
.hx-cta.rv{transform:translate3d(0,16px,0); transition-duration:1.15s; transition-delay:.42s}
.hx-rail.rv{transform:translate3d(0,14px,0); transition-duration:1.15s; transition-delay:.58s}
.hx-h.rv.vis,.hx-lead.rv.vis,.hx-cta.rv.vis,.hx-rail.rv.vis{transform:translate3d(0,0,0)}
/* The map is the backdrop: sliding something that wide draws the eye away from
   the words, so it only fades — slower and starting earlier, so it is already
   settling by the time the headline lands. Its transform is deliberately left
   alone: .hx-mapwrap uses transform for its own vertical positioning, so
   overriding it here would drop the map out of place. */
.hx-mapwrap.rv{transition-property:opacity; transition-duration:1.9s; transition-delay:.05s}
/* Auto margins top and bottom split the free space evenly, so the copy stays
   optically centred while the rail below it lands on the bottom edge. */
.hx-grid{display:block; margin-top:clamp(6px,1.2vh,14px); margin-block:auto}
.hx-kicker{margin:0}
.hx-copy{max-width:60ch}
.hx-h{font-family:var(--serif); font-weight:300; color:var(--hxink);
  font-size:clamp(40px,5.4vw,74px); line-height:1.06; margin:0; text-wrap:balance}
.hx-h em{font-style:italic; color:var(--hxmut)}
.hx-lead{color:var(--hxmut); font-size:clamp(15.5px,1.35vw,18px); line-height:1.6;
  max-width:52ch; margin:22px 0 0}
.hx-cta{display:flex; align-items:center; gap:26px; margin-top:30px; flex-wrap:wrap}
/* The hero panel is dark in BOTH themes, so this button must not use --accent or
   --ink: those flip per theme and used to leave the primary CTA at 1.93:1 in dark
   mode (pale #9FB3C6 on #F5F2EC) with a black --ink border smudged over #16181c.
   Fixed brand red on white is 4.77:1 and identical in both themes. */
/* Fixed values per theme rather than --accent/--ink: those flip independently of
   the panel and previously left the CTA at 1.93:1. Both branches are solid-on-
   solid so contrast is the panel's inverse either way. */
.hx-btn{background:#16181C; color:#FFFFFF; border:1px solid #16181C; padding:15px 32px;
  font-family:var(--sans); font-weight:500; font-size:11.5px;
  letter-spacing:.22em; text-transform:uppercase}
.hx-btn:hover{background:#33383F; border-color:#33383F; color:#FFFFFF}
html[data-theme="dark"] .hx-btn{background:#FFFFFF; color:#16181C; border-color:#FFFFFF}
html[data-theme="dark"] .hx-btn:hover{background:#E7E3DA; border-color:#E7E3DA; color:#16181C}
.hx-tel{font-family:var(--mono); font-size:12.5px; letter-spacing:.12em;
  color:var(--hxink); border-bottom:1px solid var(--hxhair); padding-bottom:3px}
/* Sits high behind the headline, not behind the CTA row. Brighter and unblurred
   than before; the mask carries the extra load of keeping the copy legible, so
   its solid stop is pushed later to compensate. */
/* top is 52% rather than 30% because the transform below is now actually
   respected — see the specificity note under it. */
.hx-mapwrap{position:absolute; top:52%; transform:translateY(-50%);
  right:calc(-1 * var(--gutter)); width:min(86%,1060px); margin:0; z-index:0;
  pointer-events:none;
  -webkit-mask-image:linear-gradient(100deg, transparent 0%, #000 52%);
  mask-image:linear-gradient(100deg, transparent 0%, #000 52%)}
/* The reveal system's .rv.vis{opacity:1} (styles.css:647) outranks a single-class
   selector, so the map's resting opacity has to be stated at equal-or-higher
   specificity or it silently reveals to full strength. */
/* Three tiers by specificity, because .hx-mapwrap alone (0,1,0) would otherwise
   override .rv{opacity:0} (also 0,1,0, but earlier in the cascade) and the map
   would sit at full strength from the first frame instead of fading in. */
.hx-mapwrap{opacity:.55}
.hx-mapwrap.rv{opacity:0}
.hx-mapwrap.rv.vis{opacity:.55}
/* Same trap for transform: .rv.vis{transform:translate3d(0,0,0)} (0,2,0) outranks
   .hx-mapwrap (0,1,0), so the map lost its translateY(-50%) the instant it
   revealed and dropped 183px down the panel. Restated at matching specificity. */
.hx-mapwrap.rv, .hx-mapwrap.rv.vis{transform:translateY(-50%)}
.hx-map{width:100%; height:auto; display:block}
/* Dark dots on white carry more visual weight than light dots on graphite, so
   the light panel needs a lower value to read at the same density. */
.hx-dots circle{fill:var(--hxink); opacity:.2; r:2.5}
html[data-theme="dark"] .hx-dots circle{opacity:.34}
@media (max-width:760px){
  /* Lifted off the bottom edge so the map sits behind the copy rather than
     collecting in the corner under it. */
  .hx-mapwrap{top:auto; bottom:clamp(70px,16vh,170px); width:130%; right:-15%}
  .hx-mapwrap, .hx-mapwrap.rv, .hx-mapwrap.rv.vis{transform:none}
  .hx-mapwrap, .hx-mapwrap.rv.vis{opacity:.3}
}
.hx-hq{fill:#D23B2C}
.hx-lbl{font-family:var(--mono); font-size:10px; letter-spacing:.14em; fill:var(--hxink)}
/* Zürich ⇄ Dubai link — the static fallback, shown only under reduced motion.
   js/hopline.js hides this and runs the capital-to-capital relay instead. */
.hx .wm-arc{stroke:#D23B2C; stroke-width:1.7; stroke-dasharray:3 7; opacity:.95;
  animation:arcflow 1.5s linear infinite}
@keyframes arcflow{to{stroke-dashoffset:-40}}
.hx .wm-ring{stroke:#D23B2C}
@media (prefers-reduced-motion: reduce){ .hx .wm-arc{animation:none} }
.wm-cap{fill:var(--hxink); opacity:.4; transition:fill .3s, opacity .3s, r .3s}

/* ---- Capital relay: each hop draws on, marches, then fades (js/hopline.js) ---- */
/* Phase 1 — draw-on. JS sets dasharray/dashoffset inline to the path length and
   then transitions the offset to 0, so the arc appears to travel to its target. */
.wm-hop{fill:none; stroke:#D23B2C; stroke-width:1.7; opacity:.95;
  transition:stroke-dashoffset .9s cubic-bezier(.33,.68,.35,1), opacity .62s ease-out}
/* Phase 2 — JS clears those inline styles and adds this class, handing the path
   over to the same marching-dash texture the original static arc used. */
.wm-hop--live{animation:arcflow 1.5s linear infinite; stroke-dasharray:3 7}
.wm-hop--out{opacity:0}
/* The capital currently being travelled to. */
.wm-cap.is-target{fill:#D23B2C; opacity:1; r:3.6}
/* Invisible, generously sized hover targets over each capital. */
.wm-hit{fill:transparent; pointer-events:auto; cursor:crosshair}
.wm-cap.is-hover{fill:#D23B2C; opacity:1; r:3.6}

/* Ping + label. Fixed red, not var(--accent): accent flips per theme and the
   hero panel is dark in both, so the ping used to change colour with the theme. */
/* Scaled via transform rather than animating r: transform is composited, r is
   not, so the old version repainted the whole map SVG on every frame. */
.wm-ping{fill:none; stroke:#D23B2C; stroke-width:1.6; r:3px;
  transform-box:fill-box; transform-origin:center;
  animation:wmping 1.8s ease-out forwards}
@keyframes wmping{from{transform:scale(1); opacity:.9} to{transform:scale(11); opacity:0}}
.wm-capflash{fill:#D23B2C; animation:wmfade 1.8s ease-out forwards}
.wm-capname{font-family:var(--mono); font-size:11px; letter-spacing:.16em;
  fill:var(--hxink); animation:wmfade 1.8s ease-out forwards}
/* Hover labels persist while the pointer is on the capital — no fade animation. */
.wm-capname--hover{animation:none; opacity:1}
@keyframes wmfade{0%{opacity:0} 18%{opacity:1} 100%{opacity:0}}
@media (prefers-reduced-motion: reduce){
  .wm-ping,.wm-capflash,.wm-capname{animation:none; opacity:0}
  .wm-capname--hover{opacity:1}
  .wm-hop{transition:none}
  .wm-hop--live{animation:none}
}

/* ---------- Hover states ----------
   House style: short (180–260ms), small (2–4px), no bounce, nothing scaling past
   1.02. Buttons, nav links, .nt, .office and .f-col a already had hovers in
   styles.css; these fill the gaps. */
.sx-rail li::before{transition:width .3s cubic-bezier(.4,0,.2,1)}
.sx-rail li:hover::before{width:100%}
.sx-rail li h3{transition:color .22s ease}

.case{transition:background .22s ease, border-color .22s ease}
.case:hover{background:var(--card); border-color:var(--accent)}
.case:hover .case__no{color:var(--accent)}
.case__no{transition:color .22s ease}

.hx-rail span{transition:color .2s ease, background .2s ease}
.hx-rail span:hover{color:var(--hxink); background:rgba(16,18,20,.045)}
html[data-theme="dark"] .hx-rail span:hover{background:rgba(236,233,226,.05)}

@media (prefers-reduced-motion: reduce){
  .fx-cell,.fx-cell::after,.fx-cell .fx-no,.sx-rail li::before,
  .case,.case__no,.hx-rail span,.wm-cap{transition:none}
  .fx-cell:hover::after,.sx-rail li:hover::before{width:0}
}
.hx-rail{display:grid; grid-template-columns:repeat(4,1fr); gap:0;
  margin-top:clamp(30px,5.5vh,58px)}
.hx-rail span{padding:16px 4px; font-family:var(--mono); font-size:10px;
  letter-spacing:.18em; text-transform:uppercase; color:var(--hxmut);
  border-right:1px solid var(--hxhair); text-align:center}
.hx-rail span:last-child{border-right:0}
@media (max-width:720px){ .hx-rail{grid-template-columns:1fr 1fr}
  .hx-rail span:nth-child(2){border-right:0} }
/* On a phone the four service labels repeat the section-02 grid immediately
   below the hero, so they are dropped and the copy takes the space they leave:
   margin-top:auto pushes the block down to sit above the panel's bottom padding
   instead of floating mid-panel. Must come after .hx-rail{display:grid} above —
   same specificity, so source order decides. */
@media (max-width:640px){
  /* Full-height hero on phones too (100svh fills the visible area under the
     browser chrome). The rail is hidden — it repeats section 02 — and the copy
     centres via .hx-grid{margin-block:auto} so the panel reads as intentional
     rather than leaving dead space above and below. */
  .hx-rail{display:none}
  .hx-grid{margin-block:auto}
}

/* ---------- Nav over the hero ----------
   Until scrolled, the transparent nav floats over the hero panel. When that
   panel is dark the nav has to read light regardless of theme, so these force
   white. They are scoped to dark mode now that the light-mode hero is white —
   left unscoped they would put a white logo and white links on white. Once
   .scrolled kicks in the nav gets its paper background and the normal
   per-theme rules take over in both modes. */
html[data-theme="dark"] .nav:not(.scrolled) .nav__brand .ic-d{display:none}
html[data-theme="dark"] .nav:not(.scrolled) .nav__brand .ic-l{display:block}
html[data-theme="dark"] .nav:not(.scrolled) .nav__links a,
html[data-theme="dark"] .nav:not(.scrolled) .nav__tools .nav__login,
html[data-theme="dark"] .nav:not(.scrolled) .lang__btn,
html[data-theme="dark"] .nav:not(.scrolled) .theme-t{color:#ECE9E2}
html[data-theme="dark"] .nav:not(.scrolled) .nav__links a::after{background:#ECE9E2}
html[data-theme="dark"] .nav:not(.scrolled) .burger i,
html[data-theme="dark"] .nav:not(.scrolled) .burger i::before,
html[data-theme="dark"] .nav:not(.scrolled) .burger i::after{background:#ECE9E2}
/* keep the menu overlay readable once open, regardless of nav state */
#mmenu.open .burger i{background:transparent}

/* Once the mobile menu is open the nav no longer floats over the dark hero — it
   sits on #mmenu's var(--paper) background. The always-light overrides above
   would leave a white logo and a white close cross on light paper, i.e.
   invisible. Hand the nav back to the normal per-theme rules. */
body.menu-open .nav:not(.scrolled) .nav__brand .ic-d{display:block}
body.menu-open .nav:not(.scrolled) .nav__brand .ic-l{display:none}
html[data-theme="dark"] body.menu-open .nav:not(.scrolled) .nav__brand .ic-d{display:none}
html[data-theme="dark"] body.menu-open .nav:not(.scrolled) .nav__brand .ic-l{display:block}
body.menu-open .nav:not(.scrolled) .lang__btn,
body.menu-open .nav:not(.scrolled) .theme-t{color:var(--ink-2)}
body.menu-open .nav:not(.scrolled) .burger i,
body.menu-open .nav:not(.scrolled) .burger i::before,
body.menu-open .nav:not(.scrolled) .burger i::after{background:var(--ink)}
/* ...but the middle bar still has to vanish so the cross reads as a cross. */
body.menu-open .nav:not(.scrolled) .burger i{background:transparent}

/* 02 · THE FIRM — the .fx-* statement/grid components moved to styles.css so
   pages that do not load this file (careers, strategy, …) can use them too. */

/* 03 · STRATEGY — the .sx-rail method rail moved to styles.css so careers can
   use it too; this file is only loaded by index.html. */

/* ---------- 04 · Case studies — swipe slider on mobile only ---------- */
.case-dots{display:none}
@media (max-width:640px){
  .case-slider{display:flex; gap:16px; overflow-x:auto; scroll-snap-type:x mandatory;
    -webkit-overflow-scrolling:touch; scrollbar-width:none;
    margin:0 -24px; padding:4px 24px 6px}
  .case-slider::-webkit-scrollbar{display:none}
  .case-slider .case{flex:0 0 88%; scroll-snap-align:center; margin:0;
    border:1px solid var(--hair); padding:22px 20px; display:block}
  .case-slider .case .case__no{margin-bottom:12px}
  .case-slider .case__side{margin-top:14px; padding-top:14px; border-top:1px solid var(--hair)}
  .case-dots{display:flex; gap:6px; justify-content:center; margin-top:16px}
  /* 24px tap target (WCAG 2.5.8) with the visible 7px dot rendered via ::before */
  .case-dots button{width:24px; height:24px; padding:0; border:0; background:transparent;
    display:grid; place-items:center; cursor:pointer; -webkit-tap-highlight-color:transparent}
  .case-dots button::before{content:""; width:7px; height:7px; border-radius:50%;
    background:var(--hair); transition:background .2s, transform .2s}
  .case-dots button[aria-current="true"]::before{background:var(--accent); transform:scale(1.25)}
  .case-swipehint{display:block; text-align:center; margin-top:10px;
    font-family:var(--mono); font-size:10px; letter-spacing:.18em;
    text-transform:uppercase; color:var(--muted)}
}
.case-swipehint{display:none}

/* ---------- Zürich footer map ---------- */
.fzmap{position:absolute; inset:0; width:100%; height:100%}
.fzmap .map-pin{animation:pinpulse 2.6s ease-in-out infinite}
.fz-water{opacity:.9}
.fz-main,.fz-d1,.fz-d2,.fz-d3{stroke-dasharray:900; stroke-dashoffset:900;
  animation:fzdraw 2.8s ease-out forwards}
.fz-d1{animation-delay:.2s}.fz-d2{animation-delay:.45s}.fz-d3{animation-delay:.7s}
.fz-main{animation-delay:.9s}
@keyframes fzdraw{to{stroke-dashoffset:0}}
@media (prefers-reduced-motion: reduce){
  .fz-main,.fz-d1,.fz-d2,.fz-d3{animation:none; stroke-dashoffset:0}
  .fzmap .map-pin{animation:none}
  .hx-h,.hx-lead{transition:none}
}
