/* ============================================================
   NEXT — design tokens
   ============================================================ */
:root{
  --brand:#33CCFF;
  --radius:2px;
  --maxw:1220px;
  --gutter:clamp(20px,5vw,64px);
  --ff: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --ease: cubic-bezier(.22,.61,.36,1);
  --ease-out: cubic-bezier(.16,1,.3,1);

  /* Type scale — one ratio, so headings, body and labels read as a system */
  --t-display: clamp(2.1rem, 4.4vw, 3.55rem);
  --t-h1:      clamp(1.95rem, 3.9vw, 3.1rem);
  --t-h2:      clamp(1.55rem, 2.7vw, 2.35rem);
  --t-h3:      1.1875rem;
  --t-lede:    clamp(1.05rem, 1.45vw, 1.2rem);
  --t-body:    1rem;
  --t-small:   0.875rem;
  --t-label:   0.6875rem;

  /* Spacing rhythm */
  --sp-section: clamp(76px, 8.5vw, 124px);
  --sp-tight:   clamp(52px, 6vw, 80px);
}
/* Light (default) */
:root, [data-theme="light"]{
  /* A distinctly blue light theme, not tinted paper. Ink, muted text and the
     accent are all darkened enough to clear AA on the deepest band (--bg3). */
  --bg:#e9f2fd;
  --bg2:#dceaf8;
  --bg3:#cde0f3;
  --ink:#06131f;
  --ink2:#20394a;
  --muted:#425c76;
  --line:#bed6ea;
  --line2:#9dbcd7;
  --accent:#0a6595;
  --onbrand:#04222e;
  --shadow:0 1px 2px rgba(6,19,31,.06), 0 12px 32px -18px rgba(6,19,31,.28);
  --grid:rgba(10,45,85,.075);
  color-scheme:light;
}
[data-theme="dark"]{
  --bg:#070c11;
  --bg2:#0c141b;
  --bg3:#121d26;
  --ink:#e9f2f8;
  --ink2:#c2d2de;
  --muted:#8ba0b0;
  --line:#1b2731;
  --line2:#28384555;
  --accent:#5fd8ff;
  --onbrand:#04222e;
  --shadow:0 1px 2px rgba(0,0,0,.5), 0 20px 46px -24px rgba(0,0,0,.9);
  --grid:rgba(233,242,248,.05);
  color-scheme:dark;
}
@media (prefers-color-scheme:dark){
  [data-theme="auto"]{
    --bg:#070c11; --bg2:#0c141b; --bg3:#121d26;
    --ink:#e9f2f8; --ink2:#c2d2de; --muted:#8ba0b0;
    --line:#1b2731; --line2:#28384555;
    --accent:#5fd8ff; --onbrand:#04222e;
    --shadow:0 1px 2px rgba(0,0,0,.5), 0 20px 46px -24px rgba(0,0,0,.9);
    --grid:rgba(233,242,248,.05);
    color-scheme:dark;
  }
}

/* ============================================================
   Base
   ============================================================ */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0; background:var(--bg); color:var(--ink);
  font-family:var(--ff); font-size:var(--t-body); line-height:1.62;
  font-synthesis-weight:none;
  -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility;
  transition:background .35s var(--ease), color .35s var(--ease);
  overflow-x:hidden;
}
img,svg{max-width:100%}
a{color:var(--accent); text-decoration:none}
a:hover{text-decoration:underline; text-underline-offset:3px}
h1,h2,h3,h4{margin:0; font-weight:300; letter-spacing:-.024em; line-height:1.06; color:var(--ink); text-wrap:balance}
h3{letter-spacing:-.012em}
/* Figures line up in columns and don't jitter while counting */
.heroMeta dd, .market .code{font-variant-numeric:tabular-nums}
p{margin:0 0 1.1em}
:focus-visible{outline:2px solid var(--brand); outline-offset:3px; border-radius:2px}
.skip{position:absolute;left:-9999px;top:0;background:var(--brand);color:var(--onbrand);padding:10px 18px;z-index:200}
.skip:focus{left:12px;top:12px}

.wrap{max-width:var(--maxw); margin-inline:auto; padding-inline:var(--gutter)}
.eyebrow{
  font-size:var(--t-label); letter-spacing:.2em; text-transform:uppercase;
  color:var(--muted); font-weight:600; display:flex; align-items:center; gap:10px; margin:0 0 22px;
}
.eyebrow::before{
  content:""; width:0;height:0;
  border-left:5px solid transparent;border-right:5px solid transparent;
  border-bottom:8px solid var(--brand); flex:none;
}
.lede{font-size:var(--t-lede); line-height:1.6; color:var(--ink2); font-weight:300; max-width:60ch; text-wrap:pretty}
h1 + .lede, h2 + .lede, h3 + .lede{margin-top:18px}
.muted{color:var(--muted)}
.rule{height:1px;background:var(--line);border:0;margin:0}
section{padding-block:var(--sp-section)}
.tight{padding-block:var(--sp-tight)}
.alt{background:var(--bg2)}

/* Placeholder marker — content to be confirmed */
.ph{
  border-bottom:1px dotted color-mix(in srgb, var(--muted) 42%, transparent);
  text-decoration:none;
}
body.hide-ph .ph{border-bottom:0}

/* ============================================================
   Header
   ============================================================ */
header.site{
  position:sticky; top:0; z-index:100;
  background:color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter:saturate(140%) blur(14px);
  border-bottom:1px solid var(--line);
}
.bar{display:flex; align-items:center; gap:22px; height:66px}
.brand{display:flex; align-items:center; gap:11px; color:var(--brand); flex:none}
.brand svg{height:21px; width:auto; display:block}
.brand:hover{text-decoration:none}

/* The full lockup: the NEXT mark plus the name it stands for.
   The name is LIVE TEXT, not part of the artwork. That is what lets it follow
   the theme — the supplied logo sets the name in black, which would disappear
   on the dark ground, and a flat image would need two copies and still be soft
   on a retina screen. As text it also puts the full company name on every page
   as real, selectable content. It is set in the site face, so it is very close
   to the original artwork but not a glyph-for-glyph match. */
.brandName{
  display:none; flex-direction:column;
  font-size:10px; line-height:1.18; letter-spacing:.004em;
  color:var(--ink); font-weight:400; white-space:nowrap;
  transition:color .35s var(--ease);
}
.brandName b{color:var(--brand); font-weight:400}
.brandRule{display:none; width:1px; align-self:stretch; background:var(--line); margin-block:3px}
/* Below this the header has to hold the mark and the menu button, so the name
   steps aside and the mark alone carries it. */
@media (min-width:760px){
  .brandName{display:flex}
  .brandRule{display:block}
}
nav.main{margin-left:auto; display:flex; gap:4px; align-items:center}
nav.main a{
  color:var(--ink2); font-size:13.5px; letter-spacing:.01em; padding:8px 12px;
  border-radius:var(--radius); position:relative; transition:color .18s var(--ease);
}
nav.main a:hover{color:var(--ink); text-decoration:none}
nav.main a::after{
  content:""; position:absolute; left:12px; right:12px; bottom:2px; height:1px;
  background:var(--brand); transform:scaleX(0); transform-origin:left;
  transition:transform .3s var(--ease);
}
nav.main a:hover::after{transform:scaleX(1)}
nav.main a[aria-current="page"]{color:var(--ink); font-weight:500}
nav.main a[aria-current="page"]::after{transform:scaleX(1)}

/* The About item carries the delta from the wordmark. Drawn with borders
   rather than a text glyph (Δ renders as an outlined letter in the body
   font and would not match the solid mark), and hung on ::before because
   ::after is already the hover underline. */
nav.main a.delta, .fgrid a.delta{display:inline-flex; align-items:center; gap:7px}
nav.main a.delta::before, .fgrid a.delta::before{
  content:""; width:0; height:0; flex:none;
  border-left:4px solid transparent; border-right:4px solid transparent;
  border-bottom:7px solid var(--brand);
}

/* The eXcellence item picks out its X the way the header lockup does.
   <b> would otherwise bold it; only the colour should change. */
nav.main a b, .fgrid a b{color:var(--brand); font-weight:inherit}

.icobtn{
  width:36px;height:36px;flex:none;display:grid;place-items:center;
  background:transparent;border:1px solid var(--line);border-radius:var(--radius);
  color:var(--ink2);cursor:pointer;transition:.2s var(--ease);
}
.icobtn:hover{border-color:var(--line2); color:var(--ink)}
.icobtn svg{width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}

#menuBtn{display:none}
@media (max-width:900px){
  nav.main{
    position:fixed; inset:66px 0 auto 0; flex-direction:column; align-items:stretch; gap:0;
    background:var(--bg); border-bottom:1px solid var(--line); padding:8px var(--gutter) 20px;
    transform:translateY(-120%); transition:transform .38s var(--ease); margin-left:0;
  }
  nav.main.open{transform:translateY(0)}
  nav.main a{padding:14px 0; font-size:16px; border-bottom:1px solid var(--line)}
  nav.main a::after{display:none}
  /* The underline indicator is hidden on mobile, so mark the current page in colour */
  nav.main a[aria-current="page"]{color:var(--brand)}
  #menuBtn{display:grid; margin-left:auto}
}

/* ============================================================
   Hero
   ============================================================ */
/* The hero follows the page theme. Only two extra tokens are needed: a soft
   glow behind the particle field and an edge vignette, each per theme. */
.hero{
  --heroGlow:#cfe4fa;               /* light: cool tint behind the stars */
  --heroVig:rgba(233,242,253,.60);  /* light: edges fade to paper */
  position:relative; overflow:hidden;
  background:radial-gradient(120% 80% at 50% 20%, var(--heroGlow) 0%, transparent 62%), var(--bg);
  padding-block:0 clamp(54px,8vw,92px);
}
[data-theme="dark"] .hero{ --heroGlow:#0e1c2b; --heroVig:rgba(7,12,17,.72); }
@media (prefers-color-scheme:dark){
  [data-theme="auto"] .hero{ --heroGlow:#0e1c2b; --heroVig:rgba(7,12,17,.72); }
}
.hero::after{ /* vignette */
  content:""; position:absolute; inset:0; pointer-events:none;
  background:radial-gradient(110% 78% at 50% 42%, transparent 52%, var(--heroVig) 100%);
}
.hero .wrap{position:relative; z-index:2}

/* Hero wordmark — the logo itself, set once and left alone.
   This replaced a canvas particle field. The mark carries the delta under the
   X, so it is the company logo rather than type set to look like it. Its cyan
   follows the same two-value treatment as the rest of the brand: the bright
   #5fd8ff holds easily on the dark ground, but only reaches 1.66:1 on the pale
   light one, so light steps down to a deeper cyan that still reads. */
.heroMark{
  --markInk:#127fab;
  position:relative; z-index:1;
  width:min(620px, 72%); margin:0 auto;
  padding-block:clamp(34px,7vh,86px) clamp(10px,2vw,22px);
  color:var(--markInk);
  animation:markIn 1.1s var(--ease-out) both;
}
[data-theme="dark"] .heroMark{ --markInk:#5fd8ff; }
@media (prefers-color-scheme:dark){ [data-theme="auto"] .heroMark{ --markInk:#5fd8ff; } }
.heroMark svg{display:block; width:100%; height:auto}
@keyframes markIn{
  from{opacity:0; transform:translateY(14px)}
  to  {opacity:1; transform:none}
}
@media (prefers-reduced-motion:reduce){
  .heroMark{animation:none}
}

.heroInner{text-align:center; display:flex; flex-direction:column; align-items:center}
.acronym{
  display:flex; flex-wrap:wrap; justify-content:center; gap:6px 18px; font-size:clamp(10px,1.25vw,12.5px);
  letter-spacing:.2em; text-transform:uppercase; color:var(--muted); font-weight:600; margin:0 0 30px;
}
.acronym span{opacity:0; transform:translateY(8px); animation:rise .6s var(--ease) forwards}
.acronym b{color:var(--ink); font-weight:700}
@keyframes rise{to{opacity:1;transform:none}}
.hero h1{
  font-size:var(--t-display); max-width:19ch; font-weight:300; margin-bottom:22px;
}
.hero h1 em{font-style:normal; color:var(--accent)}
.hero .lede{max-width:58ch; margin:0 auto 34px}
.btn{
  display:inline-flex; align-items:center; gap:10px; padding:13px 22px;
  border-radius:var(--radius); font-size:14px; font-weight:500; letter-spacing:.01em;
  border:1px solid var(--brand); background:var(--brand); color:var(--onbrand);
  transition:.22s var(--ease); cursor:pointer;
}
.btn:hover{text-decoration:none; transform:translateY(-1px); box-shadow:0 8px 22px -10px var(--brand)}
.btn.ghost{background:transparent; color:var(--ink); border-color:var(--edge)}
.btn.ghost:hover{border-color:var(--brand); box-shadow:none}
.btn svg{width:15px;height:15px;stroke:currentColor;fill:none;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}

.heroMeta{
  display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); gap:1px; width:100%;
  background:var(--line); border:1px solid var(--line); margin-top:clamp(40px,6vw,72px); text-align:left;
}
.heroMeta div{background:var(--bg); padding:20px 22px}
.heroMeta dt{font-size:10.5px; letter-spacing:.18em; text-transform:uppercase; color:var(--muted); font-weight:600; margin-bottom:7px}
.heroMeta dd{margin:0; font-size:17px; font-weight:300; color:var(--ink)}

/* ============================================================
   Reveal
   ============================================================ */
/* Hidden only when JS is present — without JS everything stays visible */
.js .rv{opacity:0; transform:translateY(18px); transition:opacity .7s var(--ease), transform .7s var(--ease)}
.js .rv.in{opacity:1; transform:none}
@media (prefers-reduced-motion:reduce){
  .js .rv{opacity:1;transform:none;transition:none}
  .acronym span{opacity:1;transform:none;animation:none}
  *{scroll-behavior:auto !important}
}

/* ============================================================
   Generic blocks
   ============================================================ */
.secHead{display:grid; grid-template-columns:1fr; gap:14px; margin-bottom:clamp(34px,5vw,56px); max-width:70ch}
.secHead h2{font-size:var(--t-h2)}

.cards{display:grid; gap:1px; background:var(--line); border:1px solid var(--line)}
.cards.c2{grid-template-columns:repeat(2,minmax(0,1fr))}
.cards.c3{grid-template-columns:repeat(3,minmax(0,1fr))}
.cards.c4{grid-template-columns:repeat(4,minmax(0,1fr))}
@media(max-width:1100px){.cards.c4{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:620px){.cards.c4{grid-template-columns:repeat(1,minmax(0,1fr))}}
/* Compact variant: many small cards rather than a few generous ones.
   The grid's own background is the page colour rather than the line colour,
   so an incomplete last row leaves page-coloured space, not a lit panel;
   the dividers are drawn by each card's own 1px shadow into the gap. */
.cards.compact{background:var(--bg)}
.cards.compact > .card{box-shadow:1px 1px 0 0 var(--line)}
.cards.compact .card{padding:clamp(16px,1.8vw,22px)}
.cards.compact .card h3{font-size:15px; margin-bottom:7px; line-height:1.32}
.cards.compact .card p{font-size:13px; line-height:1.55}
.cards.compact .card ul{margin-top:10px}
.cards.compact .card ul li{font-size:12.5px; margin-bottom:5px; line-height:1.45}
/* The one card that is a statement rather than a tool. */
.cardAccent{background:var(--bg3)}
.alt .cardAccent{background:var(--bg3)}
.cardAccent h3{color:var(--brand)}
.cardAccent::before{transform:scaleY(1)}
@media(max-width:900px){.cards.c3{grid-template-columns:repeat(1,minmax(0,1fr))}}
@media(max-width:680px){.cards.c2{grid-template-columns:repeat(1,minmax(0,1fr))}}
.card{background:var(--bg); padding:clamp(24px,3vw,34px); position:relative; transition:background .3s var(--ease)}
.alt .card{background:var(--bg2)}
.card:hover{background:var(--bg3)}
.card .num{
  font-size:11px; letter-spacing:.16em; color:var(--brand); font-weight:700; display:block; margin-bottom:16px;
}
.card h3{font-size:var(--t-h3); font-weight:500; margin-bottom:10px}
.card p{font-size:14.5px; color:var(--muted); margin:0; line-height:1.65}
.card ul{margin:14px 0 0; padding:0; list-style:none}
.card ul li{font-size:13.5px; color:var(--muted); padding-left:16px; position:relative; margin-bottom:6px}
.card ul li::before{content:""; position:absolute; left:0; top:9px; width:5px;height:5px; background:var(--brand); clip-path:polygon(50% 0,100% 100%,0 100%)}


/* Split rows */
.split{display:grid; grid-template-columns:minmax(0,.85fr) minmax(0,1.15fr); gap:clamp(26px,5vw,72px); align-items:start}
@media(max-width:860px){.split{grid-template-columns:1fr}}

/* Timeline / process */
.steps{border-top:1px solid var(--line)}
.step{display:grid; grid-template-columns:64px 1fr; gap:clamp(16px,3vw,32px); padding:clamp(22px,3vw,30px) 0; border-bottom:1px solid var(--line); align-items:start}
.step .k{font-size:12px; letter-spacing:.14em; color:var(--brand); font-weight:700; padding-top:5px}
.step h3{font-size:19px; font-weight:500; margin-bottom:8px}
.step p{margin:0; color:var(--muted); font-size:14.5px; max-width:70ch}
@media(max-width:560px){.step{grid-template-columns:1fr; gap:6px}}
@media(max-width:980px){.markets{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:520px){.markets{grid-template-columns:1fr}}

/* Markets */
.markets{display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:1px; background:var(--line); border:1px solid var(--line)}
.market{background:var(--bg); padding:clamp(24px,3vw,32px)}
.alt .market{background:var(--bg2)}
.market .code{font-size:clamp(30px,4vw,42px); font-weight:200; color:var(--brand); letter-spacing:-.02em; line-height:1}
.market h3{font-size:16px; font-weight:500; margin:14px 0 6px}
.market p{font-size:13.5px; color:var(--muted); margin:0}

/* ---------- Org chart (Delta) ----------
   Drawn with borders rather than SVG so every label stays real, selectable
   text that reflows. The connectors are pseudo-elements: a trunk down from
   the top box, stubs down to each team, and one rail spanning from the
   centre of the first column to the centre of the last. That span is
   computed from the column count and the gap, so it lands on the stubs
   exactly instead of being eyeballed.

   The team lead hangs off the side of the trunk rather than sitting under
   it — the usual way a role that sits beside the line of command rather
   than beneath it is drawn. Narrow screens have no room for that, so below
   760px the box drops back under the trunk and centres.

   Below 900px the seven teams can no longer sit in a row, and a rail drawn
   across a wrapped grid would cut through the middle of it — so the rail
   and stubs are dropped there and the teams become a plain grid. */
.org{--orgGap:10px; --orgArm:46px; --orgDrop:54px; --orgStub:26px; --orgJoin:14px;
     --orgTier:0px; --orgSplitStub:22px; --orgNoteMax:132px; --orgNoteBlock:27px; --orgCols:10}
.orgLead{display:flex; flex-direction:column; align-items:center}
.orgNode{
  background:var(--bg2); border:1px solid var(--line); border-radius:var(--radius);
  padding:18px 26px; text-align:center; min-width:min(260px,80vw);
}
.orgNode h3{font-size:16px; font-weight:500; margin:0 0 4px}
.orgNode p{font-size:12.5px; color:var(--accent); letter-spacing:.04em; margin:0}

/* the trunk below the top box; the lead is placed against it */
.orgStem{position:relative; width:100%; display:flex; justify-content:center}
.orgStem::before{
  content:""; position:absolute; left:50%; top:0; width:1px; height:100%;
  background:var(--rule);
}
@media(min-width:761px){
  .orgStem{height:112px}
  .orgAide{
    position:absolute; top:50%; left:calc(50% + var(--orgArm));
    transform:translateY(-50%); margin:0; white-space:nowrap;
  }
  .orgAide::before{
    content:""; position:absolute; left:calc(var(--orgArm) * -1); top:50%;
    width:var(--orgArm); height:1px; background:var(--rule);
  }
}
@media(max-width:760px){
  .orgStem{padding-top:44px}
  .orgStem::before{height:44px}
}

.orgTeams{
  list-style:none; margin:0; padding:0; position:relative;
  display:grid; grid-template-columns:repeat(var(--orgCols),minmax(0,1fr)); gap:var(--orgGap);
  align-items:start;
}
/* The rail sits where the trunk ends. The stubs below it are deliberately
   short of it — they hang from above each box rather than joining the rail,
   which keeps the row reading as seven separate teams instead of one comb.
   --orgDrop is rail-to-box; --orgStub is how much of that the tick fills. */
.orgTeams::after{
  content:""; position:absolute; top:0; height:1px; background:var(--rule);
  left:calc((100% - (var(--orgCols) - 1) * var(--orgGap)) / (var(--orgCols) * 2));
  right:calc((100% - (var(--orgCols) - 1) * var(--orgGap)) / (var(--orgCols) * 2));
}
/* Two boxes per team: the title is the chart node, the roster is its own
   panel beneath. The li itself is just the column that holds them, so the
   stub above lands on the title box and nothing else. */
.orgTeam{
  position:relative; margin-top:var(--orgDrop);
  display:flex; flex-direction:column; gap:var(--orgJoin);
}
.orgTitle{
  background:var(--bg2); border:1px solid var(--line); border-radius:var(--radius);
  padding:11px 9px; text-align:center;
  font-size:13px; font-weight:500; color:var(--ink); line-height:1.3;
  text-wrap:balance;
}
.orgRoster{
  position:relative;
  background:var(--bg); border:1px solid var(--line); border-radius:var(--radius);
  padding:11px 8px;
}
/* Names never wrap, so a box with a long one grows past its column rather
   than breaking the name in two. Only the two longest names trigger this;
   the tier stagger keeps the space beside them clear. */
@media(min-width:1301px){
  /* Boxes keep to their track. With ten columns across there is no slack
     for a box to grow into, so the two longest names wrap on a 1440px
     laptop and sit on one line from about 1600px up. */
  /* the label keeps wrapping: it must not be what widens the box */
  .orgNote{max-width:var(--orgNoteMax)}
}
/* a team can hold more than one roster: the plain one and a labelled
   sub-function beside it. Only the last stretches, so the columns still
   bottom-align across the row. */
/* the title box is the node; this joins its roster to it, the same way
   every other pair in the chart is joined */
.orgRoster::before{
  content:""; position:absolute; left:50%; width:1px;
  top:calc(var(--orgJoin) * -1); height:var(--orgJoin);
  background:var(--rule);
}
.orgTeam::before{
  content:""; position:absolute; left:50%; width:1px;
  top:calc(var(--orgStub) * -1); height:var(--orgStub);
  background:var(--rule);
}
.orgPeople{list-style:none; margin:0; padding:0; display:grid; gap:0; width:100%}
.orgPeople li{
  position:relative; padding:4px 0;
  font-size:11px; color:var(--ink2); text-align:center; line-height:1.35;
  text-wrap:balance;
}
/* a short centred rule between names, so a name that wraps onto two lines
   still reads as one person rather than two */
.orgPeople li + li::before{
  content:""; position:absolute; top:0; left:50%; transform:translateX(-50%);
  width:34px; height:1px; background:var(--line);
}
/* a specialism attached to one person, or to the team as a whole */
/* the label on a sub-function roster, above the people in it */
.orgNote{
  display:block; font-size:9.5px; line-height:1.35; color:var(--muted);
  letter-spacing:.06em; text-transform:uppercase; font-weight:600;
  text-align:center; text-wrap:balance;
  margin:0 0 7px; padding-bottom:6px; border-bottom:1px solid var(--line);
}

/* A team with two sub-functions splits into branches side by side, so the
   pair is two columns wide and overflows half a column into each neighbour.
   That only works because alternate teams are dropped a tier lower on a
   longer stub: a wide box slides into the vertical gap beside its neighbour
   instead of colliding with it. Tiers are assigned so that no two teams
   whose footprints overlap sit at the same depth. */
/* Kept at 0: with the chart at its full width every team has its own track
   and nothing overflows into a neighbour, so no stagger is needed. Raise this
   if a roster ever grows enough to make boxes collide — the ?edit org panel
   reports that the moment it happens. */
@media(min-width:1301px){ .org{--orgTier:0px} }

.orgTeam--deep{margin-top:calc(var(--orgDrop) + var(--orgTier))}
.orgTeam--deep::before{
  top:calc((var(--orgStub) + var(--orgTier)) * -1);
  height:calc(var(--orgStub) + var(--orgTier));
}

.orgTeam--split > .orgTitle{position:relative}
/* title down to the branch rail */
.orgTeam--split > .orgTitle::after{
  content:""; position:absolute; left:50%; top:100%;
  width:1px; height:var(--orgJoin); background:var(--rule);
}
/* The chart is a diagram, not prose, so it is allowed wider than the text
   column it sits in. Nine units across: the teams that need two get two. */
@media(min-width:1301px){ .org{width:min(96vw,1400px); margin-left:calc(50% - min(48vw,700px))} }
.orgTeam--split{grid-column:span 2}
.orgTeam--wide{grid-column:span 2}
.orgTeam--span4{grid-column:span 4}
/* a team with three branches: three columns, and a rail from the centre of
   the first to the centre of the last (1/6 in from each edge) */
.orgTeam--span3{grid-column:span 3}
.orgTeam--span3 > .orgBranches{grid-template-columns:1fr 1fr 1fr}
.orgTeam--span3 > .orgBranches::before{left:calc(100% / 6); right:calc(100% / 6)}
/* a sub-team that splits again: its own rail, one level further down */
.orgBranch > .orgBranches{width:100%}
/* ...and the line that reaches it. At team level the vertical into the rail
   is drawn off the title; a nested rail hangs under a roster or a sub-team
   node instead, so it draws its own. */
/* Side by side, a plain roster sits higher than a labelled one by exactly the
   label block (text, rule and gap). Drop it by that amount so the first name on
   each side shares a row while the box stays the size of its names — Dona beside Amal, Rifa beside Alphin. Desktop only;
   stacked boxes have nothing to align with. */
@media(min-width:1301px){
  .orgBranches:has(.orgNote) > .orgBranch > .orgRoster:first-child:not(:has(.orgNote)):not(.orgRoster--lead){
    margin-top:var(--orgNoteBlock);
  }
  /* ...and the drop from the rail reaches the lower box */
  .orgBranches:has(.orgNote) > .orgBranch:not(:has(> .orgRoster--lead)):has(> .orgRoster:first-child > .orgPeople:first-child)::before{
    height:calc(var(--orgSplitStub) + var(--orgNoteBlock));
  }
}
/* Two rows the whole chart keys to. The leads (Adheena, Sidharth) share one
   row, and every other roster starts below it, whatever its team's depth.
   Title, sub-node and lead boxes are given fixed heights so the rows are
   arithmetic rather than measurement: the lead row sits one sub-node below
   the titles, the people row one lead box below that. Desktop only. */
@media(min-width:1301px){
  .org{--orgT:58px; --orgS:33px; --orgA:47px;
       --orgLeadDrop:calc(var(--orgSplitStub) + var(--orgS) + var(--orgJoin) + var(--orgSplitStub));
       --orgPeopleDrop:calc(var(--orgLeadDrop) + var(--orgA) + var(--orgSplitStub) + var(--orgJoin))}
  .orgTitle{min-height:var(--orgT); display:flex; align-items:center; justify-content:center}
  .orgSub{min-height:var(--orgS); display:flex; align-items:center; justify-content:center}
  .orgRoster--lead{min-height:var(--orgA)}
  /* a lead hanging straight off a team title (Sidharth) */
  .orgTeam > .orgTitle + .orgRoster--lead{margin-top:var(--orgLeadDrop)}
  .orgTeam > .orgTitle + .orgRoster--lead::before{top:calc(var(--orgLeadDrop) * -1); height:var(--orgLeadDrop)}
  /* ...and when that lead box carries a label, it rises by the label block so
     the name itself shares the row with the other lead */
  .orgTeam > .orgTitle + .orgRoster--lead:has(.orgNote){margin-top:calc(var(--orgLeadDrop) - var(--orgNoteBlock))}
  .orgTeam > .orgTitle + .orgRoster--lead:has(.orgNote)::before{top:calc((var(--orgLeadDrop) - var(--orgNoteBlock)) * -1); height:calc(var(--orgLeadDrop) - var(--orgNoteBlock))}
  /* a plain roster hanging straight off a team title (Project Management, Finance) */
  .orgTeam > .orgTitle + .orgRoster:not(.orgRoster--lead){margin-top:var(--orgPeopleDrop)}
  .orgTeam > .orgTitle + .orgRoster:not(.orgRoster--lead)::before{top:calc(var(--orgPeopleDrop) * -1); height:var(--orgPeopleDrop)}
  /* branches straight off a title (Merchandising): the sub-nodes sit level with
     Order management; the rosters under them, and a plain roster beside them,
     drop to the people row */
  .orgTeam--span3 > .orgBranches > .orgBranch > .orgSub + .orgRoster{margin-top:calc(var(--orgPeopleDrop) - var(--orgSplitStub) - var(--orgS) - var(--orgJoin))}
  .orgTeam--span3 > .orgBranches > .orgBranch > .orgSub + .orgRoster::before{
    top:calc((var(--orgPeopleDrop) - var(--orgSplitStub) - var(--orgS)) * -1);
    height:calc(var(--orgPeopleDrop) - var(--orgSplitStub) - var(--orgS));
  }
  .orgTeam--span3 > .orgBranches > .orgBranch > .orgRoster:first-child{margin-top:calc(var(--orgPeopleDrop) - var(--orgSplitStub))}
  .orgTeam--span3 > .orgBranches > .orgBranch:has(> .orgRoster:first-child)::before{height:var(--orgPeopleDrop)}
  /* beneath a lead, the next roster lands on the people row */
  .orgRoster--lead + .orgRoster{margin-top:calc(var(--orgSplitStub) + var(--orgJoin) - var(--orgJoin))}
  .orgRoster--lead + .orgRoster::before{top:calc((var(--orgSplitStub) + var(--orgJoin)) * -1); height:calc(var(--orgSplitStub) + var(--orgJoin))}
  /* a branch beside a lead's branch: its box drops to the people row and the rail reaches it */
  .orgBranches:has(> .orgBranch > .orgRoster--lead) > .orgBranch > .orgRoster:first-child:not(.orgRoster--lead){margin-top:calc(var(--orgA) + var(--orgSplitStub) + var(--orgJoin))}
  .orgBranches:has(> .orgBranch > .orgRoster--lead) > .orgBranch:not(:has(> .orgRoster--lead))::before{height:calc(var(--orgSplitStub) + var(--orgA) + var(--orgSplitStub) + var(--orgJoin))}
  /* branches hanging off a sub-node with no lead between (Order management) */
  .orgBranch > .orgSub + .orgBranches:not(:has(.orgRoster--lead)){margin-top:calc(var(--orgPeopleDrop) - var(--orgSplitStub) - var(--orgS) - var(--orgJoin))}
  .orgBranch > .orgSub + .orgBranches:not(:has(.orgRoster--lead))::after{
    top:calc((var(--orgPeopleDrop) - var(--orgSplitStub) - var(--orgS)) * -1);
    height:calc(var(--orgPeopleDrop) - var(--orgSplitStub) * 2 - var(--orgS));
  }
}
.orgBranch > .orgBranches::after{
  content:""; position:absolute; left:50%; width:1px;
  top:calc((var(--orgSplitStub) + var(--orgJoin)) * -1);
  height:var(--orgJoin); background:var(--rule);
}
.orgBranches{
  position:relative; flex:none;
  display:grid; grid-template-columns:1fr 1fr; gap:var(--orgGap);
  align-items:start;
  margin-top:var(--orgSplitStub);
}
/* a sub-team inside a branch: its own node, one step down from the team */
.orgSub{
  background:var(--bg2); border:1px solid var(--line); border-radius:var(--radius);
  padding:8px 9px; text-align:center;
  font-size:11.5px; font-weight:500; color:var(--ink); line-height:1.3; text-wrap:balance;
}
/* the branch rail, spanning the two branch centres */
.orgBranches::before{
  content:""; position:absolute; height:1px; background:var(--rule);
  top:calc(var(--orgSplitStub) * -1); left:25%; right:25%;
}
.orgBranch{position:relative; display:flex; flex-direction:column; gap:var(--orgJoin)}
/* rail down to each branch */
.orgBranch::before{
  content:""; position:absolute; left:50%; width:1px;
  top:calc(var(--orgSplitStub) * -1); height:var(--orgSplitStub);
  background:var(--rule);
}
/* the branch drop already lands on the first box; its own join would double it */
.orgBranch > :first-child::before{display:none}
.orgSub + .orgRoster::before,
.orgRoster + .orgRoster::before{display:block}

@media(max-width:1300px){
  /* One column per team, all five still on one row under the rail, so the
     chart keeps its shape down to tablet width. Inside a team everything
     stacks: a split team's branches become a single column of boxes. */
  .org{--orgCols:5; --orgTier:0px}
  /* Column spans are a desktop-only device. Below the breakpoint the grid has
     fewer tracks than a span asks for, and a span wider than the grid does not
     clamp — it mangles every track's width. Each team is one cell here. */
  .orgTeam, .orgTeam--split, .orgTeam--span3, .orgTeam--span4, .orgTeam--wide{grid-column:auto}
  .orgBranches::before, .orgBranches::after, .orgBranch::before,
  .orgTeam--split > .orgTitle::after{display:none}
  .orgTeam--deep{margin-top:var(--orgDrop)}
  .orgTeam--deep::before{top:calc(var(--orgStub) * -1); height:var(--orgStub)}
  /* branches stack like any other pair of boxes once the row breaks up */
  .orgBranches{
    display:flex; flex-direction:column; gap:var(--orgJoin);
    width:auto; margin-left:0; margin-top:var(--orgJoin);
    /* the desktop grid wants align-items:start so columns hang from the top;
       as a stacked column that same value stops every box filling the width */
    align-items:stretch;
  }
  .orgBranch > :first-child::before{display:block}
  .orgTitle{min-height:58px; display:flex; align-items:center; justify-content:center}
}
@media(max-width:900px){
  /* Phones and portrait tablets: a single column, no rail or stubs. */
  .org{--orgCols:1}
  .orgTeams::after, .orgTeam::before{display:none}
  .orgTeam, .orgTeam--deep{margin-top:0}
  .orgTeams{margin-top:30px}
  .orgTitle{min-height:0}
}

/* Roadmap: heading with a status badge beside it, and the "on the horizon"
   chip row. The badge sits on the baseline of the heading on wide screens and
   drops beneath it when there is no room, rather than squeezing the title. */
.secHead--badge{
  grid-template-columns:1fr auto; align-items:start;
  column-gap:20px; max-width:none;
}
.secHead--badge .tag{justify-self:end; white-space:nowrap; margin-top:6px}
@media(max-width:680px){
  .secHead--badge{grid-template-columns:1fr}
  .secHead--badge .tag{justify-self:start}
}
.horizon{margin-top:clamp(30px,4vw,44px)}
.horizon .eyebrow{margin-bottom:16px}
.chips{list-style:none; margin:0; padding:0; display:flex; flex-wrap:wrap; gap:10px}
.chips li{
  font-size:13.5px; color:var(--ink2); line-height:1.4;
  background:var(--bg); border:1px solid var(--line); border-radius:var(--radius);
  padding:10px 14px;
}
.alt .chips li{background:var(--bg2)}

/* Roles / careers */
.role-row{
  display:grid; grid-template-columns:1fr auto; gap:18px; align-items:center;
  padding:22px 0; border-bottom:1px solid var(--line);
}
.role-row:first-child{border-top:1px solid var(--line)}
.role-row h3{font-size:19px; font-weight:500; margin-bottom:6px}
.role-row .meta{font-size:13px; color:var(--muted); display:flex; gap:8px; flex-wrap:wrap}
.role-row .meta span::after{content:"·"; margin-left:8px; color:var(--line2)}
.role-row .meta span:last-child::after{content:""}
.tag{
  font-size:11px; letter-spacing:.12em; text-transform:uppercase; font-weight:600;
  padding:5px 10px; border:1px solid var(--line2); color:var(--muted); border-radius:var(--radius);
}
@media(max-width:560px){.role-row{grid-template-columns:1fr}}

/* Quote / statement band */
.band{background:var(--bg3); border-block:1px solid var(--line)}
.statement{font-size:clamp(21px,3.1vw,33px); font-weight:200; letter-spacing:-.02em; line-height:1.34; max-width:24ch; color:var(--ink)}
.statement b{font-weight:400; color:var(--brand)}

/* Contact */
/* Two columns, not four — a full street address needs the room */
.contactGrid{display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:1px; background:var(--line); border:1px solid var(--line)}
@media(max-width:620px){ .contactGrid{grid-template-columns:1fr} }
.contactGrid > div{background:var(--bg); padding:28px}
.contactGrid dt{font-size:10.5px; letter-spacing:.18em; text-transform:uppercase; color:var(--muted); font-weight:600; margin-bottom:10px}
.contactGrid dd{margin:0; font-size:15.5px; font-weight:300}

/* Footer */
footer.site{border-top:1px solid var(--line); background:var(--bg2); padding-block:clamp(44px,6vw,66px) 28px}
.fgrid{display:grid; grid-template-columns:minmax(0,1.4fr) repeat(auto-fit,minmax(140px,1fr)); gap:clamp(26px,4vw,46px)}
.fgrid h4{font-size:11px; letter-spacing:.18em; text-transform:uppercase; color:var(--muted); font-weight:600; margin-bottom:16px}
.fgrid ul{list-style:none; margin:0; padding:0; display:grid; gap:9px}
.fgrid a{color:var(--ink2); font-size:14px}
.fgrid a:hover{color:var(--brand)}
.fbrand svg{height:19px; color:var(--brand)}
.fbot{display:flex; flex-wrap:wrap; gap:14px; justify-content:space-between; margin-top:clamp(34px,5vw,54px); padding-top:22px; border-top:1px solid var(--line); font-size:12.5px; color:var(--muted)}

/* Prose pages (privacy): a readable measure and spacing for running text,
   which the rest of the site never needs because it is all cards and grids. */
.prose{max-width:72ch}
.prose h2{font-size:var(--t-h3); font-weight:500; margin:clamp(34px,4vw,46px) 0 14px}
.prose > h2:first-child{margin-top:0}
.prose p{font-size:15.5px; line-height:1.72; color:var(--ink2); margin:0 0 14px; text-wrap:pretty}
.prose address{font-style:normal; font-size:15px; line-height:1.7; color:var(--muted); margin:0 0 14px}
.prose code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:.92em; color:var(--ink);
  background:var(--bg2); border:1px solid var(--line); border-radius:4px; padding:1px 5px}
.prose strong{font-weight:600; color:var(--ink)}
.fbot a{color:var(--muted)}
.fbot a:hover{color:var(--brand)}

/* Page headers */
.pagehead{padding-block:clamp(56px,8vw,96px) clamp(30px,4vw,48px); border-bottom:1px solid var(--line); position:relative; overflow:hidden}
.pagehead .wrap{position:relative}
.pagehead h1{font-size:var(--t-h1); margin-bottom:20px; max-width:17ch; position:relative}
/* 17ch suits the short page headlines ("Evidence, not adjectives."). A long
   one hits the cap and shatters into six lines, so it opts into a wider
   measure rather than the cap being raised for every page — that would
   collapse the deliberate two-line headlines elsewhere onto one. */
.pagehead h1.wide{max-width:32ch}

/* ============================================================
   Responsive overrides (kept last so they win)
   ============================================================ */
@media(max-width:980px){ .markets{grid-template-columns:repeat(2,minmax(0,1fr))} }
@media(max-width:560px){ .markets{grid-template-columns:1fr} }
@media(max-width:880px){ .fgrid{grid-template-columns:repeat(2,minmax(0,1fr))} .fgrid > :first-child{grid-column:1 / -1} }
@media(max-width:480px){ .fgrid{grid-template-columns:1fr} }
@media(max-width:400px){ .heroMeta{grid-template-columns:1fr} }

/* ============================================================
   Craft layer — component polish
   ============================================================ */

/* Scroll progress */
.scrollbar{
  position:fixed; top:0; left:0; height:2px; width:100%;
  transform:scaleX(0); transform-origin:0 50%;
  background:linear-gradient(90deg, var(--accent), var(--brand));
  z-index:120; pointer-events:none;
}
.js .scrollbar{transition:transform .12s linear}

/* Header densifies once you leave the top of the page */
header.site{transition:background .3s var(--ease), border-color .3s var(--ease)}
.bar{transition:height .32s var(--ease)}
.is-scrolled .bar{height:56px}
.is-scrolled header.site{
  background:color-mix(in srgb, var(--bg) 94%, transparent);
  border-bottom-color:var(--line2);
}
.brand{transition:transform .32s var(--ease); transform-origin:left center}
.is-scrolled .brand{transform:scale(.93)}

/* Cards lift, and an accent edge draws down the left */
.card{overflow:hidden}
.card::before{
  content:""; position:absolute; left:0; top:0; bottom:0; width:2px;
  background:var(--brand); transform:scaleY(0); transform-origin:50% 0;
  transition:transform .5s var(--ease-out);
}
.card:hover::before{transform:scaleY(1)}
.js .card{transition:background .3s var(--ease), transform .45s var(--ease-out)}
.js .card:hover{transform:translateY(-3px)}
.card .num{transition:letter-spacing .4s var(--ease)}
.card:hover .num{letter-spacing:.26em}

/* Buttons */
.btn{position:relative; overflow:hidden}
.btn svg{transition:transform .34s var(--ease-out)}
.btn:hover svg{transform:translateX(4px)}
.btn.ghost::after{
  content:""; position:absolute; inset:0; background:var(--brand);
  transform:scaleX(0); transform-origin:0 50%; z-index:-1;
  transition:transform .4s var(--ease-out);
}

/* Inline links get a wipe rather than a browser underline */
.lede a, .card p a, main p a:not(.btn){
  text-decoration:none; background-image:linear-gradient(var(--accent),var(--accent));
  background-size:100% 1px; background-repeat:no-repeat; background-position:0 100%;
  transition:background-size .35s var(--ease-out);
}
.lede a:hover, main p a:not(.btn):hover{text-decoration:none; background-size:0% 1px; background-position:100% 100%}

/* Role rows */
.role-row{transition:padding-left .4s var(--ease-out)}
.js .role-row:hover{padding-left:12px}
.role-row h3{transition:color .25s var(--ease)}
.role-row:hover h3{color:var(--accent)}

/* Steps: a rail that fills as the section scrolls past */
.steps{position:relative; --p:0}
.steps::before, .steps::after{
  content:""; position:absolute; left:0; top:0; width:2px; height:100%;
}
.steps::before{background:var(--line)}
.steps::after{
  background:linear-gradient(var(--accent), var(--brand));
  transform:scaleY(var(--p)); transform-origin:50% 0;
  transition:transform .2s linear;
}
.step{padding-left:clamp(18px,3vw,30px)}
.step .k{position:relative}
.step .k::before{
  content:""; position:absolute; left:calc(-1 * clamp(18px,3vw,30px) - 3px); top:8px;
  width:8px; height:8px; background:var(--bg); border:2px solid var(--rule);
  border-radius:50%; transition:border-color .4s var(--ease), background .4s var(--ease);
}
.step.lit .k::before{border-color:var(--brand); background:var(--brand)}
.alt .step .k::before{background:var(--bg2)}
.alt .step.lit .k::before{background:var(--brand)}

.pagehead{position:relative}

/* Footer sign-off */
footer.site .fbrand svg{transition:transform .4s var(--ease-out)}
footer.site .fbrand:hover svg{transform:translateX(3px)}
.fgrid a{position:relative; display:inline-block}
.fgrid a::after{
  content:""; position:absolute; left:0; right:0; bottom:-2px; height:1px; background:var(--brand);
  transform:scaleX(0); transform-origin:0 50%; transition:transform .35s var(--ease-out);
}
.fgrid a:hover{text-decoration:none}
.fgrid a:hover::after{transform:scaleX(1)}

/* ============================================================
   Motion layer
   ============================================================ */

/* Page enter / leave. Without JS nothing here applies. */
.js main{animation:pageIn .6s var(--ease-out) both}
@keyframes pageIn{from{opacity:0; transform:translateY(10px)} to{opacity:1; transform:none}}
.js.leaving{opacity:0; transition:opacity .19s ease-in}

/* Staggered children — index set by JS as --i */
.js .rv{transition-delay:calc(var(--i, 0) * 70ms)}

/* Headline lines rise out of a mask */
.js h1.sr, .js h2.sr{overflow:visible}
.sr .line{display:block; overflow:hidden; padding-bottom:.06em; margin-bottom:-.06em}
.sr .line-i{display:block; will-change:transform}
.js .sr .line-i{transform:translateY(105%); transition:transform .8s var(--ease-out); transition-delay:var(--d,0s)}
.js .sr.in .line-i{transform:none}

/* ---------- Markets globe (Home) ----------
   An orthographic projection centred on 20N 61E, so the Gulf and Kerala
   both sit on the near face. The four Gulf markets are genuinely within
   ~17px of one another at this scale, so they cannot be labelled where
   they sit; leader lines carry each label outward along its true bearing
   and the labels are set outside the sphere. */
.globe{
  width:100%; max-width:560px; margin:0 auto; position:relative;
  /* Canvas colours. Kept here rather than in the script so both themes
     stay in one place; the script reads them and re-reads on theme change. */
  --g-ocean:#b9d4ec; --g-oceanLit:#dcecfa; --g-land:#8fb6d6; --g-landLit:#a9c9e4;
  --g-grid:#7ea6c8; --g-rim:#0a6595; --g-shadow:rgba(10,45,75,.30);
}
[data-theme="dark"] .globe{
  --g-ocean:#0b1b28; --g-oceanLit:#173b55; --g-land:#1e4661; --g-landLit:#2b6285;
  --g-grid:#3a6284; --g-rim:#5fd8ff; --g-shadow:rgba(0,0,0,.55);
}
@media(prefers-color-scheme:dark){[data-theme="auto"] .globe{
  --g-ocean:#0b1b28; --g-oceanLit:#173b55; --g-land:#1e4661; --g-landLit:#2b6285;
  --g-grid:#3a6284; --g-rim:#5fd8ff; --g-shadow:rgba(0,0,0,.55);
}}
.globe svg{width:100%; height:auto; overflow:visible; position:relative; z-index:1}
/* Drag turns the globe. pan-y hands vertical gestures back to the page so
   a thumb can still scroll past it; only horizontal ones reach the script.
   The labels are not interactive, so pointer events go straight through
   them to the container that listens for the drag. */
.globe{touch-action:pan-y; cursor:grab; -webkit-user-select:none; user-select:none}
.globe.dragging{cursor:grabbing}
.globe svg text{pointer-events:none}
@media (hover:none){ .globe{cursor:auto} }
/* The canvas carries the lit sphere and the graticule; the SVG's own
   versions of those are hidden the moment the canvas is in place, so a
   browser without JavaScript still gets the flat wireframe. */
.globe canvas{position:absolute; left:0; top:0; width:100%; display:block}
.globe.hasCanvas > svg > .sphere,
.globe.hasCanvas > svg > .grat{display:none}

.globe .sphere{
  fill:var(--bg2); stroke:var(--rule); stroke-width:1.2;
  opacity:0; transition:opacity .9s var(--ease);
}
.globe.in .sphere{opacity:1}

.globe .grat *{
  fill:none; stroke:var(--rule); stroke-width:.85;
  opacity:0; transition:opacity 1s var(--ease) .15s;
}
.globe.in .grat *{opacity:.5}

/* Kochi to the Gulf cluster — the one line that means something. */
.globe .link{
  fill:none; stroke:var(--accent); stroke-width:1.5; stroke-linecap:round;
  stroke-dasharray:130; stroke-dashoffset:130;
  transition:stroke-dashoffset 1.2s var(--ease-out) .5s;
}
.globe.in .link{stroke-dashoffset:0}

.globe .leaders line{
  stroke:var(--rule); stroke-width:1;
  opacity:0; transition:opacity .7s var(--ease) .8s;
}
.globe.in .leaders line{opacity:.9}

.globe .mk{
  fill:var(--bg); stroke:var(--accent); stroke-width:1.9;
  transform-box:fill-box; transform-origin:center; transform:scale(0);
  transition:transform .55s var(--ease-out);
}
.globe.in .mk{transform:scale(1)}
.globe .k1{transition-delay:.55s} .globe .k2{transition-delay:.65s}
.globe .k3{transition-delay:.75s} .globe .k4{transition-delay:.85s}

.globe .hub{
  fill:var(--accent);
  transform-box:fill-box; transform-origin:center; transform:scale(0);
  transition:transform .55s var(--ease-out) .95s;
}
.globe.in .hub{transform:scale(1)}

.globe text{
  fill:var(--ink2); font-size:12px; font-weight:600; letter-spacing:.10em;
  opacity:0; transition:opacity .6s var(--ease) 1s;
}
.globe.in text{opacity:1}
.globe text.hubLabel{fill:var(--muted); font-size:9.5px; letter-spacing:.14em}
@media(max-width:700px){ .globe text{font-size:17px} .globe text.hubLabel{font-size:14px} }

/* Once the script takes the wheel it writes cx/cy, d and opacity every
   frame, so the reveal's transitions have to get out of the way — a .6s
   opacity transition would leave every value trailing a third of a second
   behind the geometry. The dash that drew the link in is cleared for the
   same reason: the path length now changes continuously. */
.globe svg.spin .link{stroke-dasharray:none}
/* Turning the globe drags each pin away from its parked label, so the
   leaders grow long and diagonal. Thin them to a hairline while it spins
   — they still tie label to pin without becoming the loudest thing on
   the diagram. */
.globe svg.spin .leaders line{stroke-width:.8}
.globe svg.spin text,
.globe svg.spin .leaders line,
.globe svg.spin .mk,
.globe svg.spin .hub{transition:none}

@media (prefers-reduced-motion:reduce){
  .js main{animation:none}
  .js .sr .line-i{transform:none; transition:none}
  .js .card:hover{transform:none}
  .globe .sphere, .globe .grat *, .globe .link, .globe .leaders line,
  .globe .mk, .globe .hub, .globe text{transition:none}
  .globe .mk, .globe .hub{transform:scale(1)}
  .globe text, .globe .sphere{opacity:1}
  .globe .grat *{opacity:.5} .globe .leaders line{opacity:.9}
  .globe .link{stroke-dashoffset:0}
  .js .scrollbar{transition:none}
}

/* Markets sit beside the globe, so two columns rather than five.
   Five cards leave an odd gap in a 2-up grid, and the fifth is not a
   market at all — it is the office — so it takes the full row. */
.split .markets{grid-template-columns:repeat(2,minmax(0,1fr))}
.split .markets .market:last-child{grid-column:1 / -1}
@media(max-width:980px){
  .split .markets{grid-template-columns:repeat(2,minmax(0,1fr))}
  .globe{max-width:400px}
}
@media(max-width:560px){ .split .markets{grid-template-columns:1fr} }

/* ============================================================
   Cursor trail — canvas, so there is no element to mis-align
   ============================================================ */
.cursor-trail{
  position:fixed; inset:0; width:100%; height:100%;
  /* Above the sticky header (100) so it doesn't vanish over the nav — the
     most interactive strip on the page. Never interactive itself. */
  pointer-events:none; z-index:110;
}
@media (prefers-reduced-motion:reduce){ .cursor-trail{display:none} }
@media (pointer:coarse){ .cursor-trail{display:none} }

/* ============================================================
   Theme switch
   The track is deliberately inverted against the page: a dark chip on the
   light theme, a light chip on the dark one. Every part of the control is
   therefore themed as a pair — knob and icons must contrast the TRACK,
   not the page behind it.
   ============================================================ */
.toggle{
  /* Light page -> dark track */
  --sw-track:#152330;
  --sw-edge:#3a5a76;
  --sw-icon:#c3d8e8;                       /* the icon the knob isn't covering */
  --sw-knob:#33ccff;
  --sw-glow:0 0 0 1px rgba(0,0,0,.4), 0 0 10px -1px rgba(51,204,255,.55);
  background:none; border:0; padding:4px; margin-left:8px;
  display:inline-flex; align-items:center; cursor:pointer; flex:none;
  -webkit-tap-highlight-color:transparent;
}
[data-theme="dark"] .toggle{
  /* Dark page -> light track */
  --sw-track:#dcebf8;
  --sw-edge:#9dbdd8;
  --sw-icon:#2d4a63;
  --sw-knob:#0a6595;
  --sw-glow:0 1px 3px rgba(0,0,0,.35);
}
@media (prefers-color-scheme:dark){
  [data-theme="auto"] .toggle{
    --sw-track:#dcebf8;
    --sw-edge:#9dbdd8;
    --sw-icon:#2d4a63;
    --sw-knob:#0a6595;
    --sw-glow:0 1px 3px rgba(0,0,0,.35);
  }
}
.toggle .track{
  position:relative; display:inline-flex; align-items:center;
  width:54px; height:28px; border-radius:999px;
  background:var(--sw-track); border:1px solid var(--sw-edge);
  transition:background .35s var(--ease), border-color .35s var(--ease);
}
.toggle:hover .track{border-color:var(--brand)}
.toggle:focus-visible{outline:none}
.toggle:focus-visible .track{outline:2px solid var(--brand); outline-offset:3px}

/* Both icons are always present; the knob slides over the inactive one.
   Offsets are explicit, so there is no centring transform to mis-resolve. */
.toggle .ic{
  position:absolute; top:7px; width:14px; height:14px;
  color:var(--sw-icon); opacity:.95;
  stroke:currentColor; fill:none; stroke-width:1.8;
  stroke-linecap:round; stroke-linejoin:round;
  transition:color .35s var(--ease);
}
.toggle .ic-sun{left:6px}
.toggle .ic-moon{right:6px}

.toggle .knob{
  position:absolute; top:3px; left:3px; width:20px; height:20px;
  border-radius:50%; background:var(--sw-knob);
  box-shadow:var(--sw-glow);
  transition:transform .42s cubic-bezier(.34,1.32,.5,1),
             background .35s var(--ease), box-shadow .35s var(--ease);
}
.toggle[aria-checked="true"] .knob{transform:translateX(26px)}
.toggle:active .knob{width:24px}

@media (prefers-reduced-motion:reduce){
  .toggle .knob, .toggle .track, .toggle .ic{transition:none}
}
@media (max-width:900px){ .toggle{margin-left:0; margin-top:14px} }

/* Scrim behind the open mobile menu — absorbs the outside click so it
   closes the menu instead of activating the content underneath. */
.nav-scrim{
  position:fixed; inset:0; z-index:98;
  background:rgba(4,12,20,.46);
  opacity:0; pointer-events:none;
  transition:opacity .3s var(--ease);
}
.nav-scrim.on{opacity:1; pointer-events:auto}
@media (min-width:901px){ .nav-scrim{display:none} }
@media (prefers-reduced-motion:reduce){ .nav-scrim{transition:none} }

/* <address> is italic by default in every browser */
address{font-style:normal; line-height:1.65}
.contactGrid address{font-size:15px; font-weight:300}

/* ============================================================
   Empty state — must read as an answer, not a section that
   failed to load, so it gets a real frame and centred weight.
   ============================================================ */
.empty{
  border:1px solid var(--line2); border-radius:var(--radius);
  background:var(--bg); text-align:center;
  padding:clamp(44px,7vw,76px) clamp(20px,5vw,48px);
  position:relative; overflow:hidden;
}
.alt .empty{background:var(--bg)}
.empty::before{            /* the brand triangle, used as a quiet marker */
  content:""; display:block; width:0; height:0; margin:0 auto 22px;
  border-left:9px solid transparent; border-right:9px solid transparent;
  border-bottom:14px solid var(--brand); opacity:.85;
}
.empty p{margin:0}
.empty-head{
  font-size:clamp(18px,2.2vw,23px); font-weight:300; letter-spacing:-.015em;
  color:var(--ink); margin-bottom:12px !important;
}
.empty-sub{font-size:15px; color:var(--muted); max-width:46ch; margin-inline:auto !important}

/* ============================================================
   --rule: a SOLID hairline colour.
   --line2 is part-transparent in the dark palette, which is fine for
   dividers between filled panels but leaves SVG strokes and thin
   graphics almost invisible on the dark ground. Anything drawn as a
   line rather than an edge between surfaces uses this instead.
   ============================================================ */
:root, [data-theme="light"]{ --rule:#9dbcd7; }
[data-theme="dark"]{ --rule:#35506a; }
@media (prefers-color-scheme:dark){ [data-theme="auto"]{ --rule:#35506a; } }

/* --edge: the outline of an interactive control that has no fill.
   Same problem as --rule, one step further: a hairline on a diagram can
   afford to whisper, but the only edge a ghost button has IS the button,
   so it has to clear the 3:1 WCAG asks of a UI boundary. On the dark
   ground --line2 lands at about 1.29:1 and all but disappears; this is
   3.27:1. Light already passed, so that value is unchanged. */
:root, [data-theme="light"]{ --edge:#9dbcd7; }
[data-theme="dark"]{ --edge:#456686; }
@media (prefers-color-scheme:dark){ [data-theme="auto"]{ --edge:#456686; } }
