/* Fonts are linked from the document head, not imported here: an @import
   inside the stylesheet chains a second request behind the first and
   blocks rendering twice over. */

/* ==========================================================================
   Veltracon Lifestyle - design tokens

   Gold is the group's constant: af8d48 (30 occurrences in the original site's
   own inline CSS), light gold e8ba5c, logo gold b69553. Ivory replaces pure
   white for depth.

   The ground is deep NAVY, aligned with the sister site veltracon-medical.com
   so the two read as one house. It replaced a warm near-black whose grade was
   turning the photography muddy brown rather than rich.

   Contrast, measured not guessed (and re-measured after the navy change, since
   the swap invalidated every earlier figure):
     ivory  F4F0E8 on onyx 070C16 ... 17.2:1   (was 17.3 on the old black)
     ivory  F4F0E8 on ink  0E1626 ... 15.9:1
     gold   AF8D48 on ink  0E1626 ...  5.8:1
     onyx   070C16 on gold AF8D48 ...  6.3:1   -> gold surfaces carry DARK text
     white  FFFFFF on gold AF8D48 ...  3.1:1   -> never white on gold
     muted  98A0AE on ink  0E1626 ...  6.9:1   -> cool grey; the old warm grey
                                                  went muddy against navy
   ========================================================================== */
:root{
  --onyx:#070C16;
  --ink:#0E1626;
  --ink-2:#131D30;
  --ink-3:#1A2740;
  /* Kept its name because it is referenced widely; it is no longer a warm
     black but the navy step that carries the alternating sections. */
  --warm:#16203A;

  --gold:#AF8D48;
  --gold-lt:#E8BA5C;
  --gold-logo:#B69553;
  --gold-deep:#8A6E38;
  /* Tonal steps either side of the brand gold. One gold on one black was the
     whole palette in the first pass and it read as flat. These are surface and
     ornament tones only; gold stays the single interactive accent. */
  --champagne:#E4CFA3;
  --bronze:#8A5E2B;
  --espresso:var(--onyx);

  --ivory:#F4F0E8;
  --ivory-2:#DCD6C9;
  --muted:#98A0AE;          /* 6.9:1 on ink — cool, to sit on navy */
  /* Reserved for non-text decoration only. It measures under 4.5:1 on these
     surfaces, so it must never carry a label or body copy. */
  --muted-2:#6C7688;

  /* Hairlines follow the ground, not the ivory: warm rules over navy read as
     a slightly dirty edge. */
  --line:rgba(214,226,240,.14);
  --line-2:rgba(214,226,240,.08);
  --gold-line:rgba(175,141,72,.42);

  --font-display:'Playfair Display','Playfair Fallback', Georgia, serif;
  --font-body:'Montserrat','Montserrat Fallback', system-ui, -apple-system, sans-serif;

  --wrap:1280px;
  --gutter:clamp(1.25rem, 4vw, 3.5rem);

  --ease:cubic-bezier(.22,.61,.36,1);
  --ease-out:cubic-bezier(.16,1,.3,1);

  --r:2px;                  /* one radius system: near-sharp, luxury print feel */
  --r-pill:999px;

  /* THE unifier. Every clip on this site was graded warm for the old black
     ground; under navy they would each pull in their own direction. One
     consistent navy wash over all media pulls them into a single house look —
     the same device the sister site uses to tame its stock footage, and the
     reason a technically simpler page reads as calmer than ours did. */
  --wash:rgba(16,30,58,.52);
  --wash-soft:rgba(16,30,58,.34);

  --shadow:0 40px 90px -50px rgba(0,0,0,.9);
  --nav-h:76px;
}

/* ------------------------------------------------------------------ reset */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
html{scroll-behavior:smooth}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}}

body{
  margin:0;
  background:var(--onyx);
  color:var(--ivory);
  font-family:var(--font-body);
  font-weight:300;
  font-size:clamp(.95rem,.9rem + .2vw,1.0625rem);
  line-height:1.75;
  -webkit-font-smoothing:antialiased;
  overflow-x:hidden;
}
img,video,svg{display:block;max-width:100%}
img,video{height:auto}
a{color:inherit;text-decoration:none}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
ul{margin:0;padding:0;list-style:none}

/* German and English compound words must never break the viewport */
h1,h2,h3,h4,h5{overflow-wrap:break-word;hyphens:auto}

:focus-visible{outline:2px solid var(--gold-lt);outline-offset:3px;border-radius:var(--r)}

/* Body copy: stop the last line falling to a single orphan word. Headings
   already balance above; `pretty` is the paragraph-shaped counterpart and
   only touches the final lines, so long text does not get re-flowed. */
p,li,dd,figcaption,blockquote{text-wrap:pretty}

/* The browser default selection is a saturated blue that has nothing to do
   with this palette and lands on near-black type. */
::selection{background:var(--gold);color:var(--onyx)}

/* Native control accents (the select's chevron and focus tint) follow the
   brand instead of the OS blue. */
:root{accent-color:var(--gold)}

/* Windows High Contrast forces its own palette and drops decorative
   backgrounds. Two things break silently there: gradient-clipped text becomes
   invisible because its fill is transparent by design, and buttons drawn only
   with a background colour lose their edges. Both are given back. */
@media (forced-colors:active){
  .foil{-webkit-text-fill-color:currentColor;color:currentColor;background:none}
  .btn,.motion-toggle,.totop{border:1px solid currentColor}
  .hero-scrim,.subhero-scrim,.band-scrim{display:none}
}

/* --------------------------------------------------------------- typography */
h1,h2,h3,h4,h5{
  font-family:var(--font-display);
  font-weight:400;
  line-height:1.12;
  margin:0;
  letter-spacing:-.012em;
  text-wrap:balance;
}
/* italic display type needs descender clearance for y g j p q */
h1 em,h2 em,h3 em,.pull em{
  font-style:italic;
  line-height:1.14;
  padding-bottom:.06em;
  color:var(--gold-lt);
}

/* Gold foil. A slow sheen travelling across the accent word, kept inside the
   gold family so the whole gradient still clears contrast on onyx: champagne
   12.8:1, deep gold 4.1:1, both fine for display sizes. */
.foil{
  background:linear-gradient(100deg,
    var(--gold-deep) 0%, var(--gold) 18%, var(--champagne) 34%,
    var(--gold-lt) 46%, var(--champagne) 62%, var(--gold) 80%, var(--gold-deep) 100%);
  background-size:260% 100%;
  -webkit-background-clip:text;background-clip:text;
  -webkit-text-fill-color:transparent;color:transparent;
  animation:foil 9s linear infinite;
}
@keyframes foil{to{background-position:260% 0}}
@media (prefers-reduced-motion:reduce){
  .foil{animation:none;background-position:34% 0}
}

.d1{font-size:clamp(2.4rem,1.5rem + 4.4vw,4.9rem)}
.d2{font-size:clamp(1.9rem,1.3rem + 2.7vw,3.35rem)}
.d3{font-size:clamp(1.45rem,1.15rem + 1.35vw,2.05rem)}
.d4{font-size:clamp(1.15rem,1.03rem + .5vw,1.4rem)}

p{margin:0 0 1.15em}
p:last-child{margin-bottom:0}
.lede{font-size:clamp(1.02rem,.96rem + .35vw,1.2rem);color:var(--ivory-2);line-height:1.78;max-width:62ch}
.body-muted{color:var(--muted)}
.measure{max-width:64ch}
.measure-sm{max-width:52ch}

/* the small caps label. Used sparingly: at most one per three sections. */
.eyebrow{
  font-family:var(--font-body);
  font-size:.6875rem;
  font-weight:500;
  letter-spacing:.34em;
  text-transform:uppercase;
  color:var(--gold);
  margin:0 0 1.4rem;
  display:block;
}

/* the original site's signature: a large italic serif pull quote */
.pull{
  font-family:var(--font-display);
  font-style:italic;
  font-weight:400;
  font-size:clamp(1.3rem,1.05rem + 1.15vw,2rem);
  line-height:1.4;
  color:var(--ivory);
  max-width:26ch;
  margin:0;
}
.pull--wide{max-width:34ch}

/* ------------------------------------------------------------------ layout */
.wrap{width:100%;max-width:var(--wrap);margin-inline:auto;padding-inline:var(--gutter)}
.wrap-narrow{max-width:920px}
.section{padding-block:clamp(3rem,2rem + 4.5vw,6rem);position:relative}
.section--tight{padding-block:clamp(2.5rem,1.75rem + 3.5vw,4.5rem)}
/* Flat sections no longer carry a fill of their own: the ambient layer is the
   ground, and a section that needs to step forward does it with a soft wash
   that fades at both ends. A hard-edged slab on a living background would be
   the old page again — a block dropped on top instead of a place in it. */
.section--ink{background:transparent}
.section--warm{background:linear-gradient(to bottom,transparent,rgba(22,32,58,.62) 16%,rgba(22,32,58,.62) 84%,transparent)}

/* A section with footage behind its content — the same window idea as the
   hero and the closing band, generalised. The wash is heavier here than on
   the hero (the content is small type and cards, not a headline), and both
   edges dissolve so the section reads as the page opening onto a view for a
   moment, not as a slab of video with text on it. */
.section--media{position:relative;overflow:hidden;isolation:isolate;
  -webkit-mask-image:linear-gradient(to bottom,transparent,#000 12%,#000 88%,transparent);
  mask-image:linear-gradient(to bottom,transparent,#000 12%,#000 88%,transparent)}
.section--media .sec-media{position:absolute;inset:0;z-index:0}
.section--media .sec-media img,.section--media .sec-media video{width:100%;height:100%;object-fit:cover}
.section--media .sec-media video{position:absolute;inset:0;opacity:0;transition:opacity 1.2s var(--ease)}
.section--media .sec-media video.playing{opacity:1}
.section--media .sec-scrim{position:absolute;inset:0;z-index:1;pointer-events:none;
  background:
    linear-gradient(to bottom,rgba(14,22,38,.55),rgba(14,22,38,.78) 55%,rgba(14,22,38,.86)),
    linear-gradient(var(--wash),var(--wash))}
.section--media > .wrap{position:relative;z-index:2}

.stack-s>*+*{margin-top:1rem}
.stack-m>*+*{margin-top:1.75rem}
.stack-l>*+*{margin-top:3rem}

.rule{height:1px;background:var(--line);border:0;margin:0}
.rule--gold{background:linear-gradient(90deg,var(--gold-line),transparent)}

/* a thin gold hairline used as a section opener, drawn in on reveal */
.hairline{display:block;width:64px;height:1px;background:var(--gold);transform-origin:left;margin-bottom:2rem}
[data-reveal] .hairline{transform:scaleX(0);transition:transform 1s var(--ease-out) .15s}
[data-reveal].in .hairline{transform:scaleX(1)}

/* --------------------------------------------------------------- buttons */
.btn{
  display:inline-flex;align-items:center;gap:.7rem;
  padding:.95rem 1.85rem;
  font-family:var(--font-body);
  font-size:.76rem;font-weight:500;letter-spacing:.15em;text-transform:uppercase;
  border-radius:var(--r);
  border:1px solid transparent;
  transition:background .45s var(--ease),color .45s var(--ease),border-color .45s var(--ease),transform .18s var(--ease);
  white-space:nowrap;            /* CTA labels never wrap */
  line-height:1;
}
.btn svg{width:15px;height:15px;flex:none;transition:transform .45s var(--ease)}
.btn:hover svg{transform:translateX(4px)}
.btn:active{transform:translateY(1px)}

/* gold surface carries DARK text: white on gold is only 3.1:1
   A vertical gradient plus an inset top highlight and bottom shade gives the
   button a struck-metal edge instead of a flat colour swatch. */
/* A struck-metal gradient with an inset top highlight and a bottom shade.
   The rendered brushed texture was tried here and taken back out, on looks
   rather than on numbers: at an 11px uppercase label the grain is simply not
   visible, so it added a request and a blend mode for nothing. It stays where
   it can be seen, on the call-to-action plate.
   Measured on the rendered pixels: onyx label on this gradient is 5.58:1. */
.btn-gold{
  background:linear-gradient(180deg,var(--gold-lt) -22%,var(--gold) 52%,var(--gold-deep) 148%);
  color:var(--onyx);font-weight:500;
  box-shadow:inset 0 1px 0 rgba(255,246,224,.5),inset 0 -1px 0 rgba(0,0,0,.2),
             0 14px 34px -20px rgba(175,141,72,.75);
}
.btn-gold:hover{
  background:linear-gradient(180deg,#F6D68A -22%,var(--gold-lt) 52%,var(--gold) 148%);
  box-shadow:inset 0 1px 0 rgba(255,250,236,.62),inset 0 -1px 0 rgba(0,0,0,.18),
             0 18px 44px -20px rgba(232,186,92,.8);
}

/* a hairline that fills from the left on hover rather than just tinting */
.btn-line{border-color:var(--gold-line);color:var(--gold-lt);position:relative;overflow:hidden;isolation:isolate}
.btn-line::before{
  content:"";position:absolute;inset:0;z-index:-1;
  background:linear-gradient(90deg,rgba(175,141,72,.22),rgba(175,141,72,.06));
  transform:scaleX(0);transform-origin:left;
  transition:transform .55s var(--ease-out);
}
.btn-line:hover{border-color:var(--gold)}
.btn-line:hover::before{transform:scaleX(1)}

.btn-ivory{border-color:rgba(244,240,232,.32);color:var(--ivory)}
.btn-ivory:hover{border-color:var(--ivory);background:rgba(244,240,232,.07)}

.btn-row{display:flex;flex-wrap:wrap;gap:.85rem}

/* text link with an underline that draws from the left */
.tlink{
  display:inline-flex;align-items:center;gap:.55rem;position:relative;
  font-size:.7rem;font-weight:500;letter-spacing:.22em;text-transform:uppercase;
  color:var(--gold-lt);padding-bottom:.4rem;
}
.tlink::after{content:"";position:absolute;left:0;bottom:0;height:1px;width:100%;background:var(--gold-line);transform:scaleX(1);transform-origin:right;transition:transform .5s var(--ease-out)}
.tlink:hover::after{transform:scaleX(0)}
.tlink svg{width:14px;height:14px;transition:transform .45s var(--ease)}
.tlink:hover svg{transform:translateX(5px)}

/* ------------------------------------------------------------------- nav */
.progress{position:fixed;top:0;left:0;height:2px;width:0;background:var(--gold);z-index:120;transition:width .12s linear}

.nav{
  position:fixed;top:0;left:0;right:0;z-index:100;
  height:var(--nav-h);display:flex;align-items:center;
}
/* Over the hero the bar is nothing but its contents. From the first scroll
   it becomes a floating capsule of glass — inset from the edges, a hairline of
   gold-line around it, a soft shadow beneath — the way a considered site
   carries its navigation today, rather than a full-width plank that darkens.
   The capsule lives inside the same 76px band, so nothing below it moves. */
.nav .wrap{
  display:flex;align-items:center;justify-content:space-between;gap:1.5rem;
  height:var(--nav-h);border:1px solid transparent;border-radius:18px;
  transition:height .5s var(--ease),background .5s var(--ease),border-color .5s var(--ease),
    box-shadow .5s var(--ease),padding .5s var(--ease),transform .5s var(--ease),backdrop-filter .5s var(--ease);
}
.nav.scrolled .wrap,.nav.is-solid .wrap{
  height:60px;transform:translateY(8px);
  padding-inline:clamp(1rem,.6rem + 1.2vw,1.6rem);
  background:rgba(10,17,32,.72);
  backdrop-filter:blur(20px) saturate(140%);-webkit-backdrop-filter:blur(20px) saturate(140%);
  border-color:rgba(175,141,72,.2);
  box-shadow:0 22px 50px -24px rgba(0,0,0,.75),inset 0 1px 0 rgba(244,240,232,.05);
}
.nav.menu-open .wrap{background:rgba(7,12,22,.96);border-color:var(--line-2);border-radius:18px 18px 0 0}
@media (max-width:1023px){.nav.scrolled .wrap,.nav.is-solid .wrap{transform:translateY(6px);height:58px}}
/* Phone: backdrop-filter re-blurs whatever scrolls under the capsule on every
   frame. The capsule goes nearly opaque instead and drops the blur. */
@media (max-width:820px){.nav.scrolled .wrap,.nav.is-solid .wrap{background:rgba(9,15,28,.94);backdrop-filter:none;-webkit-backdrop-filter:none}}
@media (forced-colors:active){.nav.scrolled .wrap{background:Canvas;backdrop-filter:none}}

.brand{display:flex;align-items:center;gap:.85rem;flex:none}
.brand-mark{width:auto;height:36px;color:var(--gold-logo);flex:none;transition:height .5s var(--ease)}
.nav.scrolled .brand-mark{height:30px}
.brand-word{display:flex;flex-direction:column;line-height:1}
.brand-word b{font-family:var(--font-body);font-weight:500;font-size:.82rem;letter-spacing:.3em;text-transform:uppercase;color:var(--ivory)}
.brand-word small{font-family:var(--font-body);font-weight:300;font-size:.65rem;letter-spacing:.28em;text-transform:uppercase;color:var(--gold);margin-top:.34rem}

.nav-links{display:none;align-items:center;gap:clamp(.7rem,1.1vw,1.35rem);position:relative}
/* One gold hairline glides between the links (after React Bits' FlowingMenu /
   PillNav): main.js measures the hovered link and moves this; at rest it sits
   under the current page. Without JS the per-link underline below still marks
   the current page. */
.nav-ind{position:absolute;bottom:.28rem;height:1px;background:var(--gold);left:0;width:0;opacity:0;pointer-events:none;
  transition:left .5s var(--ease-out),width .5s var(--ease-out),opacity .3s var(--ease)}
.nav-links.has-ind .nav-ind{opacity:1}
.nav-links.has-ind .nav-link::after{display:none}
.nav-link{
  position:relative;font-size:.74rem;font-weight:400;letter-spacing:.1em;text-transform:uppercase;
  color:var(--ivory-2);padding:.45rem 0;transition:color .35s var(--ease);white-space:nowrap;
}
.nav-link::after{content:"";position:absolute;left:0;right:100%;bottom:0;height:1px;background:var(--gold);transition:right .45s var(--ease-out)}
.nav-link:hover,.nav-link.active{color:var(--ivory)}
.nav-link:hover::after,.nav-link.active::after{right:0}

/* The original navigation carried 13 top-level links, which cannot sit on one
   line at any sane desktop width. The nine service verticals move into one
   dropdown: every original link stays reachable, the bar stays single-line. */
.has-dropdown{position:relative}
.has-dropdown>.nav-link{display:inline-flex;align-items:center;gap:.4rem}
.has-dropdown>.nav-link svg{width:11px;height:11px;transition:transform .35s var(--ease)}
.has-dropdown:hover>.nav-link svg,.has-dropdown:focus-within>.nav-link svg{transform:rotate(180deg)}
/* invisible bridge so the pointer can travel from the trigger to the panel */
.has-dropdown::after{content:"";position:absolute;left:0;right:0;top:100%;height:18px}
/* The services panel (after React Bits' CardNav): not a list, a small
   gallery — the nine services with a thumbnail, their number and name, in a
   glass panel that settles in with a short lift. Hover or focus opens it. */
.nav-dropdown{
  position:absolute;top:calc(100% + 14px);left:50%;
  transform:translateX(-50%) translateY(-8px) scale(.985);transform-origin:50% 0;
  width:min(760px,92vw);padding:1.1rem 1.1rem 1rem;
  background:rgba(10,17,32,.94);
  backdrop-filter:blur(24px) saturate(140%);-webkit-backdrop-filter:blur(24px) saturate(140%);
  border:1px solid rgba(175,141,72,.2);border-radius:16px;
  box-shadow:0 30px 70px -30px rgba(0,0,0,.8);
  opacity:0;visibility:hidden;pointer-events:none;
  transition:opacity .34s var(--ease),transform .34s var(--ease),visibility .34s;
}
.has-dropdown:hover .nav-dropdown,.has-dropdown:focus-within .nav-dropdown{
  opacity:1;visibility:visible;pointer-events:auto;transform:translateX(-50%) translateY(0) scale(1);
}
.nd-label{margin:0 0 .8rem .3rem;font-size:.7rem;letter-spacing:.22em;text-transform:uppercase;color:var(--gold)}
.nd-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:.35rem}
/* No running numbers here (or anywhere): they read as scaffolding. The name
   does the work — display serif, generous, ivory — with the picture beside it. */
.nd-item{
  display:grid;grid-template-columns:48px 1fr;column-gap:.9rem;align-items:center;
  padding:.5rem .65rem;border-radius:12px;color:var(--ivory);
  transition:background .3s var(--ease),color .3s var(--ease);
}
.nd-item img{width:48px;height:48px;object-fit:cover;border-radius:10px;
  filter:saturate(.62) brightness(.9);transition:filter .5s var(--ease),transform .5s var(--ease)}
.nd-name{font-family:var(--font-display);font-size:1.08rem;letter-spacing:.005em;line-height:1.25}
.nd-item:hover,.nd-item.active,.nd-item:focus-visible{background:rgba(175,141,72,.12);color:var(--gold-lt)}
.nd-item:hover img,.nd-item.active img{filter:saturate(1) brightness(1);transform:scale(1.04)}
.nd-all{
  display:inline-flex;align-items:center;gap:.5rem;margin:.75rem 0 0 .6rem;
  font-size:.7rem;letter-spacing:.14em;text-transform:uppercase;color:var(--gold);
}
.nd-all svg{width:14px;height:14px;transition:transform .35s var(--ease)}
.nd-all:hover svg{transform:translateX(3px)}
@media (max-width:1180px){.nd-grid{grid-template-columns:repeat(2,1fr)}.nav-dropdown{width:min(560px,92vw)}}

/* mobile: the same grouping becomes an accordion */
.m-sub{display:none;padding:.3rem 0 .8rem 1rem;border-bottom:1px solid var(--line-2)}
.m-sub.open{display:block}
.m-sub a{display:block;padding:.4rem 0;font-size:.95rem;color:var(--muted);font-family:var(--font-body)}
.m-sub a:hover{color:var(--gold-lt)}
.m-toggle{
  display:flex;align-items:center;justify-content:space-between;width:100%;
  font-family:var(--font-display);font-size:1.45rem;padding:.55rem 0;
  color:var(--ivory-2);border-bottom:1px solid var(--line-2);text-align:left;
}
.m-toggle svg{width:16px;height:16px;color:var(--gold);transition:transform .35s var(--ease)}
.m-toggle[aria-expanded="true"] svg{transform:rotate(180deg)}

.nav-cta{display:none;flex:none}
.nav-cta .btn{padding:.72rem 1.3rem;font-size:.7rem}
/* Below ~400px the widest label ("Download Brochure") wants 248px once the
   larger type and its tracking are paid for, and the card it sits in only
   offers 250 — enough to push the whole document 2px wide. The button gives
   back the padding and some of the tracking rather than the legibility. */
@media (max-width:400px){
  .btn{padding-inline:1.15rem;letter-spacing:.09em}
}

.m-burger{display:flex;flex-direction:column;justify-content:center;gap:5px;width:42px;height:42px;align-items:flex-end;flex:none}
.m-burger span,.m-burger::before,.m-burger::after{content:"";display:block;height:1px;background:var(--ivory);transition:transform .4s var(--ease),opacity .3s var(--ease),width .4s var(--ease)}
.m-burger::before{width:26px}
.m-burger span{width:18px}
.m-burger::after{width:26px}
.nav.menu-open .m-burger::before{transform:translateY(6px) rotate(45deg)}
.nav.menu-open .m-burger span{opacity:0;width:0}
.nav.menu-open .m-burger::after{transform:translateY(-6px) rotate(-45deg)}

/* 13 nav items is a lot. Desktop nav only appears when it genuinely fits. */
@media (min-width:1220px){
  .nav-links{display:flex}
  .m-burger{display:none}
}
@media (min-width:1400px){
  .nav-cta{display:block}
}

#mobileMenu{
  position:fixed;inset:var(--nav-h) 0 0;z-index:99;
  background:var(--onyx);          /* opaque: backdrop-filter on fixed overlays is unreliable */
  padding:2.5rem var(--gutter) 3rem;
  overflow-y:auto;
  transform:translateY(-101%);
  /* The panel starts at top:var(--nav-h), so translating by its own height
     still leaves that offset showing at the top of the screen. visibility
     is what actually takes it out of view; the transform only animates. */
  visibility:hidden;
  transition:transform .6s var(--ease-out),visibility .6s;
  display:flex;flex-direction:column;
}
#mobileMenu.open{transform:translateY(0);visibility:visible}
@media (min-width:1220px){#mobileMenu{display:none}}
.m-link{
  display:block;font-family:var(--font-display);font-size:1.45rem;
  padding:.55rem 0;color:var(--ivory-2);border-bottom:1px solid var(--line-2);
  transition:color .3s var(--ease),padding-left .3s var(--ease);
}
.m-link:hover,.m-link.active{color:var(--gold-lt);padding-left:.5rem}
.m-foot{margin-top:auto;padding-top:2rem;display:flex;flex-direction:column;gap:1rem}
.m-foot a[href^="tel"],.m-foot a[href^="mailto"]{font-size:.9rem;color:var(--muted);letter-spacing:.04em}

/* ------------------------------------------------- video with a still under it */
/* Every background video sits on top of its own poster as a real <img>. A
   paused video, a blocked autoplay or a slow connection then shows the
   photograph instead of an empty box. Learned the hard way: the montage used
   to open on black, so a paused hero rendered as a black rectangle. */
.hero-media .still,.subhero-media .still,.band-media .still{
  position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:0;
}
.hero-media video,.subhero-media video,.band-media video{
  position:absolute;inset:0;z-index:1;opacity:0;
  transition:opacity 1s var(--ease);
}
.hero-media video.playing,.subhero-media video.playing,.band-media video.playing{opacity:1}

/* ------------------------------------------------------------------ hero */
.hero{position:relative;min-height:100dvh;display:flex;align-items:flex-end;overflow:hidden}
.hero-media{position:absolute;inset:0;z-index:0}
/* The hero does not stop at a line; the footage and its scrim thin out over
   the last eighth of the section and the ambient ground takes over beneath
   the buttons. Same idea at the top of the closing band and both edges of the
   interlude — the media sections are windows in the page, not tiles on it. */
.hero-media,.hero-scrim,.subhero-media,.subhero-scrim{
  -webkit-mask-image:linear-gradient(to bottom,#000 78%,transparent 100%);
  mask-image:linear-gradient(to bottom,#000 78%,transparent 100%);
}
.hero-media img,.hero-media video{width:100%;height:100%;object-fit:cover}
/* Four layers, not one. The vertical gradient carries legibility, two pools
   anchor the text block, and the warm pass puts a low gold light into the
   frame so the hero reads as lit rather than merely darkened.

   Every layer lives here, on an element that exactly covers the hero, and
   that is the point: this scrim has no visible edge for a gradient to step
   at. The copy's own pool of shade used to sit on `.hero-content::before`,
   which is inset from the hero — its topmost stop began at 42% opacity, so
   the element's top edge drew a hard horizontal line straight across the
   footage at y=189. Anchored to the hero instead, the same shade runs out
   smoothly and there is nothing to see. */
.hero-scrim{
  position:absolute;inset:0;z-index:1;
  background:
    radial-gradient(90% 70% at 12% 88%,rgba(175,141,72,.16),transparent 62%),
    linear-gradient(var(--wash),var(--wash)),
    linear-gradient(to top,rgba(7,12,22,.96) 0%,rgba(7,12,22,.62) 34%,rgba(7,12,22,.26) 62%,rgba(7,12,22,.74) 100%),
    radial-gradient(84% 80% at 24% 64%,rgba(7,12,22,.82) 0%,rgba(7,12,22,.54) 38%,transparent 72%),
    radial-gradient(120% 80% at 20% 90%,rgba(7,12,22,.72),transparent 70%);
}

/* the house line, set as the hero's only small text element */
/* Ivory, not gold. Gold at this size measured 3.3:1 over the hero footage,
   and because the hero is a montage the background changes six times, so the
   line has to hold on the brightest shot rather than on a lucky frame. The
   gold accent lives in the rule beside it instead. */
.hero-tag{
  display:flex;align-items:center;gap:1rem;
  font-family:var(--font-body);font-size:.74rem;font-weight:500;
  letter-spacing:.26em;text-transform:uppercase;color:var(--ivory);
  text-shadow:0 1px 12px rgba(7,12,22,.85);
  margin:0 0 1.9rem;
}
.hero-tag span{
  display:block;width:clamp(34px,5vw,72px);height:1px;flex:none;
  background:linear-gradient(90deg,transparent,var(--gold));
  transform:scaleX(0);transform-origin:left;
  animation:tagline-rule 1.2s var(--ease-out) .35s forwards;
}
@keyframes tagline-rule{to{transform:scaleX(1)}}
@media (prefers-reduced-motion:reduce){.hero-tag span{animation:none;transform:scaleX(1)}}
.hero-content{position:relative;z-index:2;width:100%;padding-bottom:clamp(3.5rem,2rem + 6vw,7rem);padding-top:calc(var(--nav-h) + 2rem)}
/* The pool of shade that used to live here now sits in `.hero-scrim`, where
   it cannot draw an edge — see the note there. */
/* Two lines at desktop. The headline is 13 words, so the scale has to be
   planned around the copy rather than set to the largest step available. */
.hero h1{max-width:26ch;font-size:clamp(2.1rem,1.35rem + 3.5vw,4.05rem)}
.hero .lede{margin-top:1.85rem;max-width:46ch}
.hero .btn-row{margin-top:2.6rem}

/* subpage hero: shorter, same construction */
.subhero{position:relative;min-height:min(62dvh,560px);display:flex;align-items:flex-end;overflow:hidden}
.subhero-media{position:absolute;inset:0;z-index:0}
.subhero-media img,.subhero-media video{width:100%;height:100%;object-fit:cover}
/* Two scrims, not one. The vertical gradient alone was tuned on dark clips and
   left the headline sitting on bright plaster once the library and the clinic
   corridor arrived. The horizontal pass darkens only the side the text is on,
   so the picture stays legible on the other. */
.subhero-scrim{
  position:absolute;inset:0;z-index:1;
  background:
    linear-gradient(to top,rgba(7,12,22,.96),rgba(7,12,22,.5) 58%,rgba(7,12,22,.74)),
    linear-gradient(90deg,rgba(7,12,22,.78) 0%,rgba(7,12,22,.34) 46%,rgba(7,12,22,0) 78%),
    linear-gradient(var(--wash),var(--wash));
}
.subhero-content{position:relative;z-index:2;width:100%;padding-block:clamp(2.5rem,2rem + 4vw,4.5rem);padding-top:calc(var(--nav-h) + 2.5rem)}
/* subpage h1 gets its own smaller step: inheriting the homepage scale makes
   long titles run to four or five lines */
.subhero h1{font-size:clamp(2rem,1.4rem + 2.9vw,3.5rem);max-width:17ch}
/* the German pages carry a standfirst under the subhero heading; without the
   gap the two run together as one block of type */
.subhero .lede{margin-top:1.3rem;max-width:52ch}
.subhero .pull{margin-top:1.6rem}

.crumb{display:flex;align-items:center;gap:.6rem;font-size:.7rem;letter-spacing:.15em;text-transform:uppercase;color:var(--muted);margin-bottom:1.5rem}
.crumb a:hover{color:var(--gold-lt)}
.crumb span{color:var(--gold)}

/* ------------------------------------------------------- split (about etc) */
.split{display:grid;gap:clamp(2.5rem,2rem + 4vw,5.5rem);align-items:center}
@media (min-width:900px){
  .split{grid-template-columns:1.05fr .95fr}
  .split--wide-left{grid-template-columns:1.25fr .75fr}
  .split--flip>*:first-child{order:2}
}
.frame{position:relative;overflow:hidden;border-radius:var(--r);background:var(--ink-2)}
/* a frame may carry a clip over its still — same reveal rule as every clip */
.frame video{position:absolute;inset:0;opacity:0;transition:opacity 1s var(--ease);z-index:0;filter:saturate(.72) contrast(1.03)}
.frame video.playing{opacity:1}
body.motion-off .frame video{opacity:0}

/* ------------------------------------------------- one treatment for media
   Every framed image on the page gets the same wash as the video sections.
   Without it the imported colour photography (a red car, a stack of gold bars)
   jumps out of the navy ground and each card pulls in its own direction —
   the single thing that most made the page read as assembled rather than
   designed. Pulled back, not killed: the picture returns to full colour on
   hover, so the restraint reads as deliberate. */
.frame::after,.post__media::after,.g-item::before,.chapter__pic::after{
  content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background:var(--wash-soft);
  transition:opacity .6s var(--ease);
}
.frame img,.post__media img,.g-item img,.chapter__pic img{
  filter:saturate(.62) contrast(1.03);
  transition:filter .6s var(--ease),transform 1.1s var(--ease),scale 1.9s var(--ease-out),clip-path 1.25s var(--ease-out);
}
.post:hover .post__media::after,.g-item:hover::before,a:hover > .frame::after{opacity:0}
/* (whole-image hover saturation retired — the chroma spotlight below is the hover) */
.frame img,.frame video{width:100%;height:100%;object-fit:cover;transition:transform .9s var(--ease)}
.frame:hover img{transform:scale(1.04)}
.frame--tall{aspect-ratio:4/5}
.frame--wide{aspect-ratio:16/10}
.frame--square{aspect-ratio:1}
/* a thin gold inner keyline, the original site's button language applied to images */
.frame::after{content:"";position:absolute;inset:0;border:1px solid var(--line);pointer-events:none;border-radius:inherit}

/* ------------------------------------------------------- editorial stack */
/* A second, smaller plate overlapping the first. One lone photo in the about
   section read as an afterthought; two overlapping ones read as art direction.
   The overlap only exists where there is room for it. */
.photo-stack{position:relative}
.photo-stack .frame:first-child{width:100%}
.photo-stack .frame + .frame{margin-top:1rem}
@media (min-width:900px){
  .photo-stack{padding-bottom:5.5rem;padding-right:3rem}
  .photo-stack .frame + .frame{
    position:absolute;right:0;bottom:0;width:52%;margin-top:0;
    box-shadow:var(--shadow);z-index:2;
  }
  .photo-stack .frame + .frame::after{border-color:var(--gold-line)}
}

/* ------------------------------------------------------------ stats strip */
.stats{display:grid;grid-template-columns:repeat(2,1fr);gap:1px;background:var(--line-2)}
@media (min-width:860px){.stats{grid-template-columns:repeat(4,1fr)}}
.stat{background:rgba(7,12,22,.42);padding:clamp(1.75rem,1.2rem + 2vw,2.75rem) clamp(1rem,.6rem + 1.5vw,2rem)}
.stat b{display:block;font-family:var(--font-display);font-size:clamp(2rem,1.5rem + 2vw,3.1rem);font-weight:400;color:var(--gold-lt);line-height:1}
.stat span{display:block;margin-top:.75rem;font-size:.72rem;letter-spacing:.15em;text-transform:uppercase;color:var(--muted)}

/* ------------------------------------------------- the journey (chapters) */
/* Pinned media column on the left, chapters scrolling on the right.
   One pinned section rather than nine alternating panels. */
.journey{position:relative;background:transparent}
.journey-grid{display:grid;gap:clamp(2rem,1.5rem + 3vw,4rem)}
@media (min-width:1000px){.journey-grid{grid-template-columns:1.04fr .96fr}}

/* The sticky element must sit INSIDE a full-height grid item. Putting
   position:sticky on the grid item itself only lets it travel within its own
   content box, so it unsticks again after the first chapter. */
.journey-media-col{display:none}
@media (min-width:1000px){
  .journey-media-col{display:block;height:100%}
  /* A square plate rather than the source files' 16:10. The chapters are tall,
     and a letterbox left half a column of empty space under every one of them.
     object-fit crops the sides, which these compositions tolerate. */
  .journey-media{
    position:sticky;top:calc(var(--nav-h) + clamp(1.5rem,6vh,4.5rem));
    aspect-ratio:1/1;border-radius:var(--r);overflow:hidden;background:var(--ink-2);
  }
  .journey-media::after{content:"";position:absolute;inset:0;border:1px solid var(--line);pointer-events:none;z-index:4}
}
.jm-layer{position:absolute;inset:0;opacity:0;transition:opacity .85s var(--ease),scale 1.6s var(--ease)}
.jm-layer img,.jm-layer video{width:100%;height:100%;object-fit:cover}
.jm-layer.on{opacity:1}
/* One wash, like every other picture on the page. This used to be nine
   different per-vertical tints in soft-light — atmosphere, but nine plates
   each pulling toward a different hue is the opposite of a house look. */
.jm-layer::after{
  content:"";position:absolute;inset:0;z-index:2;pointer-events:none;
  background:var(--wash-soft);
}
.jm-index{
  position:absolute;left:0;right:0;bottom:0;z-index:3;
  display:flex;align-items:baseline;justify-content:space-between;gap:1rem;
  padding:1.4rem 1.6rem;
  background:linear-gradient(to top,rgba(7,12,22,.9),transparent);
  font-size:.7rem;letter-spacing:.18em;text-transform:uppercase;color:var(--gold-lt);
}
.jm-index b{font-family:var(--font-display);font-size:1.5rem;font-weight:400;letter-spacing:0;color:var(--ivory)}

.chapter{
  position:relative;
  padding-block:clamp(2.25rem,1.75rem + 2.6vw,3.6rem);
  border-top:1px solid var(--line-2);
  transition:opacity .6s var(--ease);
}
.chapter:first-child{border-top:0;padding-top:0}
/* the chapter's own colour, picked up on the dividing rule */
.chapter::before{
  content:"";position:absolute;top:-1px;left:0;width:64px;height:1px;
  background:var(--gold);
  transform:scaleX(0);transform-origin:left;
  transition:transform .9s var(--ease-out) .1s;
}
.chapter.in::before{transform:scaleX(1)}
.chapter:first-child::before{display:none}
/* on mobile the inline picture replaces the pinned plate, so it carries the
   same light */
/* This chapter picture used to carry its own gold soft-light wash, and being
   declared after the shared media rule it *replaced* that rule's background —
   so the nine largest images on the page were the only ones not in the house
   treatment. Removed: the shared `.chapter__pic::after` above now applies,
   and the journey reads as part of the page instead of a warm guest inside it.

   Removed with it: the very large hollow numeral that sat behind each chapter.
   It was a magazine device, but the number is already stated twice in the
   chapter head and once in the picture corner. A third, decorative repetition
   is ornament, and ornament is what makes a page look assembled rather than
   designed. */
.chapter > *{position:relative;z-index:1}

.chapter__head{display:flex;align-items:baseline;gap:1rem;margin-bottom:1.4rem}
.chapter__head h3{font-size:clamp(1.55rem,1.2rem + 1.6vw,2.35rem)}
.chapter__no{font-family:var(--font-body);font-size:.72rem;font-weight:500;letter-spacing:.22em;color:var(--gold);flex:none}
.chapter__q{margin-bottom:1.5rem}
.chapter__pic{display:block;margin-bottom:1.5rem;border-radius:var(--r);overflow:hidden;aspect-ratio:16/9;position:relative}
.chapter__pic img,.chapter__pic video{width:100%;height:100%;object-fit:cover}
@media (min-width:1000px){.chapter__pic{display:none}}
.chapter__list{display:grid;gap:.55rem;margin-bottom:1.6rem}
.chapter__list li{position:relative;padding-left:1.5rem;font-size:.92rem;color:var(--muted);line-height:1.6}
.chapter__list li::before{content:"";position:absolute;left:0;top:.62em;width:8px;height:1px;background:var(--gold)}

/* ------------------------------------------------- service page components */
/* The original prints these as a plain bulleted list. At up to nine items a
   default list with a rule under every row is the laziest possible layout, so
   each entry gets its own row with a gold index rule and real breathing room. */
.svc-list{display:grid;gap:0;counter-reset:svc}
.svc-list li{
  counter-increment:svc;
  position:relative;padding:1.15rem 0 1.15rem 3.25rem;
  border-top:1px solid var(--line-2);
  color:var(--ivory-2);font-size:1rem;line-height:1.65;
}
.svc-list li:first-child{border-top:0}
.svc-list li::before{
  content:counter(svc,decimal-leading-zero);
  position:absolute;left:0;top:1.35rem;
  font-family:var(--font-body);font-size:.7rem;font-weight:500;letter-spacing:.12em;color:var(--gold);
}

/* the row lights up and steps in slightly, so a long list still feels handled
   rather than dumped */
.svc-list li{transition:color .4s var(--ease),padding-left .5s var(--ease-out)}
.svc-list li::before{transition:color .4s var(--ease)}
.svc-list li:hover{color:var(--ivory);padding-left:3.6rem}
.svc-list li:hover::before{color:var(--gold-lt)}

.chips{display:flex;flex-wrap:wrap;gap:.6rem}
.chips li{
  font-family:var(--font-display);font-size:1rem;
  color:var(--ivory-2);border:1px solid var(--line);
  padding:.55rem 1.05rem;border-radius:var(--r);
  transition:border-color .4s var(--ease),color .4s var(--ease);
}
.chips li:hover{border-color:var(--gold-line);color:var(--gold-lt)}

.notes{display:grid;gap:1px;background:var(--line-2);margin-top:clamp(2rem,1.6rem + 2vw,3rem)}
@media (min-width:900px){.notes{grid-template-columns:repeat(3,1fr)}}
.note{background:rgba(22,32,58,.6);padding:clamp(1.6rem,1.3rem + 1.4vw,2.4rem);display:flex;flex-direction:column;gap:.85rem}
.note p{color:var(--muted);font-size:.93rem;line-height:1.7}

.rel-grid{display:grid;gap:1.5rem;margin-top:2rem}
@media (min-width:760px){.rel-grid{grid-template-columns:repeat(3,1fr)}}
.rel-card{display:flex;flex-direction:column;gap:1rem}
.rel-card__img{display:block;position:relative;aspect-ratio:16/10;overflow:hidden;border-radius:var(--r);background:var(--ink-2)}
.rel-card__img img{width:100%;height:100%;object-fit:cover;transition:transform .9s var(--ease)}
.rel-card:hover .rel-card__img img{transform:scale(1.05)}
.rel-card__body{display:flex;flex-direction:column;gap:.35rem}
.rel-card__body b{font-family:var(--font-display);font-weight:400;font-size:1.25rem;color:var(--ivory)}
.rel-card__body em{font-style:normal;font-size:.86rem;color:var(--muted)}

/* --------------------------------------------------------------- marquee */
/* One marquee on the page. It carries the maisons named on the original site. */
.marquee{border-block:1px solid var(--line-2);padding-block:1.6rem;position:relative}
.marquee__strip{overflow:hidden;position:relative}
.marquee__strip::before,.marquee__strip::after{content:"";position:absolute;top:0;bottom:0;width:14vw;z-index:2;pointer-events:none}
.marquee__strip{-webkit-mask-image:linear-gradient(90deg,transparent,#000 12%,#000 88%,transparent);mask-image:linear-gradient(90deg,transparent,#000 12%,#000 88%,transparent)}
.marquee__strip::before,.marquee__strip::after{display:none}
.marquee-track{display:flex;width:max-content;gap:3.5rem;animation:slide 54s linear infinite;padding-left:3.5rem}
/* no pause on hover — Dennis wants the marks to keep moving under the pointer */
/* The houses' own wordmarks, in one colour. Ten come as SVG (public-domain
   typographic marks from Wikimedia Commons, normalised to their content box
   in pipeline/data/house_logo_ratios.json) and are drawn as CSS masks over the
   page's ivory — so Rolex green, Ferrari black and Porsche's own tone all
   arrive as the same quiet ivory at a cap height tuned per mark, not per box.
   Three houses have no usable vector on Commons (Patek Philippe, Hermès,
   CVSTOS) and are set as type in the same tone. Trademark use of the marks
   is the client's to clear before go-live — see README "Offene Punkte". */
.marquee-track .house{
  display:inline-flex;align-items:center;gap:3.5rem;white-space:nowrap;opacity:.78;
  color:var(--ivory-2);
}
.marquee-track .house--type{
  font-family:var(--font-body);font-weight:400;
  font-size:clamp(.82rem,.74rem + .34vw,1.02rem);letter-spacing:.12em;text-transform:uppercase;
}
.marquee-track .mark{
  display:block;height:calc(var(--h) * var(--mh,1));width:calc(var(--h) * var(--mh,1) * var(--r));
  background:var(--ivory-2);
  -webkit-mask:var(--m) center/contain no-repeat;mask:var(--m) center/contain no-repeat;
}
@media (max-width:700px){.marquee-track .house{--mh:.82;gap:2.4rem}}
.marquee-track .house::after{
  content:"";width:4px;height:4px;flex:none;border-radius:50%;
  background:var(--gold);opacity:.55;
}
/* A quiet line of explanation. Without it a scrolling row of luxury marques
   reads as a claim of partnership; with it, it says what it is — the houses
   these requests are placed with. */
.marquee__label{
  text-align:center;margin-bottom:1.15rem;
  font-size:.68rem;letter-spacing:.24em;text-transform:uppercase;color:var(--muted);
}
@keyframes slide{from{transform:translateX(0)}to{transform:translateX(calc(-50% - 1.75rem))}}
@media (prefers-reduced-motion:reduce){.marquee-track{animation:none}}

/* --------------------------------------------------------------- ornament */
/* A centred crown between two gold hairlines, used to close a section. The
   traditional printed-page device: it tells the eye a chapter has ended,
   which endless flat spacing never does. */
.seal{display:flex;align-items:center;gap:clamp(1rem,3vw,2rem);margin-block:clamp(3rem,2rem + 3vw,5rem)}
.seal::before,.seal::after{content:"";flex:1;height:1px}
.seal::before{background:linear-gradient(90deg,transparent,var(--gold-line))}
.seal::after{background:linear-gradient(270deg,transparent,var(--gold-line))}
.seal svg{width:auto;height:30px;color:var(--gold);flex:none;opacity:.9}

/* Hairline corner marks. Two 1px angles at opposite corners of a plate, the
   way a print register mark sits on a proof sheet. */
.frame--marked::before{
  content:"";position:absolute;left:-1px;top:-1px;width:26px;height:26px;z-index:3;
  border-left:1px solid var(--gold);border-top:1px solid var(--gold);
  opacity:.75;pointer-events:none;
}
.frame--marked{position:relative}
.frame--marked > .mark-br{
  position:absolute;right:-1px;bottom:-1px;width:26px;height:26px;z-index:3;
  border-right:1px solid var(--gold);border-bottom:1px solid var(--gold);
  opacity:.75;pointer-events:none;
}

/* --------------------------------------------------------- lifted section
   Was an ivory island: one light section dropped into an otherwise dark page,
   re-scoping every token to a light equivalent. That meant a single section
   played by different rules than the other ten — the loudest break in the
   page's rhythm, and the kind of thing that reads as unresolved rather than
   considered.

   It now does the same job (give the scroll a breath, stop the page reading as
   one flat field) by the same means as everything else: a step up the navy
   scale. No token re-scoping, no light mode, no paper texture. */
.island{
  background:linear-gradient(to bottom,transparent,rgba(26,39,64,.6) 14%,rgba(26,39,64,.6) 86%,transparent);
  position:relative;
}
.island .wrap{position:relative;z-index:1}

/* ------------------------------------------------------ video interlude */
/* A full-bleed moment between two dense sections. Carries one line of copy,
   nothing else, so it reads as a breath rather than another content block. */
/* The media is FIXED, not absolute, so the band behaves as a window onto a
   layer that sits behind the page rather than as a picture scrolling with it.
   clip-path on the parent is what makes position:fixed resolve against this
   box instead of the viewport, so no JS is involved. */
.band{
  position:relative;min-height:min(88dvh,760px);display:flex;align-items:center;
  overflow:hidden;clip-path:inset(0);
  -webkit-mask-image:linear-gradient(to bottom,transparent,#000 14%,#000 86%,transparent);
  mask-image:linear-gradient(to bottom,transparent,#000 14%,#000 86%,transparent);
}
.band-media{position:fixed;inset:0;height:100dvh;z-index:0}
/* Phone: the fixed "window" costs a repaint of the masked, clipped video on
   every scroll frame. There the clip simply scrolls with its section. */
@media (max-width:900px){.band{clip-path:none}.band-media{position:absolute;height:100%}}
.band-media img,.band-media video{width:100%;height:100%;object-fit:cover}
.band-scrim{position:absolute;inset:0;z-index:1;background:
  linear-gradient(90deg,rgba(7,12,22,.94) 0%,rgba(7,12,22,.72) 45%,rgba(7,12,22,.45) 100%),
  linear-gradient(var(--wash),var(--wash))}
.band-content{position:relative;z-index:2;width:100%}
.band .pull{font-size:clamp(1.4rem,1.1rem + 1.7vw,2.5rem)}

/* ------------------------------------------------------------- services
   Nine services as an accordion gallery: nine upright panels in one row,
   one open, eight folded beside it. The open panel shows the picture in
   colour with the chapter's quote, its three lines and the link; a folded
   panel is a narrow strip carrying its number and its name set on end.

   This replaces the pinned nine-chapter journey — 5,438 px of scroll, 38 %
   of the page — with one screen. Nothing was lost: every quote, list and
   link is here, and each service still has its own page behind "Read more".

   Reference: React Bits' AccordionGallery (GSAP). Ported to plain CSS: the
   width change is a `flex-grow` transition, which the browser animates
   natively; the tilt and grayscale of the original are dropped for the
   house treatment (desaturated + washed when folded, colour when open). */
.services__head{
  display:flex;flex-wrap:wrap;align-items:flex-end;justify-content:space-between;
  gap:1.2rem 3rem;margin-bottom:clamp(1.8rem,1.4rem + 1.6vw,2.6rem);
}
.services__lede{max-width:34ch;margin:0 0 .35rem}

.acc{
  --acc-h:clamp(520px,66vh,680px);
  --acc-gap:6px;
  --acc-open:7;                /* flex-grow of the open panel; 8 folded ones share the rest */
  display:flex;gap:var(--acc-gap);height:var(--acc-h);
}
.acc__panel{
  position:relative;flex:1 1 0;min-width:0;overflow:hidden;border-radius:var(--r);
  background:var(--ink-2);cursor:pointer;
  transition:flex-grow .72s var(--ease);
  contain:layout paint;
}
.acc__panel.is-open{flex-grow:var(--acc-open);cursor:default}
.acc__panel:has(.acc__tab:focus-visible){outline:2px solid var(--gold-lt);outline-offset:2px}

/* media: the house treatment, lifted when open */
.acc__media{position:absolute;inset:0;z-index:0}
/* Performance note, learned on the phone: the first cut transitioned
   `filter` on nine large images while their boxes were resizing — nine
   re-rasterisations per frame on top of the layout — and Dennis felt it as
   lag. Now the picture carries ONE static grade and never animates a filter;
   open and folded differ only by the opacity of the wash and of a darkening
   veil (opacity is compositor work). The zoom stays desktop-only. */
.acc__media img,.acc__media video{
  position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  filter:saturate(.8) brightness(.82) contrast(1.03);
}
@media (hover:hover) and (min-width:900px){
  .acc__media img,.acc__media video{transform:scale(1.05);transition:transform 1.4s var(--ease)}
  .acc__panel.is-open .acc__media img,.acc__panel.is-open .acc__media video{transform:scale(1)}
}
.acc__media video{opacity:0;transition:opacity 1s var(--ease)}
.acc__media video.playing{opacity:1}
/* the wash — heavier at the foot where the text sits — plus a veil that
   darkens the folded panels; both change by opacity only */
.acc__media::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:
    linear-gradient(to top,rgba(7,12,22,.92) 0%,rgba(7,12,22,.55) 42%,rgba(7,12,22,.12) 70%,rgba(7,12,22,.28) 100%),
    linear-gradient(var(--wash-soft),var(--wash-soft));
}
.acc__media::before{
  content:"";position:absolute;inset:0;pointer-events:none;z-index:1;
  background:rgba(7,12,22,.46);opacity:1;transition:opacity .7s var(--ease);
}
.acc__panel.is-open .acc__media::before{opacity:0}

/* the tab: number top-left; the name set on end down the strip when folded,
   hidden when open (the body carries the heading then) */
.acc__tab{
  position:absolute;inset:0;z-index:2;display:block;width:100%;height:100%;
  padding:clamp(.9rem,.7rem + .6vw,1.3rem);text-align:left;color:var(--ivory);
  border:0;background:transparent;cursor:inherit;
}
.acc__tab:focus-visible{outline:none}
/* (no running numbers on the panels — the name, set on end, is the label) */
.acc__title{
  position:absolute;left:50%;bottom:clamp(1.1rem,.9rem + .7vw,1.6rem);
  transform:translateX(-50%) rotate(180deg);writing-mode:vertical-rl;
  font-family:var(--font-display);font-size:clamp(1rem,.9rem + .4vw,1.2rem);letter-spacing:.06em;color:var(--ivory);
  white-space:nowrap;opacity:1;transition:opacity .35s var(--ease);
  text-shadow:0 1px 12px rgba(7,12,22,.8);
}
.acc__panel.is-open .acc__title{opacity:0;transition-duration:.2s}

/* the body: fades and rises in a beat after the panel has opened, and is
   gone (visibility, so its link leaves the tab order) when folded */
.acc__body{
  position:absolute;left:0;right:0;bottom:0;z-index:3;
  padding:clamp(1.2rem,1rem + 1.2vw,2rem) clamp(1.2rem,1rem + 1.4vw,2.2rem);
  padding-top:0;
  color:var(--ivory);
  opacity:0;transform:translateY(14px);visibility:hidden;
  transition:opacity .45s var(--ease),transform .45s var(--ease),visibility 0s linear .45s;
}
.acc__panel.is-open .acc__body{
  opacity:1;transform:none;visibility:visible;
  transition:opacity .6s var(--ease) .32s,transform .6s var(--ease) .32s,visibility 0s linear .32s;
}
.acc__h{font-size:clamp(1.5rem,1.2rem + 1.4vw,2.2rem);margin:0 0 .5rem;font-weight:400}
.acc__q{
  font-family:var(--font-display);font-style:italic;font-size:clamp(1.05rem,.95rem + .5vw,1.35rem);
  line-height:1.4;color:var(--ivory-2);margin:0 0 .9rem;max-width:44ch;
}
.acc__list{margin:0 0 1rem;display:grid;gap:.3rem;max-width:56ch}
.acc__list li{position:relative;padding-left:1.1rem;font-size:.9rem;color:var(--ivory-2);line-height:1.5}
.acc__list li::before{content:"";position:absolute;left:0;top:.72em;width:.5rem;height:1px;background:var(--gold)}
.acc__body .tlink{color:var(--gold)}

/* pointer-fine and wide: hover opens. Otherwise click. */
@media (max-width:899px){
  .acc{flex-direction:column;height:auto;--acc-open:1}
  .acc__panel{flex:0 0 auto;height:58px;transition:height .42s var(--ease)}
  .acc__title{
    left:auto;right:auto;bottom:auto;transform:none;writing-mode:horizontal-tb;
    position:absolute;top:50%;left:1.2rem;translate:0 -50%;font-size:1.1rem;
  }
  /* folded rows centre their number on the row; the open panel keeps it in
     the top corner, clear of the body text */
  .acc__panel.is-open{height:min(560px,82vh)}
  .acc__panel.is-open .acc__title{opacity:0}
  .acc__q{max-width:none;font-size:1.05rem}
  .acc__list li{font-size:.86rem}
}
@media (max-width:899px) and (min-width:560px){
  .acc__panel.is-open{height:min(460px,70vh)}
}
@media (prefers-reduced-motion:reduce){
  .acc__panel,.acc__media img,.acc__media video,.acc__body,.acc__title,.acc__media::after{transition:none}
}
@media (forced-colors:active){
  .acc__panel{border:1px solid CanvasText}
  .acc__panel.is-open{outline:2px solid Highlight}
}

/* ---------------------------------------------------------------- offices */
/* ------------------------------------------------------ location overview
   The four desks and the map are one instrument: the desks are tabs down the
   left, the map on the right shows the chosen one, and each desk carries the
   way out — its Google Maps profile. On narrow screens the desks become a
   two-by-two grid above the map. */
.locations{display:grid;gap:clamp(1.2rem,1rem + 1.4vw,2rem);align-items:stretch;margin-top:clamp(1.5rem,1.2rem + 1.4vw,2.4rem)}
@media (min-width:1000px){.locations{grid-template-columns:minmax(300px,36%) minmax(0,1fr)}}
.loc-list{display:grid;gap:0;align-content:start}
@media (max-width:999px){.loc-list{grid-template-columns:repeat(2,1fr)}}
@media (max-width:559px){.loc-list{grid-template-columns:1fr}}
/* A desk is a tab: a quiet row with a hairline above, a gold rule down its
   left edge when chosen, the entity, the city, the address and (from the
   clock script) the local time. It is a <button>, so it looks and behaves
   like one row of a list, not a card. */
.office{
  position:relative;width:100%;text-align:left;font:inherit;color:inherit;cursor:pointer;
  background:transparent;border:0;border-top:1px solid var(--line-2);
  padding:clamp(.9rem,.75rem + .6vw,1.2rem) clamp(1rem,.8rem + .8vw,1.4rem) clamp(.9rem,.75rem + .6vw,1.2rem) clamp(1.2rem,1rem + .8vw,1.6rem);
  display:flex;flex-direction:column;gap:.35rem;
  transition:background .4s var(--ease);
}
.office::after{content:"";position:absolute;left:0;top:14%;bottom:14%;width:2px;background:var(--gold);
  transform:scaleY(0);transform-origin:50% 50%;transition:transform .45s var(--ease-out)}
.office.is-active::after{transform:scaleY(1)}
.office.is-active{background:rgba(26,39,64,.28)}
.office:focus-visible{outline:2px solid var(--gold-lt);outline-offset:-2px}
.loc-list .office:first-child{border-top:0}
@media (max-width:999px){.loc-list .office{border-top:1px solid var(--line-2)}.loc-list .office:nth-child(2){border-top:0}.loc-list .office:nth-child(2n){border-left:1px solid var(--line-2)}}
@media (max-width:559px){.loc-list .office:nth-child(2){border-top:1px solid var(--line-2)}.loc-list .office:nth-child(2n){border-left:0}}
.office h3{font-size:1.2rem}
/* "Veltracon Lifestyle Limited" wraps to two lines where the other three
   entity names fit on one, so Hong Kong's city heading sat a line lower than
   Zug, Dubai and Dusseldorf and the row of four read as misaligned. Reserving
   two lines puts every city name on the same baseline; the addresses below
   keep their natural heights because the card is a column, not a grid. */
.office .ent{font-size:.68rem;letter-spacing:.16em;text-transform:uppercase;color:var(--gold);line-height:1.4}
.office address{font-style:normal;font-size:.86rem;color:var(--muted);line-height:1.55}
/* Local time at each desk. Sits below the address as a quiet footer to the
   card — tabular figures so the minute changing never shifts the line, and a
   dot that reads as "someone is there" without saying it. */
.office-time{display:flex;align-items:center;gap:.55rem;margin:auto 0 0;padding-top:.7rem;
  font-size:.68rem;letter-spacing:.15em;text-transform:uppercase;color:var(--muted)}
.office-time time{font-variant-numeric:lining-nums tabular-nums;letter-spacing:.1em;
  font-size:.78rem;color:var(--ivory-2)}
.office-time i{width:5px;height:5px;border-radius:50%;background:var(--gold);flex:none;
  box-shadow:0 0 0 3px rgba(175,141,72,.15)}

/* ------------------------------------------------------------------ map
   Tiles are placed by assets/js/map.js instead of embedded, so the chrome,
   the grading and — the point of the exercise — the wheel behaviour are ours.
   An iframe hands all three to the other site. */
.map{position:relative;margin:0}
.map__frame{
  position:relative;overflow:hidden;border-radius:var(--r);
  aspect-ratio:16/10;background:var(--ink-2);border:1px solid var(--gold-line);
}
/* beside the desk list the map takes the list's height, not a ratio: a ratio
   plus height:100% would derive its WIDTH from that height and push the frame
   out of its column (measured: the pin sat at the right edge, the page grew) */
@media (min-width:1000px){.map-panel,.map{height:100%}.map__frame{aspect-ratio:auto;height:100%;min-height:420px}}
@media (max-width:700px){.map__frame{aspect-ratio:4/3}}
/* one breath when the view jumps to another office */
.map__canvas.is-jumping .map__tiles{animation:mapjump .42s var(--ease)}
@keyframes mapjump{from{opacity:.35}to{opacity:1}}
.map__canvas{position:absolute;inset:0;overflow:hidden;touch-action:pan-y}
/* Inert until clicked: the page keeps its scroll and its touch gestures. */
.map__canvas.is-live{cursor:grab;touch-action:none}
.map__canvas.is-live.is-dragging{cursor:grabbing}
.map__canvas:focus-visible{outline:2px solid var(--gold-lt);outline-offset:-3px}

/* Raster tiles are a bright grey-green sheet. Inverted and hue-rotated back
   (invert alone turns land pink), then pulled into the palette so the map
   arrives dark and warm rather than as a widget dropped on the page. */
.map__tiles{position:absolute;inset:0;
  /* hue-rotate lands the inverted tiles in the page's navy rather than the
     sepia-green they carried when the ground was warm */
  /* .42 left the parkland reading as a clear green against a navy page —
     measured at 25%% of the map's saturated pixels. .30 keeps the road
     network's gold, which is the one colour that should survive here. */
  filter:invert(1) hue-rotate(190deg) saturate(.3) brightness(.78) contrast(1.12)}
.map__tiles img{position:absolute;top:0;left:0;width:256px;height:256px;
  opacity:0;transition:opacity .45s var(--ease);will-change:transform}
.map__tiles img.in{opacity:1}

/* Edge treatment: an inset ring and a corner-weighted vignette, so the map
   stops at an edge that belongs to the page rather than at a hard crop. */
.map__frame::after{
  content:"";position:absolute;inset:0;pointer-events:none;border-radius:inherit;z-index:3;
  box-shadow:inset 0 0 0 1px rgba(175,141,72,.16),inset 0 0 90px 30px rgba(7,12,22,.6);
  background:radial-gradient(120% 90% at 50% 50%,transparent 46%,rgba(7,12,22,.42) 100%);
}

/* Our own marker: a survey mark, not a balloon pin. It suits a Swiss address
   and does not fight the map's own symbols. Positioned by the script in world
   coordinates, so it stays on the building through panning and zooming. */
.map__pin{
  position:absolute;left:0;top:0;width:54px;height:54px;z-index:2;pointer-events:none;
  background:
    linear-gradient(var(--gold),var(--gold)) 50% 0/1px 13px no-repeat,
    linear-gradient(var(--gold),var(--gold)) 50% 100%/1px 13px no-repeat,
    linear-gradient(var(--gold),var(--gold)) 0 50%/13px 1px no-repeat,
    linear-gradient(var(--gold),var(--gold)) 100% 50%/13px 1px no-repeat;
}
.map__pin::before{content:"";position:absolute;inset:15px;border:1px solid var(--gold);border-radius:50%;
  box-shadow:0 0 0 1px rgba(7,12,22,.5),0 0 20px 5px rgba(175,141,72,.3)}
.map__pin::after{content:"";position:absolute;left:50%;top:50%;width:7px;height:7px;
  transform:translate(-50%,-50%);border-radius:50%;background:var(--gold-lt);
  box-shadow:0 0 0 1px rgba(7,12,22,.6),0 0 12px 3px rgba(232,186,92,.55)}

/* The invitation, and the reason the gate is not a trap: it says what to do. */
/* Top centre, not the middle: the marker sits dead centre, and the hint was
   covering the one thing the map exists to point at. */
.map__hint{
  position:absolute;inset:0;z-index:4;display:grid;place-items:start center;pointer-events:none;
  padding-top:clamp(1.1rem,3vw,2.2rem);transition:opacity .4s var(--ease);
}
.map__canvas.is-live ~ .map__hint{opacity:0}
.map__hint span{
  font-size:.7rem;letter-spacing:.18em;text-transform:uppercase;color:var(--ivory);
  padding:.7rem 1.1rem;border:1px solid var(--gold-line);border-radius:var(--r);
  background:rgba(7,12,22,.72);
  backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
}

.map__ctrls{position:absolute;top:clamp(.8rem,1.6vw,1.2rem);right:clamp(.8rem,1.6vw,1.2rem);
  z-index:5;display:flex;flex-direction:column;gap:1px;background:var(--gold-line);
  border:1px solid var(--gold-line);border-radius:var(--r);overflow:hidden}
.map__ctrl{
  width:38px;height:38px;display:grid;place-items:center;border:0;cursor:pointer;
  background:rgba(7,12,22,.82);color:var(--ivory-2);
  font-size:1rem;line-height:1;font-family:var(--font-body);
  backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
  transition:background .3s var(--ease),color .3s var(--ease);
}
.map__ctrl:hover{background:var(--gold);color:var(--onyx)}
.map__ctrl svg{width:15px;height:15px}

.map__attr{position:absolute;right:.6rem;bottom:.5rem;z-index:5;margin:0;
  font-size:.7rem;letter-spacing:.06em;color:var(--muted)}
.map__attr a{color:var(--ivory-2);border-bottom:1px solid var(--gold-line)}
.map__attr a:hover{color:var(--gold-lt)}

/* Address plate, floating on the map. pointer-events are off on the plate so
   it never steals a drag from the map underneath, and back on for the link. */
.map__plate{
  position:absolute;left:clamp(.9rem,2vw,1.6rem);bottom:clamp(.9rem,2vw,1.6rem);
  z-index:5;pointer-events:none;max-width:min(28ch,66%);
  display:flex;flex-direction:column;gap:.35rem;
  padding:clamp(.9rem,.7rem + .5vw,1.15rem) clamp(1rem,.8rem + .6vw,1.35rem);
  background:rgba(7,12,22,.82);border:1px solid var(--gold-line);border-radius:var(--r);
  backdrop-filter:blur(10px) saturate(130%);-webkit-backdrop-filter:blur(10px) saturate(130%);
}
.map__plate .ent{font-size:.68rem;letter-spacing:.18em;text-transform:uppercase;color:var(--gold)}
.map__plate strong{font-family:var(--font-display);font-weight:400;font-size:1.02rem;color:var(--ivory);line-height:1.35}
.map__links{display:flex;gap:1.1rem;flex-wrap:wrap;margin-top:.35rem}
.map__links a{min-height:28px;display:inline-flex;align-items:center}   /* WCAG 2.5.8: a target, not a hairline */
.map__links a svg{width:11px;height:11px;vertical-align:-1px;margin-left:.25rem}
.map__plate a{pointer-events:auto;align-self:flex-start;margin-top:.25rem;
  font-size:.7rem;letter-spacing:.14em;text-transform:uppercase;color:var(--ivory-2);
  border-bottom:1px solid var(--gold-line);padding-bottom:.2rem;
  transition:color .35s var(--ease),border-color .35s var(--ease)}
.map__plate a:hover{color:var(--gold-lt);border-color:var(--gold)}

/* On a phone the floating plate covered most of a 350px map. It steps out
   of the frame and becomes a plain caption beneath it. */
@media (max-width:700px){
  .map__plate{position:static;max-width:none;margin-top:.7rem;padding:.2rem 0 0;
    background:transparent;border:0;backdrop-filter:none;-webkit-backdrop-filter:none;pointer-events:auto}
  .map__hint{padding-top:.8rem}
}
@media (forced-colors:active){
  .map__tiles{filter:none}
  .map__plate,.map__ctrl,.map__hint span{background:Canvas;backdrop-filter:none}
}

/* --------------------------------------------------------------- partners */
.people{display:grid;gap:1px;background:var(--line-2)}
@media (min-width:760px){.people{grid-template-columns:repeat(2,1fr)}}

/* Portrait beside the details, not above them: stacked, each card would run
   past 1000px on a wide screen and turn a two-person block into a scroll.
   Side by side it reads as a dossier rather than a team grid.

   Which layout applies is not a single breakpoint, because the card's width
   does not track the viewport monotonically — at 760px the people grid goes
   to two columns and each card *halves*. Measured across the range, the card
   is too narrow for two columns below 560px and again between 760 and 940px,
   where the email overflowed its column. So: stacked by default, side by side
   only in the two bands that are actually wide enough. */
.person{--card-bg:rgba(14,22,38,.72);background:var(--card-bg);display:grid;grid-template-columns:1fr}
.person-body{padding:clamp(1.5rem,1.1rem + 1.5vw,2.4rem);
  display:flex;flex-direction:column;gap:.7rem;justify-content:center;min-width:0}
.person h3{font-size:clamp(1.15rem,1rem + .55vw,1.45rem)}

/* Both photographs are bright and high-key; the card is near black. Left flat
   they sit on it as lit rectangles, so the edges are shaded and the image is
   held slightly back at rest, then released on hover. */
.person-portrait{position:relative;overflow:hidden;background:var(--ink-2)}
/* The shape comes from a padding ratio, not `aspect-ratio`. As a stretched
   grid item the portrait's height is the row height, and `aspect-ratio` would
   then derive its *width* from that height — pushing it ~29px past its own
   column and under the text. Padding-top sets a minimum height instead and
   leaves the width where the grid put it; if the body runs taller, the row
   simply grows and the absolutely-placed image fills whatever it gets. */
.person-portrait::before{content:"";display:block;padding-top:88%}
/* stacked (phone) layout: the frame is landscape and both portraits are
   framed head-high — measured on iPhone 13, the crown of the head was cut on
   both. Anchor the picture higher and give the frame a little more height. */
@media (max-width:939px){.person-portrait img{object-position:center 8%}}
.person-portrait img{position:absolute;inset:0;width:100%;height:100%;display:block;object-fit:cover;
  object-position:center 26%;
  /* Two real photographs among fourteen graded stills. At the old .86 they were
     the only full-colour images on the page — a green hedge and a blue sky
     against a navy ground. Pulled toward the house treatment, but not all the
     way to the .62 the stills carry: skin drained that far stops reading as a
     person. Hover returns them to full colour, which is the point of a portrait. */
  filter:saturate(.68) brightness(.88) contrast(1.05);transform:scale(1.01);
  transition:transform 1.2s var(--ease),filter .8s var(--ease)}
.person-portrait::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:
    linear-gradient(var(--wash-soft),var(--wash-soft)),
    linear-gradient(to bottom,rgba(0,0,0,.2) 0%,transparent 30%,transparent 62%,var(--card-bg) 100%);
  transition:opacity .8s var(--ease)}
.person:hover .person-portrait::after,.person:focus-within .person-portrait::after{opacity:.45}
.person:hover .person-portrait img,.person:focus-within .person-portrait img{
  transform:scale(1.05);filter:saturate(1) brightness(1) contrast(1)}

@media (min-width:560px) and (max-width:759px),(min-width:940px){
  .person{grid-template-columns:minmax(150px,40%) minmax(0,1fr)}
  .person-portrait::before{padding-top:125%}
  .person-portrait img{object-position:center}
  .person-portrait::after{background:
    linear-gradient(var(--wash-soft),var(--wash-soft)),
    linear-gradient(to right,rgba(0,0,0,.22) 0%,transparent 22%,transparent 72%,rgba(0,0,0,.42) 100%)}
}
.person .role{font-size:.7rem;letter-spacing:.18em;text-transform:uppercase;color:var(--gold)}
.person dl{display:grid;gap:.4rem;margin:.9rem 0 0}
.person dt{font-size:.7rem;letter-spacing:.14em;text-transform:uppercase;color:var(--muted)}
.person dd{margin:0 0 .6rem;font-size:.94rem;color:var(--ivory-2)}
.person dd a:hover{color:var(--gold-lt)}
.langs{display:flex;flex-wrap:wrap;gap:.45rem;margin-top:.4rem}
.langs li{font-size:.68rem;letter-spacing:.12em;text-transform:uppercase;color:var(--gold-lt);border:1px solid var(--gold-line);padding:.3rem .6rem;border-radius:var(--r)}

/* ------------------------------------------------------------------ forms */
.form-grid{display:grid;gap:clamp(2rem,1.5rem + 3vw,4rem)}
@media (min-width:940px){.form-grid{grid-template-columns:1.15fr .85fr}}
.field{display:flex;flex-direction:column;gap:.5rem;margin-bottom:1.15rem}
.field label{font-size:.72rem;letter-spacing:.13em;text-transform:uppercase;color:var(--ivory-2)}
.field input,.field select,.field textarea{
  width:100%;padding:.9rem 1rem;
  background:var(--ink-2);
  border:1px solid var(--line);
  border-radius:var(--r);
  color:var(--ivory);
  font-family:var(--font-body);font-size:.95rem;font-weight:300;
  transition:border-color .35s var(--ease),background .35s var(--ease);
}
.field input::placeholder,.field textarea::placeholder{color:var(--muted);opacity:1}
/* The border tint alone is not a focus indicator: it is a 1px colour change
   and it was killing the global outline via `outline:none`. Keyboard focus now
   keeps a real ring; the tint stays as the additional cue. */
.field input:focus,.field select:focus,.field textarea:focus{border-color:var(--gold);background:var(--ink-3)}
.field input:focus-visible,.field select:focus-visible,.field textarea:focus-visible{
  outline:2px solid var(--gold-lt);outline-offset:2px;
}
.field textarea{resize:vertical;min-height:140px}
.field select{
  appearance:none;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23AF8D48' stroke-width='2'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 1rem center;background-size:16px;
  padding-right:2.8rem;
}
.field-row{display:grid;gap:0 1.15rem}
@media (min-width:620px){.field-row{grid-template-columns:1fr 1fr}}
.hint{font-size:.78rem;color:var(--muted);margin-top:-.35rem}
.demo-note{font-size:.74rem;color:var(--muted);letter-spacing:.03em;margin-top:1rem}

.aside-card{background:rgba(14,22,38,.6);border:1px solid var(--line);border-radius:var(--r);padding:clamp(1.6rem,1.2rem + 1.4vw,2.25rem)}
.aside-card h3{font-size:1.15rem;margin-bottom:1rem}
.aside-card dl{margin:0}
.aside-card dt{font-size:.7rem;letter-spacing:.14em;text-transform:uppercase;color:var(--muted);margin-top:1rem}
.aside-card dd{margin:.3rem 0 0;font-size:.95rem;color:var(--ivory-2)}
.aside-card dd a:hover{color:var(--gold-lt)}

/* ------------------------------------------------------------------- blog */
.posts{display:grid;gap:clamp(1.75rem,1.4rem + 1.6vw,2.75rem)}
@media (min-width:680px){.posts{grid-template-columns:repeat(2,1fr)}}
@media (min-width:1060px){.posts{grid-template-columns:repeat(3,1fr)}}
.post{display:flex;flex-direction:column;gap:1rem;height:100%}
.post__media{aspect-ratio:3/2;overflow:hidden;border-radius:var(--r);background:var(--ink-2);position:relative}
.post__media img{width:100%;height:100%;object-fit:cover;transition:transform .9s var(--ease)}
.post:hover .post__media img{transform:scale(1.05)}
.post time{font-size:.7rem;letter-spacing:.14em;text-transform:uppercase;color:var(--gold)}
/* Titles run to one or two lines, which pushed each card's excerpt to a
   different height and broke the row's horizontal rhythm by 25px. Two lines
   are reserved so every excerpt starts on the same baseline; the "Read More"
   link is already pinned to the bottom by margin-top:auto, so the cards stay
   tidy at both ends regardless of how long the copy runs. */
.post h3{font-size:1.22rem;line-height:1.28;min-height:2.56em}
.post p{font-size:.9rem;color:var(--muted);margin:0}
.post .tlink{margin-top:auto;padding-top:.6rem}
/* Journal entries without a built-out article page: same card, no affordance
   that promises a link which is not there. */
.post--flat{cursor:default}
.post--flat h3{color:var(--ivory-2)}

/* long-form article */
.article{max-width:74ch;margin-inline:auto}
.article h2{font-size:clamp(1.5rem,1.2rem + 1.3vw,2.1rem);margin:2.6rem 0 1rem}
.article h3{font-size:1.3rem;margin:2rem 0 .8rem}
.article p{color:var(--ivory-2)}
/* An unbroken URL in one imported body was 340px wide on a 320px screen. */
.article a{overflow-wrap:anywhere}
/* And one body carries a table wider than a phone. It keeps its own scroll
   rather than pushing the page sideways; tabindex makes that scroll reachable
   from the keyboard, which a scrollable region needs. */
.table-scroll{overflow-x:auto;-webkit-overflow-scrolling:touch;margin:2rem 0}
.table-scroll:focus-visible{outline:2px solid var(--gold-lt);outline-offset:3px}
.article table{border-collapse:collapse;min-width:100%}
.article th,.article td{border:1px solid var(--line-2);padding:.6rem .8rem;text-align:left;font-size:.88rem}
.article th{color:var(--ivory-2);font-weight:500}
.article figure{margin:2.5rem 0}
.article figure img{border-radius:var(--r);width:100%}
.article figcaption{font-size:.78rem;color:var(--muted);margin-top:.7rem}
.article blockquote{
  margin:2.5rem 0;padding-left:1.75rem;border-left:1px solid var(--gold-line);
  font-family:var(--font-display);font-style:italic;font-size:1.3rem;line-height:1.45;color:var(--ivory);
}
.article ul{display:grid;gap:.6rem;margin:1.5rem 0}
.article ul li{position:relative;padding-left:1.5rem;color:var(--ivory-2)}
.article ul li::before{content:"";position:absolute;left:0;top:.72em;width:8px;height:1px;background:var(--gold)}

/* ----------------------------------------------------------------- legal */
.legal h2{font-size:1.45rem;margin:2.4rem 0 .9rem}
.legal h3{font-size:1.12rem;margin:1.8rem 0 .6rem}
.legal p,.legal li{color:var(--ivory-2);font-size:.95rem}
.legal ul{display:grid;gap:.5rem;margin:1rem 0}
.legal ul li{position:relative;padding-left:1.4rem}
.legal ul li::before{content:"";position:absolute;left:0;top:.72em;width:7px;height:1px;background:var(--gold)}

/* ---------------------------------------------------------------- CTA band */
/* ------------------------------------------------------------- closing CTA
   Was a full-bleed rendered gold-leaf plate with dark text. It was carefully
   built — the metal's luminance range was clamped so onyx text cleared 4.5:1
   on every pixel — but under the navy ground it became the single loudest
   break in the page, the same fault the ivory island had: one section playing
   by its own rules right before the footer.

   It now closes the page the way the page opens it: full-bleed footage, the
   house wash, ivory type. The gold stays where gold belongs on this site —
   on the button. */
.cta-band{
  position:relative;color:var(--ivory);text-align:center;overflow:hidden;isolation:isolate;
  background:transparent;
  /* dissolve into the ambient at the top edge instead of cutting against it */
  -webkit-mask-image:linear-gradient(to bottom,transparent,#000 18%,#000 86%,transparent);
  mask-image:linear-gradient(to bottom,transparent,#000 18%,#000 86%,transparent);
}
.cta-band .cta-media{position:absolute;inset:0;z-index:0}
.cta-band .cta-media img,.cta-band .cta-media video{
  width:100%;height:100%;object-fit:cover;
}
.cta-band .cta-media video{position:absolute;inset:0;opacity:0;transition:opacity 1s var(--ease)}
.cta-band .cta-media video.playing{opacity:1}
.cta-band .cta-scrim{
  position:absolute;inset:0;z-index:1;pointer-events:none;
  background:
    linear-gradient(var(--wash),var(--wash)),
    radial-gradient(76% 70% at 50% 50%,rgba(7,12,22,.74),rgba(7,12,22,.9) 100%);
}
.cta-band .wrap{position:relative;z-index:2}
.cta-band h2{color:var(--ivory);max-width:20ch;margin-inline:auto}
.cta-band p{color:var(--ivory-2);max-width:52ch;margin-inline:auto;margin-top:1.2rem}
.cta-band .btn-row{justify-content:center;margin-top:2.2rem}

/* ---------------------------------------------------------------- footer */
.footer{background:linear-gradient(to bottom,transparent,rgba(7,12,22,.7) 30%,rgba(7,12,22,.9));border-top:1px solid var(--line-2);padding-block:clamp(3.5rem,2.5rem + 4vw,5.5rem) 0}
.footer-grid{display:grid;gap:clamp(2rem,1.5rem + 3vw,3.5rem)}
/* four columns since the audience pages joined: brand, services, who we work
   for, offices. Below 1100px it drops to two so no column gets 120px wide. */
@media (min-width:820px){.footer-grid{grid-template-columns:repeat(2,1fr)}}
@media (min-width:1100px){.footer-grid{grid-template-columns:1.25fr .8fr .95fr .95fr}}
.footer h2{font-size:.7rem;letter-spacing:.18em;text-transform:uppercase;color:var(--gold);margin-bottom:1.2rem;font-family:var(--font-body);font-weight:500}
/* .footer is dark but carries no .section--ink class, so muted text must be
   set explicitly here. Inheriting a light-section colour is the single most
   repeated contrast bug in this portfolio. */
.footer p,.footer address,.footer li{color:var(--muted);font-size:.88rem;font-style:normal;line-height:1.75}
.footer a:hover{color:var(--gold-lt)}
.footer-links{display:grid;gap:.5rem}
.footer-ent{display:grid;gap:1.4rem}
.footer-ent address strong{display:block;color:var(--ivory-2);font-weight:400;font-size:.9rem;margin-bottom:.15rem}
.footer-bottom{
  margin-top:clamp(2.5rem,2rem + 3vw,4rem);border-top:1px solid var(--line-2);
  padding-block:1.75rem;display:flex;flex-wrap:wrap;gap:.8rem 1.75rem;align-items:center;justify-content:space-between;
}
.footer-bottom,.footer-bottom a{font-size:.76rem;color:var(--muted)}

/* WCAG 2.5.8 wants 24x24 CSS px of target. These sit at 12px type, so the
   text box is ~15px tall and the tap area was well under half the minimum.
   Padding grows the hit area, the matching negative margin keeps the row
   exactly where it was — the fix is invisible and only the finger notices. */
.footer-bottom a,.crumb a,.office address a{display:inline-block;padding-block:.4rem;margin-block:-.4rem}
.tagline{font-family:var(--font-display);font-style:italic;font-size:.95rem;color:var(--gold-lt)}

/* ------------------------------------------------------------- to-top */
.totop{
  position:fixed;right:clamp(1rem,2vw,2rem);bottom:clamp(1rem,2vw,2rem);z-index:90;
  width:46px;height:46px;display:grid;place-items:center;
  background:var(--gold);color:var(--onyx);border-radius:var(--r);
  opacity:0;pointer-events:none;transform:translateY(10px);
  transition:opacity .4s var(--ease),transform .4s var(--ease),background .4s var(--ease);
}
.totop.show{opacity:1;pointer-events:auto;transform:translateY(0)}
.totop:hover{background:var(--gold-lt)}
.totop svg{width:17px;height:17px}

/* ------------------------------------------------------------- reveals */
[data-reveal]{opacity:0;transform:translateY(26px);transition:opacity .95s var(--ease-out),transform .95s var(--ease-out)}
[data-reveal].in{opacity:1;transform:none}

/* Images do not fade in, they are unveiled: a wipe from the right combined
   with a slow settle out of a slight over-scale. A plain fade reads as a web
   page loading; a wipe reads as something being shown to you.
   The reveal uses the standalone `scale` property and hover uses `transform`,
   so the two compose instead of overwriting each other. */
.frame img,.post__media img,.rel-card__img img,.chapter__pic img{scale:1}
[data-reveal] .frame img,[data-reveal] .chapter__pic img,
[data-reveal-stagger] .post__media img,[data-reveal-stagger] .rel-card__img img{
  clip-path:inset(0 0 0 100%);
  scale:1.07;
  transition:clip-path 1.25s var(--ease-out) .08s,scale 1.9s var(--ease-out) .08s;
}
[data-reveal].in .frame img,[data-reveal].in .chapter__pic img,
[data-reveal-stagger].in .post__media img,[data-reveal-stagger].in .rel-card__img img{
  clip-path:inset(0 0 0 0);
  scale:1;
}

/* A headline lifts out from behind its own baseline rather than sliding up. */
[data-reveal-mask]{opacity:0}
[data-reveal-mask].in{opacity:1}
[data-reveal-mask] .lift{display:block;overflow:hidden;padding-bottom:.08em}
[data-reveal-mask] .lift > span{
  display:block;transform:translateY(105%);
  transition:transform 1.15s var(--ease-out);
}
[data-reveal-mask].in .lift > span{transform:translateY(0)}
[data-reveal-mask] .lift:nth-child(2) > span{transition-delay:.09s}
[data-reveal-mask] .lift:nth-child(3) > span{transition-delay:.18s}
/* The hero headline must not wait for a script: it is the largest thing on the
   first screen (LCP), and gating it behind main.js + an observer callback put
   its paint a second or more after the page was ready. On the hero the same
   lift runs as a CSS animation from the moment the stylesheet applies. */
.hero [data-reveal-mask]{opacity:1}
.hero [data-reveal-mask] .lift > span{transform:none;transition:none;animation:liftin 1.15s var(--ease-out) both .12s}
.hero [data-reveal-mask] .lift:nth-child(2) > span{animation-delay:.21s}
@keyframes liftin{from{transform:translateY(105%)}to{transform:none}}
@media (prefers-reduced-motion:reduce){.hero [data-reveal-mask] .lift > span{animation:none}}
[data-reveal-stagger]>*{opacity:0;transform:translateY(22px);transition:opacity .8s var(--ease-out),transform .8s var(--ease-out)}
[data-reveal-stagger].in>*{opacity:1;transform:none}
[data-reveal-stagger].in>*:nth-child(1){transition-delay:.04s}
[data-reveal-stagger].in>*:nth-child(2){transition-delay:.11s}
[data-reveal-stagger].in>*:nth-child(3){transition-delay:.18s}
[data-reveal-stagger].in>*:nth-child(4){transition-delay:.25s}
[data-reveal-stagger].in>*:nth-child(5){transition-delay:.32s}
[data-reveal-stagger].in>*:nth-child(6){transition-delay:.39s}

@media (prefers-reduced-motion:reduce){
  [data-reveal],[data-reveal-stagger]>*,[data-reveal-mask]{opacity:1;transform:none;transition:none}
  .hairline{transform:scaleX(1)!important}
  .frame img,.post__media img{transition:none}
  [data-reveal] .frame img,[data-reveal] .chapter__pic img,
  [data-reveal-stagger] .post__media img,[data-reveal-stagger] .rel-card__img img{
    clip-path:none;scale:1;transition:none;
  }
  [data-reveal-mask] .lift > span{transform:none;transition:none}
  .chapter::before{transform:scaleX(1)}
}

/* ---------------------------------------------------------------- ground
   The page's ground: one fixed layer of soft, static light. Deep navy with a
   cool pool of light upper-left, a warmer one lower-right, a single diagonal
   sweep of light like a window across a dark room, and a vignette that lets
   the corners fall away. Nothing moves, nothing is noisy — Dennis found the
   animated shader ground "viel zu aufdringlich" and its half-resolution grain
   "verpixelt", and he was right: a background is a room, not a screensaver.

   A fixed <div>, not background-attachment:fixed, because iOS ignores the
   latter and would stretch the pools over the whole 10,000px document. */
.ground{
  position:fixed;inset:0;z-index:-1;pointer-events:none;
  background:
    linear-gradient(118deg,transparent 40%,rgba(214,226,240,.032) 50%,transparent 60%),
    radial-gradient(70% 62% at 16% 18%,rgba(30,46,78,.62),transparent 70%),
    radial-gradient(62% 56% at 86% 84%,rgba(44,46,64,.5),transparent 70%),
    radial-gradient(130% 110% at 50% 50%,transparent 52%,rgba(4,8,16,.6) 100%),
    linear-gradient(180deg,#0B1322,#0E1626 55%,#0A1120);
}



.skip{position:absolute;left:-9999px}
.skip:focus{left:1rem;top:1rem;z-index:200;padding:.75rem 1.25rem;background:var(--gold);color:var(--onyx);border-radius:var(--r)}

/* -------------------------------------------------- headline word reveal
   Words of a data-words heading arrive one after another: blurred and a
   little low, then sharp and in place. Only once the surrounding [data-reveal]
   has fired (.in), so it rides the same observer as everything else; a
   heading that is itself the reveal target works the same way. */
.words-ready .w{display:inline-block;will-change:opacity,filter,transform;
  opacity:0;filter:blur(9px);transform:translateY(.32em);
  transition:opacity .75s var(--ease),filter .75s var(--ease),transform .75s var(--ease);
  transition-delay:calc(var(--i,0) * 65ms + 120ms)}
[data-reveal].in .words-ready .w,.words-ready[data-reveal].in .w{opacity:1;filter:blur(0);transform:none}
/* until the reveal system is live (no JS, no IO) the words must simply show */
html.no-js .words-ready .w{opacity:1;filter:none;transform:none}
@media (prefers-reduced-motion:reduce){.words-ready .w{transition:none;opacity:1;filter:none;transform:none}}

/* ------------------------------------------------------- pointer effects
   Driven by assets/js/pointer-fx.js, which writes --px/--py (pointer position
   in px, relative to the element) and toggles .has-pointer. Everything else
   is here. Hover-capable, fine-pointer devices only; the JS does not even
   attach elsewhere, so these rules simply never match on touch.

   Chroma spotlight (after React Bits' ChromaGrid): the pictures on this page
   are graded down to sit in the navy — saturate(.62) plus the house wash. A
   duplicate <img class="chroma"> sits on top, ungraded, masked to a soft disc
   under the pointer. Under the cursor the picture is itself again; a hand's
   width away it is the page's again. It is an <img> inside the same box, so
   the hover scale and reveal rules that address "… img" reach both layers
   and they stay registered to the pixel; only the grade is overridden. */
@media (hover:hover) and (pointer:fine){
  .chroma{
    position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:1;
    pointer-events:none;
    filter:none !important;
    opacity:0;transition:opacity .55s var(--ease),transform 1.1s var(--ease);
    -webkit-mask-image:radial-gradient(circle var(--cr,160px) at var(--px,50%) var(--py,50%),#000 0,rgba(0,0,0,.9) 32%,rgba(0,0,0,.35) 68%,transparent 100%);
    mask-image:radial-gradient(circle var(--cr,160px) at var(--px,50%) var(--py,50%),#000 0,rgba(0,0,0,.9) 32%,rgba(0,0,0,.35) 68%,transparent 100%);
  }
  .has-pointer .chroma{opacity:1}
  .frame .chroma,.post__media .chroma{transition:opacity .55s var(--ease),transform .9s var(--ease)}
  /* the frame's wash and mark, and the post's, keep their layer above the base
     picture but must sit under the chroma disc's own wash-free colour: they
     are ::after at z-index 1 too, drawn before a later sibling — fine. Text
     and marks that must stay on top say so: */
  .g-item figcaption{z-index:3}
  .frame--marked > .mark-br{z-index:3}

  /* Spotlight cards (after SpotlightCard): a soft gold light on the surface
     under the pointer, and a border that lifts toward it. */
  .office,.person,.stat{position:relative;overflow:hidden}
  .office::before,.person::before,.stat::before{
    content:"";position:absolute;inset:0;z-index:0;pointer-events:none;
    background:radial-gradient(260px circle at var(--px,50%) var(--py,50%),rgba(175,141,72,.13),rgba(175,141,72,.04) 40%,transparent 70%);
    opacity:0;transition:opacity .5s var(--ease);
  }
  .office.has-pointer::before,.person.has-pointer::before,.stat.has-pointer::before{opacity:1}
  .office > *,.person > *,.stat > *{position:relative;z-index:1}

  /* Specular button (after SpecularButton): the highlight travels with the
     pointer across the gold, so the button reads as a piece of metal under a
     lamp rather than a flat fill. */
  .btn-gold{position:relative;overflow:hidden}
  .btn-gold::after{
    content:"";position:absolute;inset:0;pointer-events:none;
    background:radial-gradient(120px circle at var(--px,50%) var(--py,50%),rgba(255,244,214,.55),rgba(255,244,214,.18) 35%,transparent 70%);
    mix-blend-mode:soft-light;opacity:0;transition:opacity .35s var(--ease);
  }
  .btn-gold.has-pointer::after{opacity:1}
  .btn-gold > *{position:relative;z-index:1}
}
@media (prefers-reduced-motion:reduce){
  .chroma{transition:none}
}
body.motion-off .chroma,body.motion-off .office::before,body.motion-off .person::before,body.motion-off .stat::before,body.motion-off .btn-gold::after{opacity:0 !important}

/* --------------------------------------------------------------- prose
   Long-form German copy: the cost guides and the service pages carry more
   continuous text than anything else on this site, and continuous text needs
   a measure and a rhythm rather than the sparse editorial spacing the rest of
   the page uses. One column, 68 characters, headings that own the space above
   them and not below. */
.prose{max-width:68ch}
.prose > * + *{margin-top:1.1rem}
.prose h2{margin-top:clamp(2.4rem,2rem + 2vw,3.4rem);margin-bottom:.2rem}
.prose > h2:first-child{margin-top:0}
.prose h3{margin-top:clamp(1.6rem,1.4rem + 1vw,2.2rem);margin-bottom:.1rem;
  font-size:clamp(1.1rem,1rem + .5vw,1.35rem);color:var(--ivory)}
.prose p{color:var(--ivory-2);line-height:1.8}
.prose .chapter__list{margin-top:.9rem;display:grid;gap:.45rem}
.prose .related__grid{max-width:none;margin-top:1.4rem}
/* tables carry the actual figures on the cost pages; they must stay readable
   on a phone, so they scroll inside their own box rather than widening the page */
.prose .tablewrap{overflow-x:auto;margin-top:1.2rem;border:1px solid var(--line-2);border-radius:var(--r)}
/* der Rahmen ist per Tastatur fokussierbar, damit man die rechten Spalten
   auch ohne Maus erreicht — der Fokus muss dann auch sichtbar sein */
.prose .tablewrap:focus-visible{outline:2px solid var(--gold-lt);outline-offset:2px}
.prose table{width:100%;border-collapse:collapse;font-size:.92rem;min-width:34rem}
.prose caption{caption-side:bottom;padding:.7rem .9rem;text-align:left;
  font-size:.78rem;color:var(--muted);line-height:1.6}
.prose th,.prose td{padding:.7rem .9rem;text-align:left;border-bottom:1px solid var(--line-2);vertical-align:top}
.prose thead th{color:var(--gold);font-weight:500;font-size:.72rem;letter-spacing:.14em;
  text-transform:uppercase;white-space:nowrap}
.prose tbody tr:last-child td{border-bottom:0}
.prose td:first-child{color:var(--ivory)}
.prose .src{font-size:.8rem;color:var(--muted);margin-top:.5rem}
.prose .src a{border-bottom:1px solid var(--gold-line)}
.prose .src a:hover{color:var(--gold-lt)}

/* ------------------------------------------------------------- related
   The way on. Two entries and the service they belong to, with anchor text
   that says what the reader gets — "Private travel, aviation and yacht
   charter", not "read more". Descriptive anchors are what an internal link is
   for; a link that says "more" passes a click but no meaning. */
.related__head{display:flex;flex-wrap:wrap;align-items:baseline;justify-content:space-between;
  gap:1rem 2rem;margin-bottom:clamp(1.4rem,1.1rem + 1.2vw,2rem)}
.related__grid{display:grid;gap:1px;background:var(--line-2)}
@media (min-width:720px){.related__grid{grid-template-columns:repeat(2,1fr)}}
.rel-card{display:flex;flex-direction:column;gap:.5rem;background:rgba(14,22,38,.5);
  padding:clamp(1.2rem,1rem + 1vw,1.8rem);transition:background .4s var(--ease)}
.rel-card:hover{background:rgba(26,39,64,.6)}
.rel-card__k{font-size:.7rem;letter-spacing:.22em;text-transform:uppercase;color:var(--gold)}
.rel-card__t{font-family:var(--font-display);font-size:clamp(1.05rem,.95rem + .5vw,1.3rem);
  line-height:1.3;color:var(--ivory);transition:color .35s var(--ease)}
.rel-card:hover .rel-card__t{color:var(--gold-lt)}
.rel-card__d{font-size:.9rem;color:var(--muted);line-height:1.6}

/* ----------------------------------------------------------------- FAQ
   Plain <details>, no JavaScript: it is keyboard-operable and searchable by
   the browser's own find, and a crawler reads the answer whether the item is
   open or not — which is the point, since these blocks exist to be quoted.
   The rows are hairline-separated like the office list, so the page gains a
   section without gaining a new mechanic. */
.faq__head{max-width:60ch;margin-bottom:clamp(1.6rem,1.3rem + 1.4vw,2.4rem)}
.faq__list{border-top:1px solid var(--line-2);max-width:78ch}
.faq__item{border-bottom:1px solid var(--line-2)}
.faq__item summary{
  display:flex;align-items:flex-start;gap:1rem;justify-content:space-between;
  padding:clamp(1rem,.85rem + .6vw,1.35rem) 0;cursor:pointer;list-style:none;
  font-family:var(--font-display);font-size:clamp(1.02rem,.95rem + .4vw,1.25rem);
  line-height:1.4;color:var(--ivory);transition:color .35s var(--ease);
}
.faq__item summary::-webkit-details-marker{display:none}
.faq__item summary::after{
  content:"";flex:none;width:11px;height:11px;margin-top:.45em;
  border-right:1px solid var(--gold);border-bottom:1px solid var(--gold);
  transform:rotate(45deg);transition:transform .35s var(--ease);
}
.faq__item[open] summary::after{transform:rotate(-135deg)}
.faq__item summary:hover,.faq__item[open] summary{color:var(--gold-lt)}
.faq__item summary:focus-visible{outline:2px solid var(--gold-lt);outline-offset:3px;border-radius:var(--r)}
.faq__a{padding:0 0 clamp(1rem,.85rem + .6vw,1.35rem);max-width:68ch}
.faq__a p{margin:0;color:var(--ivory-2);font-size:.97rem;line-height:1.75}
@media (prefers-reduced-motion:reduce){.faq__item summary,.faq__item summary::after{transition:none}}

/* ------------------------------------------------------------ fine detail */
/* Panels lift a hairline's worth on hover. Enough to feel responsive, not
   enough to look like a web app. */
.office,.person{transition:background .5s var(--ease)}
.office:hover{background:rgba(26,39,64,.22)}
.person:hover,.person:focus-within{--card-bg:rgba(26,39,64,.8)}
.office h3,.person h3{transition:color .4s var(--ease)}
.office:hover h3,.person:hover h3{color:var(--gold-lt)}

/* the nav marker grows from the centre instead of sweeping in from the left */
.nav-link::after{left:50%;right:50%;transition:left .4s var(--ease-out),right .4s var(--ease-out)}
.nav-link:hover::after,.nav-link.active::after{left:0;right:0}

/* small caps numerals read better in the stats row */
.stat b{font-variant-numeric:lining-nums tabular-nums;letter-spacing:-.02em}

/* a hairline above the footer that carries the brand colour across the page */
.footer{border-top:0;position:relative}
.footer::before{
  content:"";position:absolute;top:0;left:0;right:0;height:1px;
  background:linear-gradient(90deg,transparent,var(--gold-line) 22%,var(--gold-line) 78%,transparent);
}

/* the marquee sits closer to a printed masthead when it is quieter */
.marquee-track span{transition:opacity .5s var(--ease)}
.marquee:hover .marquee-track span{opacity:.5}
.marquee-track span:hover{opacity:1;color:var(--gold-lt)}

/* pull quotes get an oversized opening mark, set in the display face */
.pull{position:relative}
.chapter__q::before,.subhero .pull::before{
  content:"\201C";position:absolute;left:-.52em;top:-.18em;
  font-family:var(--font-display);font-size:2.4em;line-height:1;
  color:var(--gold);opacity:.22;pointer-events:none;
}
@media (max-width:640px){
  .chapter__q::before,.subhero .pull::before{display:none}
}

/* The video globe that stood here (three builds of it) is retired; its
   history — the stacking-context black square, the dead sibling selector, the
   motion-off empty box — lives in README "Sechzehnter Durchgang". The globe is
   now drawn: see "presence" below and assets/js/globe.js. */
/* ------------------------------------------------------------- presence
   The globe section, rebuilt: the globe is a canvas (assets/js/globe.js), set
   large and centred at the top of the section, and it dissolves at its foot
   so the heading can rise into it. Under the heading, the four desks with
   their local time read as the section's row of facts, and the map closes it.
   No split layout, no video, no rectangle — one composed piece. */
#offices{overflow-x:clip}
.presence__stage{
  position:relative;width:min(78vw,600px);aspect-ratio:1;margin:0 auto calc(-1 * clamp(5rem,4rem + 6vw,9rem));
  -webkit-mask-image:linear-gradient(to bottom,#000 0%,#000 52%,rgba(0,0,0,.35) 76%,transparent 100%);
  mask-image:linear-gradient(to bottom,#000 0%,#000 52%,rgba(0,0,0,.35) 76%,transparent 100%);
}
/* a halo behind the sphere: navy lifted a step, the faintest gold at the core */
.presence__stage::before{
  content:"";position:absolute;inset:-6%;pointer-events:none;border-radius:50%;
  background:radial-gradient(closest-side,rgba(175,141,72,.09),rgba(26,39,64,.5) 40%,transparent 72%);
}
.presence__stage canvas{
  position:relative;display:block;width:100%;height:100%;
  cursor:grab;touch-action:pan-y;outline:none;border-radius:50%;
}
.presence__stage canvas.is-dragging{cursor:grabbing}
.presence__stage canvas:focus-visible{box-shadow:0 0 0 2px var(--gold-lt)}
.presence__hint{
  position:absolute;left:50%;top:-.2rem;transform:translateX(-50%);
  font-size:.7rem;letter-spacing:.2em;text-transform:uppercase;color:var(--muted);
  opacity:.9;pointer-events:none;
}
@media (hover:none){.presence__hint{display:none}}
.presence__copy{
  position:relative;z-index:1;text-align:center;max-width:64ch;margin:0 auto clamp(2rem,1.6rem + 2vw,3.2rem);
}
.presence__copy .eyebrow{display:block;margin-bottom:.9rem}
.presence__copy h2{margin-inline:auto;max-width:18ch}
.presence__copy .lede{margin:1.2rem auto 0;max-width:56ch}
.presence__more{margin:.9rem auto 0;max-width:60ch}
@media (max-width:700px){
  .presence__stage{width:min(88vw,420px);margin-bottom:calc(-1 * clamp(3rem,10vw,5rem))}
}

/* --------------------------------------------------- motion, one step finer */
/* The pinned journey plate breathes instead of sitting still. A very slow
   scale on the active layer only, so nothing animates off-screen. */
@keyframes plate-drift{
  from{transform:scale(1.0) translate3d(0,0,0)}
  to{transform:scale(1.075) translate3d(0,-1.2%,0)}
}
.jm-layer.on img,.jm-layer.on video{
  animation:plate-drift 17s var(--ease) infinite alternate;
  will-change:transform;
}

/* Where the fixed-media trick is not supported, fall back to the old behaviour
   rather than leaving the band empty. */
@supports not (clip-path: inset(0)){
  .band-media{position:absolute;height:100%}
}

@media (prefers-reduced-motion:reduce){
  .jm-layer.on img,.jm-layer.on video{animation:none}
  .band-media{position:absolute;height:100%}
}

/* ----------------------------------------------------------------- gallery */
/* A full-bleed photographic coda. Native scroll with snap, no carousel
   library, no arrows: on a touch device it is a swipe, on a desktop it is a
   trackpad flick, and with a keyboard the strip is focusable and scrolls.
   The plates are deliberately oversized so the row runs off both edges and
   reads as a strip rather than as a row of cards. */
.gallery{padding-block:clamp(3rem,2rem + 4vw,5.5rem) clamp(1.75rem,1.25rem + 1.5vw,2.75rem);background:transparent;overflow:hidden}
/* Heading and controls share the row: the arrows read as belonging to the
   section rather than floating over the photographs. */
.gallery__head{display:flex;align-items:flex-end;justify-content:space-between;
  gap:clamp(1.5rem,4vw,3rem);margin-bottom:clamp(2rem,1.6rem + 2vw,3rem)}
.gallery__head > div:first-child{max-width:52ch}
.g-nav{display:flex;gap:1px;flex:none;background:var(--gold-line);
  border:1px solid var(--gold-line);border-radius:var(--r);overflow:hidden}
.g-btn{
  width:46px;height:46px;display:grid;place-items:center;border:0;cursor:pointer;
  background:var(--ink);color:var(--ivory-2);
  transition:background .35s var(--ease),color .35s var(--ease);
}
.g-btn svg{width:17px;height:17px}
.g-btn:hover:not(:disabled){background:var(--gold);color:var(--onyx)}
/* Not opacity: .g-nav carries a gold hairline behind the buttons, so a
   translucent button let that gold show through and the disabled arrow looked
   like the highlighted one. The glyph fades, the surface stays. */
.g-btn:disabled{color:rgba(220,214,201,.26);cursor:default;background:var(--ink)}
@media (max-width:560px){.gallery__head{flex-direction:column;align-items:flex-start}}

/* The scrollbar is hidden by design, which left no way to tell how far the
   strip runs or where in it you are. This says both, in one hairline. */
.g-rail{position:relative;height:1px;background:var(--line-2);margin-top:1.4rem}
.g-rail span{position:absolute;left:0;top:-1px;height:3px;background:var(--gold);
  border-radius:2px;transition:transform .25s var(--ease);transform-origin:left;
  width:100%;transform:scaleX(0)}
.g-strip{
  display:flex;gap:clamp(.9rem,2vw,1.6rem);
  overflow-x:auto;overscroll-behavior-x:contain;
  scroll-snap-type:x proximity;
  padding-inline:var(--gutter);padding-bottom:1.2rem;
  scrollbar-width:none;
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 4%,#000 96%,transparent);
          mask-image:linear-gradient(90deg,transparent,#000 4%,#000 96%,transparent);
}
.g-strip::-webkit-scrollbar{display:none}
.g-strip{cursor:grab}
.g-strip.is-dragging{cursor:grabbing;scroll-snap-type:none}
.g-strip.is-dragging img{pointer-events:none}
.g-item{
  position:relative;flex:0 0 auto;scroll-snap-align:center;
  width:clamp(220px,32vw,420px);aspect-ratio:4/5;
  border-radius:var(--r);overflow:hidden;background:var(--ink-2);
}
.g-item img{width:100%;height:100%;object-fit:cover;transition:transform 1.1s var(--ease)}
.g-item:hover img{transform:scale(1.05)}
.g-item::after{
  content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(to top,rgba(7,12,22,.82),transparent 46%);
}
.g-item figcaption{
  position:absolute;left:1rem;right:1rem;bottom:.9rem;z-index:2;
  font-size:.7rem;letter-spacing:.18em;text-transform:uppercase;color:var(--gold-lt);
}
/* every second plate sits lower, so the strip has a rhythm instead of a ruler edge */
.g-item:nth-child(even){margin-top:clamp(1.2rem,3vw,2.8rem)}

/* --------------------------------------------------- cursor-reactive plate */
/* A few degrees of tilt on the pinned chapter plate, following the pointer.
   Desktop pointers only, and the rotation is tiny on purpose: it should read
   as the plate having weight, not as a gimmick. */
@media (hover:hover) and (pointer:fine){
  .journey-media{
    transform:perspective(1400px) rotateX(var(--rx,0deg)) rotateY(var(--ry,0deg));
    transition:transform .5s var(--ease);
    transform-style:preserve-3d;
  }
}
@media (prefers-reduced-motion:reduce){
  .journey-media{transform:none!important}
}

/* ------------------------------------------------------- page transitions */
/* A curtain that closes on navigation and lifts on arrival. It is added by JS
   only when JS is available, so without it every link is an ordinary link. */
.curtain{
  position:fixed;inset:0;z-index:400;background:var(--onyx);
  pointer-events:none;opacity:0;
  transition:opacity .42s var(--ease);
}
.curtain.closing{opacity:1;pointer-events:auto}
@media (prefers-reduced-motion:reduce){.curtain{display:none}}

/* -------------------------------------------------- Switzerland Tourism */
/* The membership mark carried in the original footer. It was once rasterised
   onto the footer's surface colour to save an alpha channel — which was fine
   while that colour was #121215 and became a visible black plate the day the
   footer went navy. The plate is now keyed out (pipeline/src keeps the
   flattened original) and the mark sits on whatever is behind it. */
.st-badge{display:inline-block;margin-top:1.8rem;max-width:270px;opacity:.9;
  transition:opacity .4s var(--ease)}
.st-badge:hover{opacity:1}
.st-badge img{width:100%;height:auto}

/* ------------------------------------------- service pages: own identity */
/* Each vertical already owns a colour on the homepage chapters. The service
   page picks the same one up, so arriving there feels like walking further
   into that chapter rather than landing on a generic template.
   The wash sits UNDER the scrim, so it tints the picture without touching the
   contrast the headline relies on. */
.subhero[data-vertical]{--tint:var(--gold)}

/* One wash for every service page, not nine tints. The chapter is identified
   by its photograph, its number and its name — it does not also need its own
   hue, and nine hues is what stopped the set reading as one house. */
.subhero[data-vertical] .subhero-media::after{
  content:"";position:absolute;inset:0;z-index:2;pointer-events:none;
  background:var(--wash-soft);
}
/* a gold hairline along the foot of the hero */
.subhero[data-vertical]::after{
  content:"";position:absolute;left:0;bottom:0;height:2px;width:min(220px,32vw);z-index:3;
  background:linear-gradient(90deg,var(--gold),transparent);
}

/* The practice notes get their own numerals, hollow, the way the homepage
   chapters are numbered. It ties the two levels of the site together. */
.notes{counter-reset:note}
.note{counter-increment:note;position:relative;overflow:hidden}
.note::after{
  content:counter(note,decimal-leading-zero);
  position:absolute;right:-.04em;bottom:-.28em;
  font-family:var(--font-display);font-size:clamp(3.4rem,7vw,5.6rem);line-height:.8;
  color:transparent;-webkit-text-stroke:1px rgba(244,240,232,.075);
  pointer-events:none;user-select:none;
}
.note > *{position:relative;z-index:1}

/* the service list carries the chapter colour on its index numerals */
.svc-list{--tint:var(--gold)}
.svc-list li:hover::before{color:var(--tint)}

/* ------------------------------------------------------- motion control */
/* WCAG 2.2.2 Pause, Stop, Hide is a Level A requirement: anything that moves
   automatically for more than five seconds needs a mechanism to stop it, and
   every background clip on this site loops indefinitely. prefers-reduced-motion
   covers the visitors who have set it at OS level; this covers everyone else,
   which is what the criterion actually asks for. The choice is remembered. */
/* Lives in the footer, not floating over the page. WCAG 2.2.2 still needs a
   way to stop the background clips, but it does not need a badge parked in
   the corner of every screen. */
.motion-toggle{
  display:inline-flex;align-items:center;gap:.5rem;
  padding:.4rem 0;border:0;background:none;cursor:pointer;
  color:var(--muted);font-family:var(--font-body);
  font-size:.76rem;letter-spacing:.02em;
  transition:color .35s var(--ease);
}
.motion-toggle:hover,.motion-toggle:focus-visible{color:var(--gold-lt)}
.motion-toggle svg{width:13px;height:13px;flex:none}
.motion-toggle .mt-play{display:none}
.motion-toggle[aria-pressed="true"] .mt-pause{display:none}
.motion-toggle[aria-pressed="true"] .mt-play{display:block}
.motion-toggle[aria-pressed="true"]{color:var(--gold-lt);border-color:var(--gold-line);opacity:.9}
@media (max-width:600px){
  .motion-toggle .mt-label{display:none}
  .motion-toggle{padding:.6rem}
}

/* everything the control has to actually stop */
body.motion-off .marquee-track{animation:none}
body.motion-off .foil{animation:none;background-position:34% 0}
body.motion-off .jm-layer.on img,
body.motion-off .jm-layer.on video{animation:none}
body.motion-off .hero-tag span{animation:none;transform:scaleX(1)}
body.motion-off .journey-media{transform:none!important}
/* the stills underneath carry the sections while the clips are stopped */
body.motion-off .hero-media video,
body.motion-off .subhero-media video,
body.motion-off .band-media video,
body.motion-off .sec-media video,
body.motion-off .cta-media video,
body.motion-off .acc__media video{opacity:0}
@media (prefers-reduced-motion:reduce){.motion-toggle{display:none}}

/* A heading that exists for structure but is not shown. Used where a section
   is obvious to the eye but would otherwise leave a gap in the heading
   outline, which is what a screen reader navigates by. */
.sr-only{
  position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0;
}
