/* ============================================================
   Beyondsoft International — Shared Design System
   base.css  ·  used by every page
   ============================================================ */

:root{
  /* surfaces */
  --bg:#FFFFFF;
  --bg-2:#F4F7FC;
  --bg-3:#F4F7FC;
  --card:#FFFFFF;
  --card-grad-a:#F3F8FF;
  --card-grad-b:#E9F1FB;

  /* brand (Beyondsoft blue) */
  --logo-blue:#003F98;
  --blue:#008AAB;
  --blue-hi:#008AAB;
  --teal:#008AAB;

  /* iHQ auxiliary palette (P17-18) — accent colours, used with the blue core */
  --aux-cyan:#3BB0C9;
  --aux-orange:#FF9E16;
  --aux-green:#B6BD00;
  --aux-teal:#36BBB1;
  --aux-purple:#904799;
  --aux-purple-dark:#60295E;
  --aux-yellow:#FFCE00;
  --aux-red:#F42534;
  --aux-red-dark:#802528;
  --aux-grey:#7D868C;
  --tungsten-grey:#4B4F54;

  /* text */
  --ink:#26292C;
  --text:#4B4F54;
  --text-2:#3A3D40;
  --muted:#6E7276;
  --muted-2:#9BA0A4;

  /* lines */
  --line:rgba(43,46,49,.10);
  --line-2:rgba(43,46,49,.16);
  --card-line:#E5EAF1;
  --card-line-hi:#D4DCE8;

  /* type — Helvetica everywhere. One stack for display, body and mono so the whole
     site renders in a single family. The CJK faces trail the Latin ones only as
     per-glyph fallbacks: Helvetica/Arial carry no 中文/日本語 glyphs, so without them
     the browser would pick an arbitrary default for CJK copy. Latin text is Helvetica. */
  --f-display:Helvetica,'Helvetica Neue',Arial,'PingFang SC','Hiragino Sans','Microsoft YaHei','微软雅黑',sans-serif;
  --f-body:Helvetica,'Helvetica Neue',Arial,'PingFang SC','Hiragino Sans','Microsoft YaHei','微软雅黑',sans-serif;
  --f-mono:Helvetica,'Helvetica Neue',Arial,'PingFang SC','Hiragino Sans','Microsoft YaHei','微软雅黑',sans-serif;

  /* layout */
  /* Content used to cap at 1360 while the header runs at 1640 (:143) — the page's own
     content sat 280px narrower than the frame around it, which is what read as a column
     dropped into too much margin. 1560 brings the two into the same family; the padding
     opens up with the viewport instead of staying at a fixed 48. Long-form measure is
     unaffected: paragraphs carry their own ch-based max-widths, so widening the container
     widens the grids and the artwork, not the reading line. */
  --maxw:1560px;
  --pad:clamp(40px,3.4vw,72px);
  --radius:var(--radius-14);   /* the old token, now pointing at the ladder above so there is one system rather than two */
  --header-h:100px;

  /* The house curve, retuned to the one Accenture uses for 263 of its 342 easings —
     cubic-bezier(.85,0,0,1). It is a near-maximal ease-IN-out: about 1% of the distance in the
     first 10% of the time, 78% by the halfway point, then a long settle. The curve that was
     here, cubic-bezier(.22,.61,.36,1), is a plain ease-out — it leaves at full speed and has
     nothing to decelerate from, which is what made short moves read as abrupt and long ones as
     floaty. This token is referenced 185 times, so this one line re-curves most of the site. */
  --ease:cubic-bezier(.85,0,0,1);

  /* Channel triples. rgba() cannot read a hex token, so every translucent use of a brand
     colour was writing the channels out again — rgb(0,138,171) appears 138 times at 49
     different alphas, white 167 times at 24, and there are 94 distinct channel triples in the
     file. These let the alpha stay local while the colour itself has one definition:
     rgba(var(--blue-rgb),.24). Same computed value, one place to change it. */
  --blue-rgb:0,138,171;
  --blue-soft-rgb:111,171,198;
  --cyan-rgb:59,176,201;
  --ink-rgb:43,46,49;
  --white-rgb:255,255,255;
  --ground-rgb:3,17,34;

  /* #6FABC6 was the third most-used colour in the file — 29 as hex plus 30 more written as
     rgb(111,171,198) — and it had no token of its own; it existed only as a per-component
     --acc/--ca value. A colour used 59 times is a brand colour whether or not it was named. */
  --blue-soft:#6FABC6;

  /* Spacing scale. gap was the least disciplined thing in this file: 51 distinct values across
     175 declarations — 6, 8, 9, 10, 12, 14, 16, 18, 20, 22, 24, 26 all present and none of them
     meaning anything different from its neighbour. Accenture runs five spacing tokens
     redeclared per breakpoint and components never write a literal; this is the same idea at
     this site's density, a 4px grid.

     Every existing value is snapped to its NEAREST step, so nothing moves more than 2px and no
     layout is redesigned by the change — the point of this pass is to remove the vocabulary,
     not to re-space the site. Anything above 96px is left alone; those are section-scale and
     belong to the vertical rhythm, not to component gaps. */
  --sp-4:4px;   --sp-8:8px;   --sp-12:12px; --sp-16:16px;
  --sp-20:20px; --sp-24:24px; --sp-28:28px; --sp-32:32px;
  --sp-40:40px; --sp-48:48px; --sp-56:56px; --sp-64:64px;
  /* 80 and 96 were declared with the ladder and nothing reached them — gaps that large are
     section rhythm, not component spacing, and the sweep left them above its 96px ceiling. */

  /* Radius ladder. There were 28 distinct values across 180 declarations — 9, 10, 11, 12, 13,
     14, 15, 16, 18 and 20 all in use, none of them saying anything a neighbour did not, and the
     existing --radius token accounted for 7 of the 180. Accenture's whole design system carries
     16 border-radius declarations; separation there is done with hairlines, not with corners.
     Four steps is the smallest set that keeps this site's own look: every value snaps to the
     nearest and nothing moves more than 4px. 50% (circles) and the >=90px pills are untouched;
     pills are normalised to 999px so there is one way to write one. */
  --radius-4:4px; --radius-8:8px; --radius-14:14px; --radius-20:20px;

  /* Elevation. Three tokens, and the tiers were measured rather than judged: every distinct
     shadow in the file was rendered on a 320x190 card, once with and once without, and the
     largest per-pixel difference recorded. That number is what a shadow is actually worth.

     It also corrected the premise. The file has 146 box-shadow declarations at 134 distinct
     values, which sounds like chaos — but only 22 of those are NEUTRAL ELEVATION. The rest are
     brand-coloured glows keyed to a component accent, focus rings, inset hairlines, resets, and
     spread-driven keyframe endpoints. Several of the ones that look like dead no-ops are
     load-bearing: `0 0 0 0` rest states that keyframes interpolate FROM, and knockouts like
     .ab-time-era::before that mask a parent's border. None of those are touched here.

     What is touched is the 22, minus the four heaviest — those sit on dark grounds where a
     neutral value does not belong — and minus the transparent reset.

     Measured weights, max per-pixel delta out of 765:
       contact  <=45   the .card pair at 36, the 1px hairlines at 21
       raised   46-100 20px/50px at 74, 30px/60px at 88
       float    101-200 the 22px/46px pair at 114, 34px/74px at 177 */
  --sh-contact:0 1px 2px rgba(var(--ink-rgb),.05),0 12px 30px -22px rgba(var(--ink-rgb),.18);
  --sh-raised:0 20px 50px -20px rgba(var(--ink-rgb),.25);
  --sh-float:0 34px 74px -44px rgba(14,38,60,.72);

  /* Highlight gradient: Corporate Cyan → Logo Blue → Pantone 258 C (30th-anniversary ramp).
     Client-approved for the hero / heading highlight — keep this exact colour ramp.
     A teal-for-Logo-Blue substitution was trialled on 2026-08-13 and rejected. */
  --grad-anniv:linear-gradient(100deg,var(--blue) 0%,var(--logo-blue) 52%,var(--aux-purple) 100%);
  /* seamless-loop variant (mirrors back to the start colour) so a scrolling tile has no hard seam */
  --grad-anniv-loop:linear-gradient(100deg,var(--blue) 0%,var(--logo-blue) 25%,var(--aux-purple) 50%,var(--logo-blue) 75%,var(--blue) 100%);
}

*{box-sizing:border-box;}
html{scroll-behavior:smooth;}
html,body{margin:0;padding:0;background:var(--bg);}
body{
  font-family:var(--f-body);
  color:var(--text);
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  overflow-x:hidden;
}
a{color:inherit;text-decoration:none;}
/* Form controls don't inherit font-family from body — without this the browser's own
   default (Arial/system) leaks into buttons, menu carets, inputs and selects. */
button,input,select,textarea,optgroup{font-family:inherit;}
img{max-width:100%;display:block;}
::selection{background:rgba(var(--blue-rgb),.32);color:#fff;}

/* scrollbar */
body::-webkit-scrollbar{width:11px;}
body::-webkit-scrollbar-track{background:var(--bg-3);}
body::-webkit-scrollbar-thumb{background:#1c2a44;border-radius:var(--radius-4);border:2px solid var(--bg-3);}
body::-webkit-scrollbar-thumb:hover{background:#002E72;}

/* ---------- layout ---------- */
.container{width:var(--maxw);max-width:100%;margin:0 auto;padding-left:var(--pad);padding-right:var(--pad);}
/* Not every band should be the same width. A page where every section measures exactly the
   same is the thing that reads as templated — varying it is most of what separates a
   designed page from a filled-in one. Use this on bands whose content is horizontal by
   nature: logo walls, wide media, anything that gains from the extra room. */
.container.container--wide{--maxw:1880px;}
.section{padding-top:80px;padding-bottom:20px;}
.section-lg{padding-top:96px;padding-bottom:96px;}
.section-tight{padding-top:56px;padding-bottom:12px;}
.divide-top{border-top:1px solid var(--line);}

/* ---------- type helpers ---------- */
.eyebrow{
  display:inline-flex;align-items:center;gap:var(--sp-8);
  font:600 12px/1 var(--f-mono);letter-spacing:.18em;text-transform:uppercase;
  color:var(--teal);margin-bottom:16px;
}
.eyebrow .dot{width:7px;height:7px;border-radius:50%;background:var(--teal);box-shadow:0 0 12px var(--teal);}
.h1{margin:0;font:700 56px/1.02 var(--f-display);letter-spacing:-.03em;color:var(--ink);}
.h2{margin:0;font:700 34px/1.08 var(--f-display);letter-spacing:-.02em;color:var(--ink);}
.h3{margin:0;font:600 20px/1.2 var(--f-display);color:var(--ink);}
/* A measure, not just a size. With the container at 1560 a lead with no cap runs about
   180 characters per line, which is unreadable — and the templates that already set an
   inline max-width keep theirs, since inline beats this. ch rather than px so the limit
   follows the font: the same 68ch is a sane line in English and in 中文. */
.lead{font-size:20px;line-height:1.5;color:var(--text);max-width:68ch;}
.muted{color:var(--muted);}
.accent{color:var(--blue);}
.accent-teal{color:var(--teal);}
.mono{font-family:var(--f-mono);}
.grad-text{background:var(--grad-anniv);-webkit-background-clip:text;background-clip:text;color:transparent;}

.section-head{display:flex;align-items:flex-end;justify-content:space-between;gap:var(--sp-24);margin-bottom:40px;flex-wrap:wrap;}
.link-more{font-size:14.5px;font-weight:600;color:var(--teal);cursor:pointer;transition:gap var(--dur-fast);display:inline-flex;gap:var(--sp-4);align-items:center;}
.link-more:hover{gap:var(--sp-12);}

/* ---------- buttons ---------- */
.btn{
  display:inline-grid;place-items:center;grid-auto-flow:column;gap:var(--sp-8);
  height:54px;padding:0 30px;border-radius:var(--radius-8);
  font-size:15.5px;font-weight:600;cursor:pointer;white-space:nowrap;
  border:1.5px solid transparent;transition:background var(--dur-fast),border-color var(--dur-fast),color var(--dur-fast),transform var(--dur-fast),box-shadow var(--dur-fast);
}
.btn-sm{height:40px;padding:0 20px;font-size:14px;border-radius:var(--radius-8);}
.btn-primary{background:var(--blue);color:#fff;box-shadow:0 8px 24px -10px rgba(var(--blue-rgb),.9);}
.btn-primary:hover{background:var(--blue-hi);transform:translateY(-2px);box-shadow:0 14px 32px -10px rgba(var(--blue-rgb),1);}
.btn-ghost{border-color:var(--line-2);color:#fff;}
.btn-ghost:hover{border-color:var(--teal);color:var(--teal);}
.btn .arrow{color:var(--teal);transition:transform var(--dur-fast) var(--ease);}
.btn:hover .arrow{transform:translateX(5px);}
.btn-primary .arrow{color:#C4E4F2;}

/* ---------- header (injected by app.js) ---------- */
.site-header{position:relative;z-index:60;background:rgba(10,18,32,0);border-bottom:1px solid transparent;transition:background var(--dur-fast),border-color var(--dur-fast),backdrop-filter var(--dur-fast);}
.site-header.scrolled{background:rgba(10,18,32,.82);backdrop-filter:blur(14px);border-bottom:1px solid var(--line);}
.nav{position:relative;display:flex;align-items:center;justify-content:space-between;gap:var(--sp-28);height:var(--header-h);}
/* give the header more horizontal room so the enlarged logo + nav fit */
.site-header .container.nav{--maxw:1640px;--pad:34px;}
.nav-left{display:flex;align-items:center;gap:var(--sp-40);}
.nav-links{flex:1;min-width:0;align-items:center;justify-content:center;}
.nav-links .nav-item{pointer-events:auto;}
.brand{font:700 21px/1 var(--f-display);letter-spacing:-.02em;color:#fff;}
.brand b{color:var(--teal);font-weight:700;}
.nav-links{display:flex;gap:var(--sp-24);font-size:18px;font-weight:500;color:var(--text-2);}
/* The four top-level items are <button> now, not <a> — they open a panel and navigate
   nowhere. Everything below just stops a button from looking like one; the nav's own
   colour, size and active underline are handled by the rules that follow, which is why
   those were widened to :is(a,button) rather than duplicated. */
.nav-links button.nav-top,.mobile-menu button.m-link{
  appearance:none;-webkit-appearance:none;
  background:none;border:0;margin:0;
  font:inherit;color:inherit;text-align:left;
  cursor:pointer;
}
.mobile-menu button.m-link{width:100%;}
.nav-links :is(a,button){position:relative;padding:6px 0;white-space:nowrap;transition:color var(--dur-fast);}
.nav-links :is(a,button):hover{color:#fff;}
.nav-links :is(a,button).active{color:#fff;}
.nav-links :is(a,button).active::after{content:"";position:absolute;left:0;right:0;bottom:-2px;height:2px;background:var(--teal);border-radius:var(--radius-4);}
.nav-right{display:flex;align-items:center;gap:var(--sp-20);}
.lang{display:flex;align-items:center;gap:var(--sp-4);font:500 13px/1 var(--f-mono);color:var(--muted);cursor:pointer;}
.lang .caret{opacity:.5;}
.nav-burger{display:none;flex-direction:column;align-items:center;justify-content:center;gap:var(--sp-4);cursor:pointer;width:44px;height:44px;padding:0;}
.nav-burger span{width:22px;height:2px;background:#fff;border-radius:var(--radius-4);transition:var(--dur-fast);}
/* enlarged logo + nav need more room — switch to the hamburger earlier so the desktop nav never cramps */
@media (max-width:1200px){ .nav-links{display:none;} .nav-burger{display:flex;} }
.lang{position:relative;cursor:pointer;user-select:none;}
.lang-menu{position:absolute;top:calc(100% + 12px);right:0;min-width:170px;background:#0E1A30;border:1px solid var(--card-line);border-radius:var(--radius-8);padding:6px;box-shadow:0 20px 50px -20px rgba(0,0,0,.85);opacity:0;visibility:hidden;transform:translateY(-6px);transition:var(--dur-fast);z-index:70;}
.lang.open .lang-menu{opacity:1;visibility:visible;transform:none;}
.lang-menu a{display:block;padding:9px 12px;border-radius:var(--radius-8);font:500 13.5px/1.2 var(--f-body);color:var(--text-2);}
.lang-menu a:hover{background:rgba(var(--white-rgb),.05);color:#fff;}
.lang-menu a.on{color:var(--teal);}
.mobile-menu{display:none;}

/* ---------- hero / page-hero ---------- */
.hero{position:relative;padding:96px 0 90px;overflow:hidden;}
.hero-inner{position:relative;max-width:820px;}
.page-hero{position:relative;padding:72px 0 56px;overflow:hidden;border-bottom:1px solid var(--line);}
.page-hero .container{position:relative;}
.glow{position:absolute;border-radius:50%;pointer-events:none;}
.glow-blue{width:560px;height:560px;top:-120px;right:-80px;background:radial-gradient(circle at 30% 30%,rgba(var(--blue-rgb),.5),rgba(var(--blue-rgb),0) 62%);filter:blur(10px);}
.glow-teal{width:420px;height:420px;bottom:-160px;left:200px;background:radial-gradient(circle at 50% 50%,rgba(var(--blue-soft-rgb),.26),rgba(var(--blue-soft-rgb),0) 60%);}
.float{animation:floaty 14s ease-in-out infinite;}
.float-2{animation:floaty 18s ease-in-out infinite reverse;}
@keyframes floaty{0%,100%{transform:translate(0,0)}50%{transform:translate(-26px,22px)}}

/* breadcrumb */
.crumbs .sep{opacity:.5;}

/* ---------- metrics band ---------- */
.metrics{display:grid;grid-template-columns:repeat(4,1fr);border-top:1px solid var(--line);border-bottom:1px solid var(--line);}
.metric{padding:32px 40px;border-right:1px solid var(--line);}
.metric:last-child{border-right:0;}
.metric .num{font:700 40px/1 var(--f-display);color:#fff;letter-spacing:-.02em;}

/* ---- About: the deck's three asks -------------------------------------------
   [make the numbers stand out more] — the same four figures, given the room to be
   read as a claim. 40px is the site's standard metric; here they run to 72 and the
   label drops below them in the muted small caps the rest of the site uses for
   labels, so the number is the first thing the eye lands on rather than one of two
   equal lines. Applied through a modifier so /global-presence/, which uses the same
   .metrics block for a different job, is untouched. */
.metrics--hero .metric{padding:clamp(30px,3.4vw,46px) clamp(24px,2.6vw,40px);}
.metrics--hero .metric .num{
  font-size:clamp(44px,5.2vw,72px);line-height:1;letter-spacing:-.035em;
}
.metrics--hero .metric .suf{font-size:.52em;}
.metrics--hero .metric .lbl{margin-top:10px;font-size:12.5px;letter-spacing:.1em;}
.metrics--hero .metric-ic{display:none;}   /* the figure is the graphic here */
@media (max-width:900px){
  .metrics--hero{grid-template-columns:repeat(2,1fr);}
}

/* [Try to redesign so that it has a more unique from the other pages] — type at full
   width, no photograph. Every other page opens on a banner image behind a left-set
   headline; this opens on the tagline alone, with the two paragraphs set beside it on
   a wide screen and under it on a narrow one. */
.ab-hero{padding:clamp(52px,7vw,110px) 0 clamp(34px,4vw,62px);}
.ab-hero-in{display:grid;grid-template-columns:minmax(0,1.05fr) minmax(0,1fr);gap:clamp(28px,4vw,64px);align-items:start;}
.ab-hero-h1{
  margin:0;
  font:700 clamp(42px,6.4vw,86px)/1.02 var(--f-display);
  letter-spacing:-.035em;color:var(--ink);
}
.ab-hero-copy p{
  margin:0 0 18px;max-width:56ch;
  font:400 clamp(16.5px,1.4vw,18px)/1.7 var(--f-body);color:var(--text);
}
.ab-hero-copy p:last-child{margin-bottom:0;}
@media (max-width:860px){
  .ab-hero-in{grid-template-columns:1fr;}
}

/* [possible to do a graphical vertical timeline of milestones?] — the line and the
   node are drawn on the list item, so the chronology stays a plain <ol> in the markup
   with no decorative elements to keep in step with the copy. The line is inset by half
   the node so the two share a centre; the last era stops the line at its own node
   rather than trailing past the final milestone. */
.ab-time{list-style:none;margin:0;padding:0;}
.ab-time-era{
  position:relative;padding:0 0 clamp(30px,3.4vw,44px) clamp(30px,3.4vw,44px);
  border-left:1px solid var(--card-line);
}
.ab-time-era:last-child{border-left-color:transparent;padding-bottom:0;}
.ab-time-era::before{
  content:"";position:absolute;left:-5px;top:.44em;
  width:9px;height:9px;border-radius:50%;
  background:var(--blue);box-shadow:0 0 0 4px var(--bg);
}
.ab-time-when{
  margin:0 0 12px;
  font:700 clamp(18px,1.7vw,21px)/1.25 var(--f-display);letter-spacing:-.01em;color:var(--ink);
}
.ab-time-list{list-style:none;margin:0;padding:0;}
.ab-time-list li{
  position:relative;margin:0 0 9px;padding-left:20px;
  font:400 16.2px/1.68 var(--f-body);color:var(--text);
}
.ab-time-list li:last-child{margin-bottom:0;}
.ab-time-list li::before{
  content:"";position:absolute;left:2px;top:.72em;width:8px;height:0;
  border-top:1px solid var(--card-line);
}
.metric .num .suf{font-size:20px;color:var(--teal);}
.metric .lbl{margin-top:8px;font-size:13.5px;color:var(--muted);}

/* ---------- grids ---------- */
.grid{display:grid;gap:var(--sp-16);}
.g-2{grid-template-columns:repeat(2,1fr);}
.g-3{grid-template-columns:repeat(3,1fr);}
.g-4{grid-template-columns:repeat(4,1fr);}
.gap-20{gap:var(--sp-20);}   /* renamed from .gap-22: the sweep snapped 22px to the 20px rung, and a numeric utility whose name disagrees with its value is a trap */

/* ---------- cards ---------- */
.card{
  position:relative;padding:28px;border:1px solid var(--card-line);border-radius:var(--radius);
  background:var(--card);transition:border-color var(--dur-fast),transform var(--dur-fast),box-shadow var(--dur-fast);
}
.card.hover:hover,.card-link:hover{border-color:var(--blue);transform:translateY(-4px);box-shadow:0 18px 40px -22px rgba(var(--blue-rgb),.7);}
.card-link{cursor:pointer;display:block;}
/* focus / selected state — never the browser's boxy default outline;
   mouse clicks stay perfectly clean, keyboard (Tab) navigation gets a rounded
   ring that follows the card's radius and sits just outside it */
.card-link:focus{outline:none;}
.card-link::-moz-focus-inner{border:0;padding:0;}
.card-link:focus-visible{outline:2px solid var(--blue);outline-offset:3px;}
/* Keyboard focus — visible cyan ring across interactive elements (WCAG 2.4.7) */
a:focus-visible,button:focus-visible,.ah-btn:focus-visible,.ah-btn-ghost:focus-visible,
.ah-cap2:focus-visible,.rcard:focus-visible,.tab:focus-visible,.ah-more:focus-visible,
.ah-cp-item:focus-visible,input:focus-visible,textarea:focus-visible,select:focus-visible{
  outline:2px solid var(--blue);outline-offset:3px;border-radius:var(--radius-4);
}
.ah-tile:focus-visible{outline:2px solid var(--blue);outline-offset:3px;}
.card.feature{border-color:var(--card-line-hi);background:linear-gradient(180deg,var(--card-grad-a),var(--card-grad-b));}
.card.feature-teal{border-color:var(--card-line-hi);background:linear-gradient(180deg,#0F1E38,#0A1526);}
/* The tile. font-weight:700 came off with the glyphs: it was there to embolden Unicode
   symbols, and on a symbol font that is browser-synthesised faux-bold — a smeared outline, not
   a heavier drawing. Nothing inside the tile is text any more except the certification marks,
   which get .badge below. */
.card .icon{width:42px;height:42px;border-radius:var(--radius-8);display:grid;place-items:center;margin-bottom:52px;}
/* One rule for every icon in the set. The colour comes from the tile's own `color`, which is
   what .icon-soft / .icon-blue already set, so a path never carries a hex. */
.bsi{width:24px;height:24px;display:block;flex:none;}
/* The certification tiles hold typographic marks — 27001, CMMI — not icons. They keep the
   tile geometry and get their own type treatment rather than being forced through a slot
   drawn for 24px artwork. */
.card .icon.badge{font:700 12px/1 var(--f-mono);letter-spacing:.02em;font-variant-numeric:tabular-nums;width:auto;min-width:42px;padding:0 9px;}
.icon-blue{background:var(--blue);color:#fff;box-shadow:0 6px 20px -4px rgba(var(--blue-rgb),.7);}
.icon-soft{background:rgba(var(--blue-rgb),.16);color:var(--blue-hi);}
.card h3{margin:0 0 10px;font:600 20px/1.2 var(--f-display);color:#fff;}
.card p{margin:0;font-size:14.5px;line-height:1.55;color:var(--muted);}

/* badges */
.badge{font:600 10px/1 var(--f-mono);letter-spacing:.1em;color:var(--bg);background:var(--teal);padding:5px 8px;border-radius:var(--radius-4);}
.badge-tr{position:absolute;top:20px;right:20px;}
.badge-abs{position:absolute;top:12px;left:12px;}

/* tag / pill */
.tag{display:inline-block;font:600 11px/1 var(--f-mono);letter-spacing:.1em;text-transform:uppercase;color:var(--teal);}
.pill{padding:8px 14px;border:1px solid var(--card-line-hi);border-radius:var(--radius-8);font:600 13px/1 var(--f-mono);color:var(--text-2);}

/* image placeholder */
.imgph .cap{position:absolute;left:14px;bottom:14px;font:500 11px/1 var(--f-mono);color:#5B6577;}

/* ---------- real images + treatments ---------- */
.media{position:relative;overflow:hidden;background:#0b1526;}
.media img{width:100%;height:100%;object-fit:cover;display:block;transition:transform var(--dur-base) var(--ease);}

.media::after{content:"";position:absolute;inset:0;pointer-events:none;background:linear-gradient(180deg,rgba(10,18,32,.05),rgba(10,18,32,.55));}
.media.legible::after{background:linear-gradient(180deg,rgba(10,18,32,.25),rgba(10,18,32,.82));}
.media.tint::after{background:linear-gradient(145deg,rgba(var(--blue-rgb),.30),rgba(10,18,32,.5) 55%,rgba(var(--blue-soft-rgb),.22));}
.media .cap{position:absolute;left:14px;bottom:14px;z-index:2;font:500 11px/1 var(--f-mono);color:#cdd7e6;}

/* split hero — service archetype */
.hero-split{display:grid;grid-template-columns:1.05fr .95fr;gap:var(--sp-48);align-items:center;}
.hero-split .media{border-radius:var(--radius-14);aspect-ratio:4/3;border:1px solid var(--card-line);box-shadow:0 34px 80px -34px rgba(0,0,0,.85);}

/* full-bleed image hero — industry archetype */
.hero-image{position:relative;min-height:440px;display:flex;align-items:flex-end;overflow:hidden;border-bottom:1px solid var(--line);}
.hero-image .bg{position:absolute;inset:0;}
.hero-image .bg img{width:100%;height:100%;object-fit:cover;}
.hero-image .bg::after{content:"";position:absolute;inset:0;background:linear-gradient(90deg,rgba(10,18,32,.96),rgba(10,18,32,.62) 52%,rgba(10,18,32,.32));}
.hero-image .container{position:relative;padding-top:80px;padding-bottom:52px;}

/* image-top card — hub archetype */
.icard .media{height:196px;}
.icard .body{padding:24px 26px 28px;}
.icard .body .icon{margin-bottom:0;position:absolute;transform:translateY(-52px);}

/* full-bleed band with image */
.band{position:relative;overflow:hidden;border-top:1px solid var(--line);border-bottom:1px solid var(--line);}
.band .bg{position:absolute;inset:0;}
.band .bg img{width:100%;height:100%;object-fit:cover;}
.band .bg::after{content:"";position:absolute;inset:0;background:linear-gradient(120deg,rgba(10,18,32,.94),rgba(0,46,114,.72));}
.band .container{position:relative;}

/* zig-zag feature row — about archetype */
.zz{display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-48);align-items:center;}
.zz+.zz{margin-top:64px;}
.zz .media{border-radius:var(--radius-14);aspect-ratio:16/11;border:1px solid var(--card-line);}
.zz.rev .txt{order:2;}
.zz.rev .media{order:1;}

/* photo gallery — careers archetype */
.gallery{display:grid;grid-template-columns:repeat(4,1fr);grid-auto-rows:176px;gap:var(--sp-12);}
.gallery .media{border-radius:var(--radius-14);border:1px solid var(--card-line);}
.gallery .tall{grid-row:span 2;}
.gallery .wide{grid-column:span 2;}

/* oversized outline index number */
.bignum{font:700 60px/1 var(--f-display);color:transparent;-webkit-text-stroke:1.5px rgba(var(--white-rgb),.16);letter-spacing:-.02em;display:block;margin-bottom:6px;}

/* ============ motion / animations ============ */
/* scroll progress bar */
.scroll-progress{position:fixed;top:0;left:0;height:3px;width:0;z-index:200;background:linear-gradient(90deg,var(--blue),#36BBB1);box-shadow:0 0 4px rgba(var(--blue-rgb),.3);}
/* animated gradient shimmer on accent + gradient headings */
@keyframes shimmer{0%{background-position:0% 50%;}100%{background-position:200% 50%;}}
.accent{background:linear-gradient(90deg,var(--blue),var(--blue-soft),var(--blue));background-size:200% auto;-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;color:transparent;animation:shimmer 8s linear infinite;}
.grad-text{background-size:200% auto;animation:shimmer 8s linear infinite;}
/* reveal direction variants (add rl / rr / rs to .reveal) */
.reveal.rl{transform:translateX(-42px);}
.reveal.rr{transform:translateX(42px);}
.reveal.rs{transform:scale(.93);}
.reveal.rl.in,.reveal.rr.in,.reveal.rs.in{transform:none;}
/* card + tile hover lift */
.card-link{transition:border-color var(--dur-fast),transform var(--dur-base) var(--ease),box-shadow var(--dur-base) var(--ease);}
.card-link:hover{transform:translateY(-5px);}
.tile{transition:border-color var(--dur-fast),transform var(--dur-base) var(--ease),background var(--dur-fast);}
.tile:hover{transform:translateY(-4px);}
/* primary-button sheen sweep on hover */
.btn-primary{position:relative;overflow:hidden;}
.btn-primary::after{content:"";position:absolute;top:0;left:-140%;width:55%;height:100%;background:linear-gradient(100deg,transparent,rgba(var(--white-rgb),.30),transparent);transform:skewX(-20deg);pointer-events:none;}
.btn-primary:hover::after{animation:sheen .85s ease;}
@keyframes sheen{to{left:150%;}}
/* pulsing status dot */
.dot{animation:dotpulse 2.6s ease-in-out infinite;}
@keyframes dotpulse{0%,100%{box-shadow:0 0 0 0 rgba(var(--blue-soft-rgb),.45);}50%{box-shadow:0 0 14px 2px rgba(var(--blue-soft-rgb),.85);}}
/* parallax sizing for full-bleed background images */
.hero-image .bg img,.band .bg img{position:absolute;top:-9%;left:0;width:100%;height:118%;object-fit:cover;will-change:transform;}

/* ============ cookie consent ============ */
/* While the bar is up it must not sit on top of the page's primary call to action —
   measured at a 720px viewport it covered the home hero's "What we do" button outright.
   The hero reserves the bar's height for as long as it is shown, and gives it back the
   moment consent is answered. */
body.bs-cookie-open .ah-hero,
body.bs-cookie-open .hero-image,
body.bs-cookie-open .capability-hero{padding-bottom:var(--cookie-h,96px);}
.cookie-banner{position:fixed;left:0;right:0;bottom:0;z-index:300;background:rgba(10,18,32,.94);backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);border-top:1px solid var(--card-line-hi);transform:translateY(115%);transition:transform var(--dur-base) var(--ease);}
.cookie-banner.show{transform:none;}
.cookie-banner .inner{max-width:1200px;margin:0 auto;padding:20px 40px;display:flex;align-items:center;gap:var(--sp-24);flex-wrap:wrap;}
.cookie-banner p{margin:0;flex:1;min-width:280px;font-size:13.5px;line-height:1.6;color:var(--text-2);}
.cookie-banner a{color:var(--teal);}
.cookie-actions{display:flex;gap:var(--sp-8);flex-wrap:wrap;}
.btn-mini{height:44px;padding:0 20px;border-radius:var(--radius-8);font-size:14px;font-weight:600;cursor:pointer;display:grid;place-items:center;border:1px solid var(--card-line-hi);color:#fff;background:transparent;transition:border-color var(--dur-fast),color var(--dur-fast);}
.btn-mini:hover{border-color:var(--teal);color:var(--teal);}
.cookie-modal{position:fixed;inset:0;z-index:310;display:none;align-items:center;justify-content:center;padding:20px;}
.cookie-modal.show{display:flex;}
.cookie-modal .backdrop{position:absolute;inset:0;background:rgba(4,8,15,.74);backdrop-filter:blur(4px);}
.cookie-modal .panel{position:relative;width:min(620px,100%);max-height:88vh;overflow:auto;background:#0E1A30;border:1px solid var(--card-line-hi);border-radius:var(--radius-14);padding:30px 32px;box-shadow:0 40px 100px -30px #000;}
.cookie-modal h3{margin:0 0 10px;font:600 22px/1.2 var(--f-display);color:#fff;}
.cookie-modal>.panel>p{font-size:14px;line-height:1.6;color:var(--text-2);margin:0 0 20px;}
.ck-cat{border-top:1px solid var(--card-line);padding:18px 2px;}
.ck-cat:last-of-type{border-bottom:1px solid var(--card-line);margin-bottom:22px;}
.ck-cat .row{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-16);}
.ck-cat h4{margin:0;font-size:15.5px;color:#fff;}
.ck-cat p{margin:8px 0 0;font-size:13px;line-height:1.55;color:var(--muted);}
.ck-always{font:600 12px/1 var(--f-mono);color:var(--teal);white-space:nowrap;}
.switch{position:relative;width:44px;height:24px;flex:0 0 auto;display:inline-block;}
.switch input{opacity:0;width:0;height:0;position:absolute;}
.switch .slider{position:absolute;inset:0;background:#26344f;border-radius:999px;transition:var(--dur-fast);cursor:pointer;}
.switch .slider::before{content:"";position:absolute;top:3px;left:3px;width:18px;height:18px;border-radius:50%;background:#fff;transition:var(--dur-fast);}
.switch input:checked+.slider{background:var(--blue);}
.switch input:checked+.slider::before{transform:translateX(20px);}
.switch input:disabled+.slider{opacity:.5;cursor:not-allowed;}
/* policy table */
.ptable{width:100%;border-collapse:collapse;font-size:14px;min-width:520px;}
.ptable th,.ptable td{text-align:left;padding:13px 14px;border-bottom:1px solid var(--card-line);vertical-align:top;color:var(--text-2);line-height:1.5;}
.ptable thead th{font:600 11px/1.3 var(--f-mono);letter-spacing:.08em;text-transform:uppercase;color:var(--muted);border-bottom:1px solid var(--card-line-hi);}
.ptable td:first-child{color:#fff;font-weight:600;}
@media (max-width:720px){ .cookie-banner .inner{padding:16px 20px;gap:var(--sp-12);} .cookie-actions{width:100%;} .cookie-actions .btn,.cookie-actions .btn-mini{flex:1;} }
/* accessibility: respect reduced-motion */
@media (prefers-reduced-motion:reduce){
  /* .01ms, not a duration token. The token sweep that collapsed 447 durations onto --dur-fast/
     -base/-slow reached in here too and left this at 200ms, which quietly turned the reduced-
     motion switch off: every transition on the site still ran, just slightly quicker. Time
     values inside a prefers-reduced-motion block are a kill switch, not part of the scale. */
  *,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;}
  .reveal{opacity:1!important;transform:none!important;}
}

/* ---------- industry / simple tiles ---------- */
.tile{padding:20px 18px;border:1px solid var(--card-line);border-radius:var(--radius-8);background:var(--card);min-height:120px;display:flex;flex-direction:column;justify-content:flex-end;position:relative;transition:border-color var(--dur-fast),transform var(--dur-fast);color:var(--text-2);}
.tile:hover{border-color:var(--blue);transform:translateY(-4px);}
.tile.on{border-color:var(--blue);background:linear-gradient(160deg,#0A3A7A,#001F4D);color:#fff;}
.tile .t{font:600 16px/1.2 var(--f-display);}

/* ---------- trust strip ---------- */
.trust{padding:30px 40px;background:var(--card);border:1px solid var(--card-line);border-radius:var(--radius-14);display:flex;align-items:center;justify-content:space-between;gap:var(--sp-28);}
.trust .lbl{font-size:13.5px;font-weight:600;color:var(--muted);white-space:nowrap;}
.trust .items{display:flex;align-items:center;gap:var(--sp-12);flex-wrap:wrap;}

/* marquee (partners) */
.marquee{overflow:hidden;position:relative;-webkit-mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent);mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent);}
.marquee .track{display:flex;gap:var(--sp-12);width:max-content;animation:scrollx 32s linear infinite;}
.marquee:hover .track{animation-play-state:paused;}
@keyframes scrollx{to{transform:translateX(-50%)}}

/* ---------- CTA band ---------- */
.cta-band{position:relative;padding:72px 0;overflow:hidden;background:linear-gradient(115deg,#002E72,#0A1220);}
.cta-band .inner{position:relative;display:flex;align-items:center;justify-content:space-between;gap:var(--sp-40);flex-wrap:wrap;}

/* ---------- accordion (service capabilities) ---------- */
.acc{border:1px solid var(--card-line);border-radius:var(--radius-14);overflow:hidden;background:var(--card);}
.acc-item+.acc-item{border-top:1px solid var(--card-line);}
.acc-h{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-16);padding:20px 24px;cursor:pointer;transition:background var(--dur-fast);}
.acc-h:hover{background:rgba(var(--white-rgb),.02);}
.acc-h .t{font:600 17px/1.3 var(--f-display);color:#fff;}
.acc-h .pm{color:var(--teal);font-size:20px;transition:transform var(--dur-fast);flex:0 0 auto;}
.acc-item.open .pm{transform:rotate(45deg);}
/* Always open. The client asked for content to "expand out fully instead of hover to
   reveal", and on this variant the body was max-height:0 until a click — so on eight
   service pages the answer to every question was one interaction away, and on a phone
   the panel read as a list of headings with nothing under them.
   The +/- affordance goes with it: nothing collapses, so nothing should advertise that
   it does. .acc-h keeps its hover tint as a plain grouping cue. */
.acc-b{max-height:none;overflow:visible;}
.acc-h .pm{display:none;}
.acc-h{cursor:default;}
.acc-b .inner{padding:0 24px 20px;color:var(--muted);font-size:14.5px;line-height:1.6;}

/* ---------- feature list ---------- */
.flist{list-style:none;margin:0;padding:0;display:grid;gap:var(--sp-12);}
.flist li{position:relative;padding-left:30px;font-size:15px;line-height:1.5;color:var(--text);}
.flist li::before{content:"";position:absolute;left:0;top:2px;width:18px;height:18px;border-radius:var(--radius-4);background:rgba(var(--blue-soft-rgb),.15);}
.flist li::after{content:"✓";position:absolute;left:4px;top:1px;font-size:12px;color:var(--teal);font-weight:700;}

/* ---------- filter tabs ---------- */
.tabs{display:flex;gap:var(--sp-8);flex-wrap:wrap;margin-bottom:30px;}
/* A .tab is a <button> where the filter is client-side and an <a> where it drives a
   query (the Insights tabs carry ?type=). text-decoration:none is for the anchor form;
   the rest applies to both. */
.tab{padding:9px 18px;border:1px solid var(--card-line);border-radius:999px;font-size:13.5px;font-weight:600;color:var(--text-2);cursor:pointer;transition:var(--dur-fast);background:transparent;font-family:var(--f-body);text-decoration:none;display:inline-flex;align-items:center;}
.tab:hover{border-color:var(--blue);color:#fff;}
.tab.on{background:var(--blue);border-color:var(--blue);color:#fff;}

/* ---------- forms ---------- */
.field{display:flex;flex-direction:column;gap:var(--sp-8);margin-bottom:18px;}
.field label{font-size:13px;font-weight:600;color:var(--text-2);}
.field input,.field select,.field textarea{
  font-family:var(--f-body);font-size:14.5px;color:#fff;background:#0B1526;
  border:1px solid var(--card-line);border-radius:var(--radius-8);padding:13px 15px;
  outline:3px solid transparent;
  transition:border-color var(--dur-fast),outline-color var(--dur-fast);
}
.field input::placeholder,.field textarea::placeholder{color:#54617a;}
/* The focus ring is an outline, not a box-shadow, and that is an accessibility fix rather
   than a tidy-up: forced-colors mode (Windows High Contrast) forces box-shadow to none, so this
   ring used to disappear completely for exactly the users who need it most, leaving a border
   colour change as the only cue. outline is not suppressed there.

   It is declared 3px transparent at rest and only the COLOUR changes on focus. Two reasons:
   outline never participates in layout, so reserving it costs nothing and cannot shift the
   caret; and the ring still fades, because outline-color is animatable — swapping the shadow
   for a plain outline on :focus alone would have made it snap, since box-shadow was in this
   element's transition list.

   Kept on :focus, not moved to :focus-visible. .ah-field uses :focus-visible and it is the
   better modern default, but changing it here would stop the ring appearing on mouse click,
   and that is a behaviour change nobody asked for.

   The chat form's input keeps its box-shadow on purpose: it is a 999px pill, and outline only
   follows border-radius from Safari 16.4, so on older Safari it would draw a rectangle around
   a pill. */
.field input:focus,.field select:focus,.field textarea:focus{border-color:var(--blue);outline-color:rgba(var(--blue-rgb),.18);}
.field textarea{resize:vertical;min-height:120px;}
.consent{display:flex;gap:var(--sp-8);align-items:flex-start;font-size:13px;color:var(--muted);line-height:1.5;}
.consent input{margin-top:2px;}

/* purpose routing chips */
.purpose{display:grid;grid-template-columns:repeat(2,1fr);gap:var(--sp-12);margin-bottom:22px;}
.purpose .opt{padding:16px;border:1px solid var(--card-line);border-radius:var(--radius-8);cursor:pointer;transition:var(--dur-fast);}
.purpose .opt:hover{border-color:var(--blue);}
.purpose .opt.on{border-color:var(--blue);background:rgba(var(--blue-rgb),.08);}
.purpose .opt .t{font:600 15px/1.2 var(--f-display);color:#fff;margin-bottom:5px;}
.purpose .opt .d{font-size:12.5px;color:var(--muted);}

/* ---------- footer (injected by app.js) ---------- */
/* dark premium footer — deep-navy gradient + tech dot-grid + a slow drifting glow (ambient "b-roll") */
.site-footer{position:relative;overflow:hidden;padding:118px 0 46px;margin-top:0;color:rgba(var(--white-rgb),.66);
  background:radial-gradient(85% 130% at 88% -20%,#0A3A7A,transparent 58%),linear-gradient(180deg,#04152E,#001B45 55%,#00265F);}
.site-footer::before{content:"";position:absolute;inset:0;pointer-events:none;opacity:.6;z-index:0;
  background:radial-gradient(rgba(var(--white-rgb),.05) 1px,transparent 1.4px);background-size:26px 26px;
  -webkit-mask-image:linear-gradient(180deg,#000,transparent 72%);mask-image:linear-gradient(180deg,#000,transparent 72%);}
.site-footer::after{content:"";position:absolute;left:-8%;top:-40%;width:56%;height:150%;pointer-events:none;z-index:0;
  background:radial-gradient(circle,rgba(var(--blue-rgb),.16),transparent 60%);animation:ah-cglow 16s ease-in-out infinite;}
.site-footer > .container{position:relative;z-index:1;}
.foot-grid{display:grid;grid-template-columns:1.7fr 1fr 1fr 1fr;gap:var(--sp-48);padding-bottom:60px;border-bottom:1px solid rgba(var(--white-rgb),.12);}
.foot-col h4{font-size:15px;font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:#fff;margin:0 0 20px;}
.foot-col .links{display:flex;flex-direction:column;gap:var(--sp-16);font-size:17px;}
.foot-col .links a{color:rgba(var(--white-rgb),.6);transition:color var(--dur-fast);}
.foot-col .links a:hover{color:var(--blue-soft);}
.foot-brand .brand{margin-bottom:22px;display:inline-block;}
.foot-brand .brand img{height:46px;width:auto;display:block;}
.foot-brand p{margin:0 0 24px;font-size:16.5px;line-height:1.66;color:rgba(var(--white-rgb),.54);max-width:320px;}
.social{display:flex;gap:var(--sp-8);}
.social a{width:40px;height:40px;border-radius:var(--radius-8);border:1px solid rgba(var(--white-rgb),.2);display:grid;place-items:center;font-size:13px;color:rgba(var(--white-rgb),.7);transition:var(--dur-fast);}
.social a:hover{border-color:var(--blue-soft);color:var(--blue-soft);background:rgba(var(--blue-soft-rgb),.1);}
.foot-bot{display:flex;align-items:center;justify-content:space-between;padding-top:34px;font-size:15px;color:rgba(var(--white-rgb),.48);flex-wrap:wrap;gap:var(--sp-12);}
.foot-bot .legal{display:flex;gap:var(--sp-24);flex-wrap:wrap;}
.foot-bot .legal a{color:rgba(var(--white-rgb),.48);transition:color var(--dur-fast);}
.foot-bot .legal a:hover{color:#fff;}

/* ---------- reveal animation ---------- */
/* Entrance animation REMOVED 2026-08-13, at the client's call. It faded, lifted and
   (until today) blurred every element as it entered the viewport. On the white page
   skin the in-between frames read as a haze band that trailed the scroll, and no
   amount of softening the timing got rid of it — so the effect is off entirely and
   content now paints in place.

   Killed here rather than in app.js: initObservers() still tags elements with .in,
   which is now inert. The .rl/.rr/.rs direction variants (base.css:300) carry their
   own transforms and are neutralised in the same rule — without that they would sit
   permanently offset. To restore the effect, delete this rule; the original values
   were opacity:0 / translateY(54px) scale(.95) / blur(8px). */
/* ── Section motion ───────────────────────────────────────────────────────────
   Two mechanisms for one design, picked per browser.

   PREFERRED — CSS scroll-driven animation. The element's state is bound to where it
   actually sits in the scrollport, not to a timer fired once on entry. That is the whole
   difference: scroll back up and it plays backwards, stop halfway and it holds halfway,
   and every element on the page is at a different point of the same curve. A triggered
   transition cannot do any of that.

   FALLBACK — the IntersectionObserver in app.js, which now also marks .rv-out when an
   element leaves, so exit exists there too. It adds .in and never removes it: .in is
   shared with the h1 word animation and the .stagger system (fx.js:1244), and toggling
   it off would break both.

   Motion is a rise through depth — translate on Z and a small rotateX — not a flat slide.
   No filter:blur() anywhere: that is what caused the haze this page was hunting earlier.
   No clip-path either; it would crop the box-shadows off every card that reveals. */
.reveal{
  /* Kept in step with the rvIn keyframes above: same 16px, same 4px blur, same absence of
     3D and of overshoot. This is the path browsers without scroll-driven animations take,
     and the two should not feel like different sites. */
  opacity:0;transform:translate3d(0,16px,0);filter:blur(4px);
  transition:opacity var(--dur-base) var(--ease),
             transform var(--dur-base) var(--ease),
             filter var(--dur-base) var(--ease);
}
.reveal.in{opacity:1;transform:translate3d(0,0,0);filter:blur(0);}
/* Leaving upward: recede rather than vanish — it reads as depth, not as content erasing
   itself. Not below .18 opacity, so a reader scrolling back finds it already legible. */
.reveal.in.rv-out{opacity:.18;transform:perspective(900px) translate3d(0,-30px,-60px) rotateX(-5deg);}
.reveal.d1{transition-delay:.06s}.reveal.d2{transition-delay:.12s}.reveal.d3{transition-delay:.18s}
.reveal.d4{transition-delay:.24s}.reveal.d5{transition-delay:.3s}.reveal.d6{transition-delay:.36s}

/* Not a slide — a landing. The block comes in tilted and set back in Z, overshoots its
   resting position at 72%, then settles. Under a scroll timeline that overshoot is not a
   flourish you miss: scrubbing holds it there, so the block visibly travels past its mark
   and comes back. That is the whole difference between "it faded in" and "it was placed". */
@keyframes rvIn{
  /* Was 54px of travel through 90px of Z with a 7-degree pitch and an overshoot frame at
     72%. The end state was never the problem; the middle was. These are scroll-linked, so
     an element sits at whatever frame the reader stopped scrolling on — which means every
     frame has to look like a finished design, and a tilted, receding, overshooting card
     does not. 16px with a 4px blur that resolves is the Innovation Lab's vocabulary, and
     it has no bad frame. */
  0%  {opacity:0;transform:translate3d(0,16px,0);filter:blur(4px);}
  100%{opacity:1;transform:translate3d(0,0,0);filter:blur(0);}
}

@supports (animation-timeline: view()){
  .reveal{
    opacity:1;transform:none;transition:none;
    /* rvIn is `backwards`, not `both`: `both` would hold its final frame forever,
       and since that frame writes `transform`, it would outrank every :hover rule on the
       page that also uses transform — the tiles' lift, the buttons' nudge — silently
       killing them. `backwards` fills only BEFORE the range; once the entrance is done the
       property goes back to the stylesheet, where hover can reach it again. Every keyframe
       here ends on the element's natural resting state, so dropping the fill is invisible. */
    /* rvOut is gone. It faded every element back to 18% and pulled it 30px away as it left
       the viewport, so each scroll step had a set arriving AND a set leaving, and scrolling
       back up replayed the page. Measured against the Lab mirror, that one animation was
       most of the gap:12 elements changing per scroll step there against 50 here, and 2
       against 18 on the way back. Things arrive now, and then stay arrived. */
    animation:rvIn linear backwards;
    animation-timeline:view();
    /* Every range now ENDS inside the entry phase — the phase that finishes the moment the
       element is fully on screen. The old ones ran to `cover 52%` and beyond, so a card
       could sit whole and centred in the viewport and still be at 61% opacity. That is what
       it looked like: a rendering fault rather than an entrance. */
    animation-range:entry 6% entry 86%;
  }
  /* The d1-d6 stagger becomes a shifted range rather than a delay: children of one block
     cross the same curve at slightly different scroll positions, so the cascade holds no
     matter how fast the page is scrolled. A delay cannot — scroll fast enough and every
     delayed element lands at once. */
  .reveal.d1{animation-range:entry 12% entry 90%;}
  .reveal.d2{animation-range:entry 18% entry 94%;}
  .reveal.d3{animation-range:entry 24% entry 98%;}
  .reveal.d4{animation-range:entry 30% entry 100%;}
  .reveal.d5{animation-range:entry 36% entry 100%;}
  .reveal.d6{animation-range:entry 42% entry 100%;}
  .reveal.in.rv-out{opacity:initial;transform:initial;}
  /* Above the fold at load: no scroll timeline. See app.js — a view() animation cannot
     finish without scrolling, so these fall back to the timed transition defined outside
     this block, which the observer triggers immediately. */
  .reveal.rv-now{animation:none;opacity:0;transform:translate3d(0,16px,0);filter:blur(4px);}
  .reveal.rv-now.in{opacity:1;transform:translate3d(0,0,0);filter:blur(0);}
}

/* The two reduced-motion blocks already force opacity/transform with !important, which
   outranks an animation — but the animation would still be running and burning frames.
   Stop it outright. */
@media (prefers-reduced-motion:reduce){
  .reveal{animation:none!important;transition:none!important;}
}

/* ── Listing pages: the Curtain entrance ──────────────────────────────────────
   At the client's call: an entrance, but not a fade. Content is uncovered at its position,
   it does not haze into it. The shared .reveal entrance is switched off on these five pages
   and replaced with the one below.

   WHY THESE PAGES. They are grids, not compositions — /customer-stories/ prints 45 cards,
   /insights/ 24, /press/ 20 — and the shared stagger gave every card its own delay, so a
   reader watched rows arrive in sequence rather than seeing a page. The tabs carry ?type=
   as real links, so every filter change is a full page load that replays it from the top.

   THE MOTION. The card is opaque throughout and never moves. A hard edge travels down it
   and the card is uncovered: clip-path inset from 100% to 0. No opacity ramp, no blur, no
   scale, no travel — every frame is a correctly rendered card with less of it showing,
   which is the one thing a fade can never be.

   Two variants were built and compared frame by frame. An angled edge (96deg) was the more
   obviously designed of the two and was rejected: on a 3-up grid it cuts diagonally through
   the headline, so mid-animation a title is sliced mid-word — that reads as broken, not as
   arriving. The flat edge always falls between content rows. A glowing hairline riding the
   edge was also built and dropped: a bright scanline is the 2010s idiom this is avoiding.

   WHY IT IS NOT ON A SCROLL TIMELINE. The obvious build was animation-timeline:view(), which
   is what the shared system's @supports block calls its preferred path. That block does not
   run. Measured on /service-cloud/, a page none of this touches: the .reveal card carries
   animation-name rvCard with a ViewTimeline attached and currentTime null — an inactive
   timeline, on every scroll-driven animation in the theme. The cause is body{overflow-x:
   hidden} at base.css:85: a non-visible overflow makes <body> a scroll container, the
   ViewTimeline binds to it, and body never scrolls because the viewport does. So every
   scroll-linked entrance in this file has always fallen through to the IntersectionObserver
   in app.js, and this one is built on the path that actually runs. (overflow-x:clip would
   revive them all — deliberately NOT changed here: it would switch on a large body of motion
   that has never once executed, including effects the client has already objected to. That
   is a decision to take on its own, not a side effect of this one.)

   FAILING VISIBLE. The closed state lives on .rv-curtain, a class initCurtain() adds at
   runtime — it is never in the stylesheet on its own. If the script is blocked or throws,
   the class never lands and the cards are simply there. Without that the page is worse than
   before the change: measured in an earlier build of this rule, 24 cards on /insights/ sat
   at inset(0 0 100%) with nothing ever opening them. The shared system carries the same
   hazard as opacity:0 and pays a ghost for it; a clip would cost the whole card.

   THE STAGGER IS BY COLUMN, NOT BY CARD. This is what fixes the queue: three delays repeating
   across the grid mean a row is uncovered by one wave crossing it left to right, so 45 cards
   read as a handful of gestures instead of 45 events. The .d1-.d5 the template stamps on each
   card is overridden; that was the source of the queue.

   clip-path rather than mask-image: compositor-friendly, which matters at 45 cards, and
   `round 16px` keeps the card's radius through the animation. .rcard carries no box-shadow
   so nothing is clipped; .card does, and its shadow is briefly clipped while the wipe runs,
   which at this duration and that shadow's weight is not perceptible. */
body:is(.pg-insights,.pg-articles,.pg-press,.pg-whitepapers,.pg-customer-stories) .reveal{
  animation:none!important;
  transition:none!important;
  opacity:1!important;
  transform:none!important;
  filter:none!important;
}
/* Four parts, not one, and all four on Accenture's own numbers — 550ms and
   cubic-bezier(.85,0,0,1), which are the duration and the curve their design system uses more
   than any other (62 and 263 occurrences respectively in their clientlib-rad stylesheet).

   The single clip wipe that was here was doing one thing at one speed, which is what made it
   read as plain. What their entrance keyframes actually do — hero-content-reveal is
   translateY(100%) to 0, editorialAnimation is translateY(120%) rotate(6deg) to 0,
   gradient-line-in is width 0 to 100% — is move things a LONG way from outside their own box
   and let an overflow-hidden parent do the revealing. Distance is most of the character;
   14px of travel cannot read as anything.

   So: the frame is uncovered, the photograph settles inside it while that happens, the copy
   rises a full body-height into the space just uncovered, and a rule draws itself along the
   foot. Four beats over 550ms, none of them a fade, a blur or a scale. */
@keyframes rvCurtain{
  from{clip-path:inset(0 0 100% 0 round 16px);}
  to  {clip-path:inset(0 0 0    0 round 16px);}
}
/* The photograph settles as the frame uncovers it — the two move at different speeds, which
   is the same parallax relationship their page transition gets from moving the outgoing page
   a quarter of the way and the incoming one the whole way. */
@keyframes rvCurtainMedia{
  from{transform:translateY(7%);}
  to  {transform:none;}
}
/* Their hero-content-reveal, at card scale: the copy comes up from outside the card and the
   card's own overflow:hidden does the masking. No opacity anywhere in it. */
@keyframes rvCurtainBody{
  from{transform:translateY(108%);}
  to  {transform:none;}
}
/* A fourth part was built and dropped: their gradient-line-in, a rule drawn along the card's
   foot. Their design system does use it (deco-line-in, gradient-line-in) but it has nowhere to
   read here — a 2px line at the bottom of a dark photograph under a dark scrim, which is where
   their own cards would put a light ground. Three parts that all show beats four with one of
   them invisible. */
/* .rv-curtain and .rv-open are both applied by initCurtain() in app.js — the closed state
   never exists in the stylesheet alone, so no script means no clip and the cards are simply
   there. */
/* !important on the animation, and it is not decoration: the rule above switches the shared
   entrance off with `animation:none!important` on .reveal, and these cards ARE .reveal.
   !important beats specificity, so without it here the open animation never ran and the card
   stayed at inset(0 0 100%) — a blank grid. That shipped once; this is the fix. */
:is(.rcard,.card).rv-curtain{clip-path:inset(0 0 100% 0 round 16px);}
:is(.rcard,.card).rv-curtain.rv-open{
  animation:rvCurtain var(--rv-dur) var(--rv-ease) var(--rv-delay,0s) both!important;
}
.rcard.rv-curtain.rv-open img{
  animation:rvCurtainMedia var(--rv-dur) var(--rv-ease) var(--rv-delay,0s) both;
}
.rcard.rv-curtain.rv-open .rc-body{
  /* starts a beat after the frame, so the copy lands in space that has just been uncovered
     rather than travelling behind the curtain where nobody can see it */
  animation:rvCurtainBody var(--rv-dur) var(--rv-ease) calc(var(--rv-delay,0s) + .17s) both;
}
/* Their two constants, in one place so the whole entrance moves together. */
:is(.rcard,.card).rv-curtain{--rv-dur:.55s;--rv-ease:cubic-bezier(.85,0,0,1);}
/* One wave per row. */
:is(.rcard,.card).rv-curtain:nth-child(3n+2){--rv-delay:.085s;}
:is(.rcard,.card).rv-curtain:nth-child(3n+3){--rv-delay:.17s;}
@media (max-width:900px){
  /* Two up, so the wave is two beats. */
  :is(.rcard,.card).rv-curtain:nth-child(3n+2),
  :is(.rcard,.card).rv-curtain:nth-child(3n+3){--rv-delay:0s;}
  :is(.rcard,.card).rv-curtain:nth-child(2n){--rv-delay:.085s;}
}
@media (max-width:640px){
  /* One up: no wave to make, and a delay on a single column is just a wait. */
  :is(.rcard,.card).rv-curtain{--rv-delay:0s!important;}
}
@media (prefers-reduced-motion:reduce){
  :is(.rcard,.card).rv-curtain,
  :is(.rcard,.card).rv-curtain.rv-open{clip-path:none!important;animation:none!important;}
}

/* Section headings strike a short brand rule as they land. Deliberately 56px, not a full
   underline — an accent mark, the way an editorial page marks a section, not a decoration
   that turns every heading into a boxed-out header.
   Scoped to .h2 only. The hero .h1 is left alone: it is the one heading whose composition
   is being reworked separately, and a rule there would fight whatever lands.
   Matched in two shapes because a heading is sometimes the .reveal itself and sometimes a
   child of one. */
.h2.reveal::after,
.reveal .h2::after{
  content:"";display:block;height:2px;width:56px;margin-top:16px;border-radius:var(--radius-4);
  background:var(--grad-anniv);
  transform:scaleX(0);transform-origin:left center;
  transition:transform var(--dur-base) var(--ease) var(--dur-fast);
}
.h2.reveal.in::after,
.reveal.in .h2::after{transform:scaleX(1);}

@supports (animation-timeline: view()){
  .h2.reveal::after,
  .reveal .h2::after{
    transform:scaleX(0);transition:none;
    animation:rvRule linear both;
    animation-timeline:view();
    /* Starts after the block itself has essentially landed, so the rule reads as the last
       move of the sequence rather than racing the text it belongs to. */
    animation-range:entry 14% entry 82%;
  }
}
@keyframes rvRule{
  0%  {transform:scaleX(0);}
  100%{transform:scaleX(1);}
}
@media (prefers-reduced-motion:reduce){
  .h2.reveal::after,.reveal .h2::after{transform:scaleX(1);animation:none!important;transition:none!important;}
}
@media (prefers-reduced-motion:reduce){
  .reveal{opacity:1!important;transform:none!important;}
  .float,.float-2,.marquee .track{animation:none!important;}
  html{scroll-behavior:auto;}
}

/* ---------- responsive ---------- */
@media (max-width:1000px){
  :root{--pad:28px;--header-h:80px;}
  .h1{font-size:48px;}
  .h2{font-size:32px;}
  .metrics{grid-template-columns:repeat(2,1fr);}
  .metric:nth-child(2){border-right:0;}
  .metric:nth-child(1),.metric:nth-child(2){border-bottom:1px solid var(--line);}
  .g-3,.g-4,.g-5{grid-template-columns:repeat(2,1fr);}
  .foot-grid{grid-template-columns:1fr 1fr 1fr;gap:var(--sp-24);}
  .foot-brand{grid-column:1/-1;}
}
@media (max-width:720px){
  .nav-links,.nav-right .lang,.nav-right .nav-sep{display:none;}
  .nav-burger{display:flex;}
  .mobile-menu{display:block;position:fixed;inset:var(--header-h) 0 0;background:var(--bg);z-index:320;padding:24px var(--pad);transform:translateX(100%);transition:transform var(--dur-base) var(--ease);overflow-y:auto;}
  .mobile-menu.open{transform:none;}
  .mobile-menu :is(a,button.m-link){display:block;padding:16px 0;font:600 20px/1 var(--f-display);color:#fff;border-bottom:1px solid var(--line);}
  .h1{font-size:38px;}
  .hero{padding:60px 0 56px;}
  .g-2,.g-3,.g-4,.g-5{grid-template-columns:1fr;}
  .metrics{grid-template-columns:1fr;}
  .metric{border-right:0!important;border-bottom:1px solid var(--line);}
  .section,.section-lg{padding-top:56px;padding-bottom:16px;}
  .cta-band .inner{flex-direction:column;align-items:flex-start;}
  .trust{flex-direction:column;align-items:flex-start;}
  .foot-grid{grid-template-columns:1fr 1fr;}
  .purpose{grid-template-columns:1fr;}
  .hero-split,.zz{grid-template-columns:1fr;gap:var(--sp-28);}
  .zz.rev .txt{order:1;}.zz.rev .media{order:2;}
  .gallery{grid-template-columns:1fr 1fr;grid-auto-rows:150px;}
  .hero-image{min-height:0;}
}
@media (max-width:1000px){
  .hero-split{grid-template-columns:1fr;gap:var(--sp-28);}
}

/* =====================================================================
   LIGHT THEME — brand-white skin (Beyondsoft). Overrides dark defaults.
   ===================================================================== */
::selection{background:rgba(var(--blue-rgb),.20);color:#26292C;}
body::-webkit-scrollbar-track{background:#EEF2F8;}
body::-webkit-scrollbar-thumb{background:#CBD5E3;border:2px solid #EEF2F8;}
body::-webkit-scrollbar-thumb:hover{background:#B4C0D2;}

/* real logo in header + footer */
.brand{display:inline-flex;align-items:center;}
/* 82px was tall enough that the mark set the height of the whole header bar. 64 keeps it
   the most prominent thing up there without the bar being built around it. */
.brand img{height:64px;width:auto;display:block;}

/* buttons */
.btn-ghost{color:var(--ink);}
.btn-primary{box-shadow:0 8px 22px -12px rgba(var(--blue-rgb),.7);}

/* header */
.site-header{background:rgba(var(--white-rgb),0);}
.site-header.scrolled{background:rgba(var(--white-rgb),.9);border-bottom:1px solid var(--line);box-shadow:var(--sh-contact);}
/* home: keep the header WHITE; the hero canvas fades its own top to white so the
   white header dissolves softly into the blue network below (no hard seam) */
.home .site-header:not(.scrolled){background:#ffffff;}
.nav-links :is(a,button):hover,.nav-links :is(a,button).active{color:var(--ink);}
.nav-burger span{background:var(--ink);}
.lang-menu{background:#fff;border-color:var(--card-line);box-shadow:var(--sh-raised);}
.lang-menu a:hover{background:rgba(var(--ink-rgb),.05);color:var(--ink);}

/* softened glows on light bg */
.glow-blue{background:radial-gradient(circle at 30% 30%,rgba(var(--blue-rgb),.13),rgba(var(--blue-rgb),0) 62%);filter:blur(6px);}
.glow-teal{background:radial-gradient(circle at 50% 50%,rgba(var(--blue-rgb),.11),rgba(var(--blue-rgb),0) 60%);}

/* surfaces / text */
.metric .num{color:var(--ink);}
.card{box-shadow:var(--sh-contact);}
.card h3{color:var(--ink);}
.card.feature-teal{background:linear-gradient(180deg,#ECF8F5,#E0F2EC);}
.acc,.trust{box-shadow:var(--sh-contact);}
.acc-h .t{color:var(--ink);}
.acc-h:hover{background:rgba(var(--ink-rgb),.03);}
.tile.on{background:linear-gradient(160deg,var(--blue),var(--aux-purple));color:#fff;}
.tab:hover{color:var(--blue);}
.purpose .opt .t{color:var(--ink);}
.ptable td:first-child{color:var(--ink);}
.bignum{-webkit-text-stroke:1.5px rgba(var(--ink-rgb),.16);}
.media{background:#E9EEF5;}
.hero-split .media{box-shadow:var(--sh-raised);}

/* accent shimmer hues on brand */
.accent{background:linear-gradient(90deg,var(--blue),var(--aux-purple),var(--blue));background-size:200% auto;-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;color:transparent;}

/* forms */
.field input,.field select,.field textarea{color:var(--ink);background:#fff;}
.field input::placeholder,.field textarea::placeholder{color:#9AA6B5;}

/* sections that sit over DARK photos/gradients keep light text on any theme */
.hero-image .h1{color:#fff;}
.hero-image .lead{color:rgba(var(--white-rgb),.86);}
.hero-image .crumbs,.hero-image .crumbs a{color:rgba(var(--white-rgb),.72);}
.hero-image .eyebrow{color:var(--blue-soft);}
.hero-image .btn-ghost{color:#fff;border-color:rgba(var(--white-rgb),.4);}
.hero-image .grad-text,.band .grad-text,.cta-band .grad-text{background:linear-gradient(100deg,var(--blue),var(--blue-soft));background-size:200% auto;-webkit-background-clip:text;background-clip:text;color:transparent;}
.band .h2{color:#fff;}
.band .eyebrow{color:var(--blue-soft);}
.band p{color:rgba(var(--white-rgb),.88)!important;}
.band .btn-ghost{color:#fff;border-color:rgba(var(--white-rgb),.4);}
.cta-band{background:linear-gradient(120deg,var(--blue) 0%,var(--aux-purple) 55%,#7A1E86 100%);}
.cta-band .h2{color:#fff;}
.cta-band p{color:rgba(var(--white-rgb),.9)!important;}
.cta-band .btn-ghost{color:#fff;border-color:rgba(var(--white-rgb),.45);}

/* footer h4 stays white on the dark footer */
.foot-col h4{color:#fff;}

/* mobile menu */
.mobile-menu{background:#fff;}
.mobile-menu :is(a,button.m-link){color:var(--ink);border-bottom:1px solid var(--line);}

/* cookie consent (light) */
/* Opaque, and no backdrop blur. At .96 with blur(14px) behind it, the consent bar read as
   a band of white haze laid over the hero rather than as a bar sitting in front of it —
   the artwork behind stayed just visible enough to look washed out instead of covered.
   Solid white is honest about being an overlay, and costs one less compositing pass. */
/* The shadow on this one points UP, because the banner is fixed to the bottom of the viewport
   and the surface it has to lift away from is above it. --sh-contact is a downward tier and
   was substituted here by the elevation sweep, which put the shadow underneath the screen
   edge where nothing can see it. Kept as a literal rather than adding a fourth tier for a
   single component. */
.cookie-banner{background:#fff;border-top:1px solid var(--card-line-hi);box-shadow:0 -8px 30px -18px rgba(var(--ink-rgb),.22);-webkit-backdrop-filter:none;backdrop-filter:none;}
.btn-mini{color:var(--ink);border-color:var(--card-line-hi);}
.cookie-modal .backdrop{background:rgba(15,30,51,.45);}
.cookie-modal .panel{background:#fff;border-color:var(--card-line-hi);box-shadow:var(--sh-float);}
.cookie-modal h3{color:var(--ink);}
.ck-cat h4{color:var(--ink);}
.switch .slider{background:#CBD5E3;}

/* ============ mega-menu (premium dark panel) ============ */
.nav-links{align-items:center;}
.nav-item{position:relative;display:flex;align-items:center;}
.nav-item .chev{font-size:8px;opacity:.5;margin-left:5px;pointer-events:none;transition:transform var(--dur-fast),opacity var(--dur-fast);}
.nav-item:hover .chev,.nav-item:focus-within .chev{transform:rotate(180deg);opacity:.9;}
/* full-bleed dark mega, anchored flush under the sticky header (Accenture-style) */
.mega{--acc:var(--blue-soft);
  position:fixed;top:var(--header-h);left:0;right:0;width:100%;max-width:100%;
  background:linear-gradient(160deg,#002E72 0%,#001F4D 100%);
  border:0;border-top:1px solid rgba(var(--blue-soft-rgb),.16);border-radius:0;
  box-shadow:0 34px 60px -30px rgba(4,12,30,.6);
  padding:0;color:#fff;overflow:hidden;
  opacity:0;visibility:hidden;transform:translateY(-8px);
  transition:opacity var(--dur-fast) var(--ease),transform var(--dur-fast) var(--ease),visibility var(--dur-fast);z-index:55;}
/* dropdown ground stays a brand navy; only the accent colour changes per section */
.mega[data-accent="blue"]{--acc:var(--blue-soft);}
.mega[data-accent="multi"]{--acc:var(--blue-soft);}
.mega[data-accent="teal"]{--acc:var(--blue);}
.mega[data-accent="indigo"]{--acc:var(--blue);}
.mega[data-accent="steel"]{--acc:var(--blue-soft);}
.mega::before{content:"";position:absolute;top:-34px;left:0;right:0;height:36px;}
.nav-item:hover>.mega,.nav-item:focus-within>.mega{opacity:1;visibility:visible;transform:none;}
.mega-in{max-width:var(--maxw);margin:0 auto;padding:44px var(--pad) 56px;display:flex;flex-direction:column;gap:var(--sp-28);}
.mega-head{position:relative;z-index:1;}
.mega-head .mt{display:inline-flex;align-items:center;gap:var(--sp-12);font:700 clamp(28px,3vw,38px)/1.05 var(--f-display);letter-spacing:-.025em;margin:0 0 10px;color:#fff;text-decoration:none;}
/* The chevron tile that used to sit after the panel title is gone. It was there when the
   title was a link and it read as "go here"; the title is a <span> now and points nowhere,
   so the arrow was pointing at nothing. */

.mega-head .tg{font-size:13.5px;line-height:1.5;color:rgba(var(--white-rgb),.5);margin:0 0 12px;max-width:42ch;}
.mega-head .all{font-size:13px;font-weight:600;color:var(--acc);display:inline-flex;gap:var(--sp-4);transition:gap var(--dur-fast);}
.mega-head .all:hover{gap:var(--sp-12);}
.mega-cols{display:flex;gap:var(--sp-56);position:relative;z-index:1;align-items:flex-start;flex-wrap:wrap;}
.mega-col h5{font:600 11px/1 var(--f-mono);letter-spacing:.14em;text-transform:uppercase;color:rgba(var(--white-rgb),.38);margin:0 0 18px;}
.mega-col.grid{min-width:380px;}
.mega-col.grid .mcl{column-count:2;column-gap:var(--sp-56);}
.mega-col a{display:block;padding:9px 0;font-size:16px;color:rgba(var(--white-rgb),.84);white-space:nowrap;transition:color var(--dur-fast),transform var(--dur-fast);}
.mega-col a::after{content:"\2192";margin-left:7px;opacity:0;transition:opacity var(--dur-fast),margin var(--dur-fast);}
.mega-col a:hover{color:var(--acc);transform:translateX(2px);}
.mega-col a:hover::after{opacity:.75;margin-left:10px;}
/* feature promo tile — accent-tinted glass card (matches the news cards) */
.mega-feature{position:relative;overflow:hidden;margin-left:auto;align-self:center;min-width:292px;max-width:344px;
  border-radius:var(--radius-20);padding:26px 26px 24px;
  background:linear-gradient(158deg,color-mix(in srgb,var(--acc) 26%,#0A3F87) 0%,#072C64 60%,#04214C 100%);
  border:1px solid color-mix(in srgb,var(--acc) 42%,transparent);
  box-shadow:inset 0 1px 0 rgba(var(--white-rgb),.10),0 26px 52px -26px rgba(0,10,30,.72);
  display:flex;flex-direction:column;align-items:flex-start;gap:var(--sp-12);
  transition:transform var(--dur-fast) var(--ease),box-shadow var(--dur-fast) var(--ease),border-color var(--dur-fast);}
.mega-feature::before{content:"";position:absolute;inset:0;z-index:0;pointer-events:none;opacity:.85;
  background:radial-gradient(92% 78% at 100% 0%,color-mix(in srgb,var(--acc) 58%,transparent),transparent 62%),
    radial-gradient(rgba(var(--white-rgb),.06) 1px,transparent 1.3px);
  background-size:auto,18px 18px;
  -webkit-mask-image:linear-gradient(180deg,#000,transparent 88%);mask-image:linear-gradient(180deg,#000,transparent 88%);}
.mega-feature>*{position:relative;z-index:1;}
.mega-feature:hover{transform:translateY(-3px);border-color:color-mix(in srgb,var(--acc) 66%,transparent);
  box-shadow:inset 0 1px 0 rgba(var(--white-rgb),.14),0 32px 58px -24px color-mix(in srgb,var(--acc) 40%,#00040f);}
.mega-feature:focus{outline:none;}
.mega-feature:focus-visible{outline:2px solid var(--acc);outline-offset:3px;}
.mf-tag{display:inline-flex;align-items:center;gap:var(--sp-8);font:600 10px/1 var(--f-mono);letter-spacing:.14em;text-transform:uppercase;color:var(--acc);}
.mf-tag::before{content:"";width:6px;height:6px;border-radius:50%;background:var(--acc);box-shadow:0 0 8px var(--acc);}
.mega-feature h5{font:600 18px/1.25 var(--f-display);color:#fff;margin:0;text-transform:none;letter-spacing:-.01em;}
.mega-feature p{font-size:13px;line-height:1.5;color:rgba(var(--white-rgb),.6);margin:0;}
.mega-feature .mf-cta{margin-top:4px;display:inline-flex;align-items:center;gap:var(--sp-4);color:var(--acc);font-weight:700;font-size:13.5px;}
/* ---- dropdown polish: tighter panel, accent sweep, staggered reveal, link markers, scrim ---- */
.mega-in{padding:34px var(--pad) 40px;}
.mega-cols{gap:var(--sp-48);}
.mega-feature .mf-cta{transition:gap var(--dur-fast) var(--ease);}
.mega-feature:hover .mf-cta{gap:var(--sp-12);}
/* section-accent line sweeps across the top edge as the panel opens */
.mega::after{content:"";position:absolute;top:0;left:0;height:2px;width:100%;background:var(--acc);
  transform:scaleX(0);transform-origin:left center;transition:transform var(--dur-base) var(--ease);}
.nav-item:hover>.mega::after,.nav-item:focus-within>.mega::after{transform:scaleX(1);}
/* internal content cascades in after the panel drops (uses `translate` so it never fights hover transforms) */
.mega-head,.mega-cols>*{opacity:0;translate:0 9px;transition:opacity var(--dur-base) var(--ease),translate var(--dur-base) var(--ease);}
.nav-item:hover>.mega .mega-head,.nav-item:focus-within>.mega .mega-head{opacity:1;translate:0 0;transition-delay:.05s;}
.nav-item:hover>.mega .mega-cols>*,.nav-item:focus-within>.mega .mega-cols>*{opacity:1;translate:0 0;}
.nav-item:hover>.mega .mega-cols>*:nth-child(1),.nav-item:focus-within>.mega .mega-cols>*:nth-child(1){transition-delay:.10s;}
.nav-item:hover>.mega .mega-cols>*:nth-child(2),.nav-item:focus-within>.mega .mega-cols>*:nth-child(2){transition-delay:.15s;}
.nav-item:hover>.mega .mega-cols>*:nth-child(3),.nav-item:focus-within>.mega .mega-cols>*:nth-child(3){transition-delay:.20s;}
/* brand-diamond marker before each link */
.mega-col a{position:relative;padding-left:17px;}
.mega-col a::before{content:"";position:absolute;left:0;top:50%;width:6px;height:6px;margin-top:-3px;background:var(--acc);opacity:.34;transform:rotate(45deg);transition:opacity var(--dur-fast),transform var(--dur-fast);}
.mega-col a:hover::before{opacity:1;transform:rotate(45deg);}
/* Dim the page behind an open dropdown — starting BELOW the bar, not at the top of the
   viewport. The header paints no background of its own (rgba(var(--white-rgb),0)), so an
   inset:0 scrim showed straight through it: the bar and the logo greyed out along with
   the page, which is the one part of the screen that should stay lit while a menu is
   open. Stacking order was never the problem — the header sits at z-index 60, above the
   scrim's 50 — the bar was simply see-through. */
.nav-scrim{position:fixed;top:var(--header-h);left:0;right:0;bottom:0;z-index:50;background:rgba(2,10,26,.34);opacity:0;visibility:hidden;pointer-events:none;transition:opacity var(--dur-base) var(--ease),visibility var(--dur-base);}
body.nav-open .nav-scrim{opacity:1;visibility:visible;}
@media (prefers-reduced-motion:reduce){
  .mega::after{transition:none;}
  .mega-head,.mega-cols>*{opacity:1!important;translate:none!important;transition:none!important;}
  .nav-scrim{transition:none;}
}
/* skip link (a11y) */
.skip-link{position:fixed;left:14px;top:-60px;z-index:400;background:var(--blue);color:#fff;padding:10px 16px;border-radius:var(--radius-8);font-weight:600;transition:top var(--dur-fast);}
.skip-link:focus{top:14px;outline:2px solid #fff;}
@media (max-width:720px){
  .mega,.nav-item .chev{display:none!important;}
  .nav-right .btn-primary{display:none;}
  .brand img{height:48px;}
  .mobile-menu .m-sub{display:block;padding:11px 0 11px 16px;font:500 15px/1 var(--f-body);color:var(--muted);border-bottom:1px solid var(--line);}
}
@media (max-width:420px){
  .cookie-actions{flex-direction:column;}
  .cookie-actions .btn,.cookie-actions .btn-mini{width:100%;}
}

/* ============ fresh interaction layer (auto-applied) ============ */
/* gentle page fade-in on every navigation */
@keyframes fadeInPage{from{opacity:.35;}to{opacity:1;}}
body{animation:fadeInPage .55s var(--ease) both;}
/* breathing hero glows — feel alive */
@keyframes breathe{0%,100%{opacity:.7;}50%{opacity:1;}}
.glow-blue{animation:floaty 16s ease-in-out infinite, breathe 10s ease-in-out infinite;}
.glow-teal{animation:floaty 20s ease-in-out infinite reverse, breathe 13s ease-in-out infinite;}
@media (prefers-reduced-motion:reduce){
  body{animation:none;}
  .glow-blue,.glow-teal{animation:none;}
}

/* ============ STRONG interactions ============ */
/* cards: overflow for shine sweep, bolder hover shadow */
.card{overflow:hidden;}
.card-link:hover,.card:hover{box-shadow:0 36px 70px -30px rgba(var(--blue-rgb),.5),0 0 0 1px rgba(var(--blue-rgb),.16);}
.card::after{content:"";position:absolute;top:-12%;left:-75%;width:50%;height:124%;pointer-events:none;z-index:3;
  background:linear-gradient(100deg,transparent,rgba(var(--white-rgb),.55),transparent);transform:skewX(-18deg);opacity:0;}
.card:hover::after{animation:cardshine .85s ease;}
@keyframes cardshine{0%{left:-75%;opacity:0;}18%{opacity:.9;}100%{left:135%;opacity:0;}}
/* headline word-by-word rise (JS wraps words) */
.h1 .w{display:inline-block;overflow:hidden;vertical-align:top;padding:0 .01em;}
.h1 .wi{display:inline-block;transform:translateY(118%) rotate(6deg);opacity:0;transition:transform var(--dur-base) var(--ease),opacity var(--dur-base);}
.h1.words-in .wi{transform:none;opacity:1;}
@media (prefers-reduced-motion:reduce){
  .card::after{display:none;}
  .h1 .wi{transform:none;opacity:1;}
}

/* ============ content-level hover — the CONTENT reacts, not the container ============ */
/* gentle lift replaces the old exaggerated 3D tilt */
.card-link{transition:transform var(--dur-base) var(--ease),box-shadow var(--dur-base) var(--ease),border-color var(--dur-fast);}
.card-link:hover{transform:translateY(-6px);}
/* glyph icon lifts + warms */
.card-link > .icon{transition:transform var(--dur-base) var(--ease),background var(--dur-base),color var(--dur-base);}
.card-link:hover > .icon{transform:translateY(-6px) rotate(-4deg);}
/* heading takes brand colour + an underline draws left-to-right */
.card-link h3{
  background-image:linear-gradient(var(--blue),var(--blue));
  background-size:0% 2px;background-position:0 100%;background-repeat:no-repeat;
  padding-bottom:2px;
  /* Two speeds on purpose: the colour answers at once and the underline draws in behind it.
     The duration sweep collapsed both onto one token and left the rule declaring `transition`
     twice, so the second won and the underline lost its trail. */
  transition:color var(--dur-fast) var(--ease),background-size var(--dur-base) var(--ease);
}
.card-link:hover h3{color:var(--blue);background-size:100% 2px;}
/* arrow / read-more slide forward */
.card-link .arrow,.card-link .link-more{transition:transform var(--dur-base) var(--ease),gap var(--dur-base),color var(--dur-base);}
.card-link:hover .arrow{transform:translateX(6px);}
.card-link:hover .link-more{gap:var(--sp-12);color:var(--blue);}
/* image gently pushes in */
.card-link .media img,.icard .media img{transition:transform var(--dur-base) var(--ease);}

@media (prefers-reduced-motion:reduce){
  .card-link,.card-link:hover,.card-link > .icon,.card-link h3,.card-link .media img{transition:none;transform:none;}
  .card-link h3{background-size:0 2px;}
}

/* ==================================================================
   CONTENT INTERACTION MODULES (the content itself reacts)
   ================================================================== */

/* --- 1. scroll-pinned storytelling --- */
.scrolly{position:relative;display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-56);align-items:start;}
.scrolly-media{position:sticky;top:118px;height:min(70vh,520px);border-radius:var(--radius-20);overflow:hidden;border:1px solid var(--card-line);box-shadow:0 44px 90px -44px rgba(var(--blue-rgb),.42);}
.scrolly-media .sm{position:absolute;inset:0;opacity:0;transform:scale(1.07);transition:opacity var(--dur-base) var(--ease),transform var(--dur-slow) var(--ease);}
.scrolly-media .sm.on{opacity:1;transform:scale(1);}
.scrolly-media .sm::after{content:"";position:absolute;inset:0;background:linear-gradient(180deg,rgba(9,26,48,.04),rgba(9,26,48,.58));}
.scrolly-media .sm img{width:100%;height:100%;object-fit:cover;}
.scrolly-media .sm-num{position:absolute;left:28px;bottom:22px;z-index:2;font:700 clamp(46px,7vw,84px)/1 var(--f-display);color:#fff;letter-spacing:-.03em;text-shadow:0 6px 30px rgba(0,0,0,.45);}
.scrolly-steps{display:flex;flex-direction:column;}
.scrolly-step{min-height:60vh;display:flex;flex-direction:column;justify-content:center;opacity:.38;transition:opacity var(--dur-base) var(--ease);}
.scrolly-step.active{opacity:1;}
.scrolly-step .st-k{font:600 13px/1 var(--f-mono);color:var(--muted-2);letter-spacing:.16em;}
.scrolly-step h3{font:700 clamp(24px,3vw,34px)/1.12 var(--f-display);margin:12px 0 12px;color:var(--ink);}
.scrolly-step p{font-size:16.5px;line-height:1.7;color:var(--muted);max-width:440px;margin:0;}
.scrolly-step .st-bar{height:2px;width:0;background:var(--blue);margin-top:22px;border-radius:var(--radius-4);transition:width var(--dur-base) var(--ease);}
.scrolly-step.active .st-bar{width:66px;}
@media (max-width:860px){
  .scrolly{grid-template-columns:1fr;gap:var(--sp-12);}
  .scrolly-media{position:relative;top:0;height:230px;order:-1;}
  .scrolly-step{min-height:0;opacity:1;padding:18px 0;border-top:1px solid var(--line);}
  .scrolly-step .st-bar{width:66px;}
}

/* --- 2. interactive services explorer --- */
.explorer{display:grid;grid-template-columns:1fr 1.12fr;gap:var(--sp-40);align-items:stretch;}
.exp-item{display:flex;align-items:center;gap:var(--sp-16);padding:19px 20px;border-radius:var(--radius-14);cursor:pointer;border:1px solid transparent;transition:background var(--dur-fast),border-color var(--dur-fast),box-shadow var(--dur-fast);}
.exp-item .ei-ic{width:44px;height:44px;flex:0 0 auto;display:grid;place-items:center;border-radius:var(--radius-8);background:rgba(var(--blue-rgb),.08);color:var(--blue);font-size:20px;transition:transform var(--dur-base),background var(--dur-base),color var(--dur-base);}
.exp-item .ei-t{font:600 17.5px/1.25 var(--f-display);color:var(--ink);}
.exp-item .ei-ar{margin-left:auto;color:var(--muted-2);opacity:0;transform:translateX(-6px);transition:opacity var(--dur-fast),transform var(--dur-fast);}
.exp-item:hover,.exp-item.on{background:#fff;border-color:var(--card-line-hi);box-shadow:0 18px 42px -24px rgba(var(--blue-rgb),.42);}
.exp-item.on .ei-ic{background:var(--blue);color:#fff;transform:translateY(-2px) scale(1.05);}
.exp-item.on .ei-ar{opacity:1;transform:none;color:var(--blue);}
.exp-pane{position:absolute;inset:0;opacity:0;visibility:hidden;transition:opacity var(--dur-base) var(--ease);}
.exp-pane.on{opacity:1;visibility:visible;}
.exp-pane img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;transform:scale(1.05);transition:transform 7s var(--ease);}
.exp-pane.on img{transform:scale(1.13);}
.exp-pane .ep-body{position:absolute;left:0;right:0;bottom:0;padding:32px 30px 30px;z-index:2;background:linear-gradient(180deg,transparent,rgba(9,24,45,.84) 58%);color:#fff;}
.exp-pane .ep-body h3{font:700 24px/1.2 var(--f-display);margin:0 0 8px;color:#fff;}
.exp-pane .ep-body p{font-size:15px;line-height:1.6;color:rgba(var(--white-rgb),.86);margin:0 0 16px;max-width:440px;}
.exp-pane .ep-body .link-more{color:#fff;}
@media (max-width:860px){
  .explorer{grid-template-columns:1fr;gap:var(--sp-16);}
  .exp-preview{min-height:290px;order:-1;}
  .exp-item{padding:14px;}
}

/* --- 3. reveal-on-hover media cards --- */
.rcard{position:relative;display:block;border-radius:var(--radius-14);overflow:hidden;border:1px solid var(--card-line);min-height:344px;}
.rcard img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;}
/* No pointer state on the PICTURE. Removed at the client's call: "Insights 鼠标放上去图片
   会模糊掉 我不要这个效果".

   What stood here was accenture.com's device from their rad.css — the frame holds still and
   the photograph blows out: width to 260%, filter:blur(64px), opacity:.5, all clipped by the
   frame's overflow:hidden, so the picture stopped being a picture and became a colour field
   behind the type. It is gone, along with the transition that drove it, on every page that
   uses this card — /insights/, /customer-stories/, /articles/, /press/ and /whitepapers/,
   which is the whole point of removing it here rather than on the one page reported.

   Nothing replaces it, because nothing needs to: .rcard already carries .fx-card, so under a
   fine pointer the card still answers with the pointer-tracked tilt and the moving glare
   (see the CARDS section further down), and the scrim, the tag and "Read the story" are all
   present at rest. A hover zoom is not an option either — that is out at the client's
   standing call, and has been cleared from this file once already.

   Deliberately not reinstated in any softened form (a 4px blur, a slight fade): the objection
   is to the picture changing under the pointer, not to how far it went. */
.rcard::after{content:"";position:absolute;inset:0;background:linear-gradient(180deg,rgba(9,24,45,.04) 28%,rgba(9,24,45,.88));transition:background var(--dur-base);}

/* The description and the "Read the story" link used to be hidden at max-height:0 /
   opacity:0 and revealed only by .rcard:hover. That was not merely a taste call: there was
   no @media (hover:hover) guard and no :focus-within, so under a coarse pointer the copy
   measured 0px tall and was unreachable — on a phone, the 45 cards on /customer-stories/
   and the 24 on /insights/ showed a title and nothing else, permanently. (Compare
   .ah-cap-scroll further down this file, which IS guarded — so this was an oversight.)
   Everything is now shown outright, with line clamps doing the work the hidden overflow
   used to: the p clamp is 3 lines against a measured longest live paragraph of exactly
   3 lines, so nothing is truncated today, and the h3 clamp is 5 because 3 or 4 would cut
   9-13 titles at 1024px. The picture's slow zoom on hover stays as the hover affordance. */
.rcard .rc-body{position:absolute;left:0;right:0;bottom:0;padding:26px 26px 24px;z-index:2;color:#fff;}
.rcard .rc-tag{display:inline-block;font:600 11px/1 var(--f-mono);letter-spacing:.12em;text-transform:uppercase;color:#fff;background:rgba(var(--white-rgb),.15);border:1px solid rgba(var(--white-rgb),.3);padding:6px 10px;border-radius:999px;margin-bottom:14px;backdrop-filter:blur(4px);}
.rcard .rc-body h3{font:700 22px/1.28 var(--f-display);margin:0 0 10px;color:#fff;
  display:-webkit-box;-webkit-line-clamp:5;-webkit-box-orient:vertical;overflow:hidden;}
.rcard .rc-body p{font-size:14.5px;line-height:1.6;color:rgba(var(--white-rgb),.86);margin:0;
  display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;}
.rcard .rc-more{display:inline-flex;align-items:center;gap:var(--sp-4);margin-top:15px;font:600 13px/1 var(--f-body);color:#fff;}

/* --- 4. animated outcome bars (data draws on scroll) --- */
.dataviz{border:1px solid var(--card-line);border-radius:var(--radius-20);padding:34px 38px;background:linear-gradient(180deg,#fff,rgba(var(--blue-rgb),.05));}
.dataviz.in .dv-fill{width:var(--w,0%);}
@media (prefers-reduced-motion:reduce){.dv-fill{transition:none;}}

/* ============ region + language switchers (icon triggers) ============ */
#regionSwitch,#langSwitch{gap:var(--sp-4);padding:7px 8px;border-radius:var(--radius-8);color:var(--muted);transition:background var(--dur-fast),color var(--dur-fast);}
#regionSwitch:hover,#langSwitch:hover,#regionSwitch.open,#langSwitch.open{background:rgba(var(--ink-rgb),.06);color:var(--ink);}
.lang .globe,.lang .i18n-ic{flex:0 0 auto;}
.lang .caret{font-size:9px;opacity:.55;}
.lang-menu{display:block;min-width:180px;padding:6px;}
.lang-menu a{display:block;padding:9px 12px;border-radius:var(--radius-8);font:500 13.5px/1.2 var(--f-body);color:var(--text-2);white-space:nowrap;transition:background var(--dur-fast),color var(--dur-fast);}
.lang-menu a:hover{background:rgba(var(--ink-rgb),.05);color:var(--ink);}
.lang-menu a.on{color:var(--teal);font-weight:600;}

/* ============ site search ============ */
.search-btn{display:grid;place-items:center;width:44px;height:44px;border-radius:var(--radius-8);color:var(--muted);cursor:pointer;transition:background var(--dur-fast),color var(--dur-fast);flex:0 0 auto;}
.search-btn:hover{background:rgba(var(--ink-rgb),.06);color:var(--ink);}
.search-modal{position:fixed;inset:0;z-index:320;display:none;align-items:flex-start;justify-content:center;padding:11vh 20px 20px;}
.search-modal.show{display:flex;}
.search-modal .backdrop{position:absolute;inset:0;background:rgba(15,30,51,.5);backdrop-filter:blur(4px);}
.s-panel{position:relative;width:min(600px,100%);background:#fff;border:1px solid var(--card-line-hi);border-radius:var(--radius-14);box-shadow:var(--sh-float);overflow:hidden;animation:sPop .2s var(--ease);}
@keyframes sPop{from{opacity:0;transform:translateY(-10px);}to{opacity:1;transform:none;}}
.s-inputwrap{display:flex;align-items:center;gap:var(--sp-12);padding:15px 18px;border-bottom:1px solid var(--line);}
.s-inputwrap svg{color:var(--muted);flex:0 0 auto;}
.s-inputwrap input{flex:1;border:none;outline:none;font:500 17px/1.3 var(--f-body);color:var(--ink);background:transparent;}
.s-close{border:none;background:transparent;color:var(--muted);font-size:17px;line-height:1;cursor:pointer;padding:5px 7px;border-radius:var(--radius-4);}
.s-close:hover{background:rgba(var(--ink-rgb),.06);color:var(--ink);}
.s-results{max-height:min(52vh,440px);overflow:auto;padding:8px;}
.s-res{display:flex;align-items:baseline;justify-content:space-between;gap:var(--sp-12);padding:12px 14px;border-radius:var(--radius-8);color:var(--ink);}
.s-res:hover,.s-res.sel{background:rgba(var(--blue-rgb),.08);}
.s-res .s-title{font:600 15px/1.2 var(--f-display);}
.s-res .s-url{font:500 12px/1 var(--f-mono);color:var(--muted);white-space:nowrap;}
.s-empty{padding:26px 16px;color:var(--muted);font-size:14px;text-align:center;}

/* =====================================================================
   Whitepaper / report cards — minimal-refined redesign (.doc-cards)
   borderless · soft shadow · larger radius · divider under title ·
   circular arrow button pinned bottom-right · airier spacing
   ===================================================================== */
.doc-cards .card{
  border:0;
  border-radius:var(--radius-20);
  box-shadow:var(--sh-float);
  transition:transform var(--dur-base) var(--ease),box-shadow var(--dur-base) var(--ease);
}
.doc-cards .card:hover{
  transform:translateY(-8px);
  box-shadow:0 8px 18px -10px rgba(var(--ink-rgb),.12),0 36px 68px -28px rgba(var(--blue-rgb),.42);
}
.doc-cards .media{height:212px;}
.doc-cards .body{position:relative;padding:26px 28px 30px;}
.doc-cards .tag{color:var(--blue);}
/* the "Download →" text link becomes a round arrow button, pinned bottom-right;
   the label text stays in the DOM for screen readers (collapsed with font-size:0) */
.doc-cards .link-more{
  position:absolute;right:26px;bottom:24px;margin:0;gap:0;
  width:44px;height:44px;border-radius:50%;
  background:var(--blue);color:#fff;
  display:grid;place-items:center;
  font-size:0;
  box-shadow:0 10px 22px -8px rgba(var(--blue-rgb),.75);
  transition:transform var(--dur-base) var(--ease),background var(--dur-base);
}
.doc-cards .link-more::after{content:"\2192";font:600 19px/1 var(--f-body);color:#fff;}
.doc-cards .card:hover .link-more{background:var(--blue-hi);color:#fff;transform:translateY(-2px);}
.doc-cards .card:hover h3{color:var(--blue);}
@media (prefers-reduced-motion:reduce){
  .doc-cards .card,.doc-cards .card:hover,.doc-cards .link-more{transition:none;transform:none;}
}

/* homepage "Insights & news" cards (.insight-cards) — same refined shell,
   lighter content (image + tag + title, no divider / description / button) */
.insight-cards .card{
  border:0;border-radius:var(--radius-20);
  box-shadow:var(--sh-float);
  transition:transform var(--dur-base) var(--ease),box-shadow var(--dur-base) var(--ease);
}
.insight-cards .card:hover{
  transform:translateY(-8px);
  box-shadow:0 8px 18px -10px rgba(var(--ink-rgb),.12),0 36px 68px -28px rgba(var(--blue-rgb),.42);
}
.insight-cards .media{height:190px;}
.insight-cards .body{padding:22px 24px 26px;}
.insight-cards .tag{color:var(--blue);}
.insight-cards h3{
  color:var(--ink);font:600 18.5px/1.34 var(--f-display);
  margin:11px 0 0;background-image:none;
}
.insight-cards .card:hover h3{color:var(--blue);}
@media (prefers-reduced-motion:reduce){
  .insight-cards .card,.insight-cards .card:hover{transition:none;transform:none;}
}

/* =====================================================================
   Mobile polish — hamburger→✕, nav accordion, small-screen type,
   consistent card image ratio, calmer motion on phones
   ===================================================================== */
/* hamburger morphs into ✕ when the menu is open */
.nav-burger span{transition:transform var(--dur-base) var(--ease),opacity var(--dur-fast);}
.nav-burger.open span:nth-child(1){transform:translateY(7px) rotate(45deg);}
.nav-burger.open span:nth-child(2){opacity:0;}
.nav-burger.open span:nth-child(3){transform:translateY(-7px) rotate(-45deg);}

/* mobile nav accordion (collapsible sections) */
.mobile-menu .m-item{border-bottom:1px solid var(--line);}
.mobile-menu .m-row{display:flex;align-items:center;}
.mobile-menu .m-item .m-link{flex:1;border-bottom:0;}
.mobile-menu .m-toggle{flex:0 0 auto;width:44px;height:44px;display:grid;place-items:center;background:none;border:0;color:var(--muted);cursor:pointer;}
.mobile-menu .m-caret{font-size:13px;line-height:1;display:inline-block;transition:transform var(--dur-fast) var(--ease);}
.mobile-menu .m-item.open .m-caret{transform:rotate(180deg);}
.mobile-menu .m-panel{max-height:0;overflow:hidden;transition:max-height var(--dur-base) var(--ease);}
.mobile-menu .m-item.open .m-panel{max-height:720px;}
.mobile-menu .m-panel .m-sub{border-bottom:0;padding-top:9px;padding-bottom:9px;}
.mobile-menu .m-panel .m-sub:last-child{padding-bottom:16px;}

@media (max-width:720px){
  /* consistent framing for card images on phones */
  .doc-cards .media,.insight-cards .media{height:auto;aspect-ratio:16/10;}
  /* pause purely-decorative infinite animations to save battery */
  .glow-blue,.glow-teal{animation:none;}
}
@media (max-width:400px){
  .h1{font-size:32px;}
  .h2{font-size:27px;}
}

/* =====================================================================
   Homepage (.achome) — centred tagline hero, moving gradient bg,
   scrolling news, client logo wall, contact form. Per 2026-07-20 brief.
   ===================================================================== */
.ah-btn{display:inline-flex;align-items:center;gap:var(--sp-8);font:700 15px var(--f-body);background:linear-gradient(125deg,var(--blue),#0E079E);color:#fff;padding:15px 26px;border-radius:var(--radius-8);border:none;cursor:pointer;box-shadow:0 16px 32px -14px rgba(var(--blue-rgb),.85);transition:transform var(--dur-fast) var(--ease),box-shadow var(--dur-fast);}
.ah-btn:hover{transform:translateY(-2px);box-shadow:0 22px 40px -16px rgba(var(--blue-rgb),.95);}
.ah-btn .ah-arw{transition:transform var(--dur-fast) var(--ease);}
.ah-btn:hover .ah-arw{transform:translateX(4px);}
.ah-btn-ghost{background:transparent;color:#007086;border:1.5px solid color-mix(in srgb,var(--blue) 60%,transparent);box-shadow:none;}
.ah-btn-ghost:hover{border-color:var(--blue);color:#00606F;background:color-mix(in srgb,var(--blue) 8%,transparent);}
.ah-accent{background:var(--grad-anniv);-webkit-background-clip:text;background-clip:text;color:transparent;}

/* hero */
.ah-hero{position:relative;overflow:hidden;text-align:center;min-height:clamp(680px,calc(100svh - 92px),840px);}
.ah-herobg{position:absolute;inset:0;z-index:0;overflow:hidden;background:linear-gradient(180deg,#E7F0FB,#FFFFFF 82%);}
.ah-canvas{position:absolute;inset:0;width:100%;height:100%;display:block;z-index:0;}
@keyframes ahb1{0%,100%{transform:translate(0,0);}50%{transform:translate(46px,34px);}}
@keyframes ahb2{0%,100%{transform:translate(0,0);}50%{transform:translate(-50px,28px);}}
.ah-herobg::after{content:"";position:absolute;inset:0;opacity:.5;background-image:radial-gradient(rgba(var(--blue-rgb),.13) 1px,transparent 1.4px);background-size:26px 26px;-webkit-mask-image:radial-gradient(58% 60% at 50% 42%,#000,transparent 74%);mask-image:radial-gradient(58% 60% at 50% 42%,#000,transparent 74%);}
.ah-hero .container{position:relative;z-index:1;min-height:inherit;display:grid;align-items:center;}
.ah-hero-in{width:100%;max-width:1080px;margin:0 auto;padding:104px 0 96px;}
.ah-h1{margin:0;font:700 clamp(46px,8.8vw,112px)/.92 var(--f-display);letter-spacing:-.02em;text-transform:uppercase;color:var(--ink);}
.ah-lead{margin:30px auto 0;max-width:52ch;font:500 clamp(17px,2.1vw,22px)/1.5 var(--f-body);color:var(--text-2);text-wrap:balance;}
html[lang="zh"] .ah-h1{line-height:.98;letter-spacing:-.015em;text-transform:none;}
/* hero title — per-letter "power-on" entrance (tech feel)
   NOTE: state classes are namespaced (ah-htype*) — do NOT reuse ".hero-split",
   which is an unrelated grid-layout class elsewhere in this file. */
.ah-h1.ah-htype{opacity:0;}
.ah-h1.ah-htype.ah-htype-on{opacity:1;}
/* letters stay INLINE and never move — only fade + de-blur + glow in place */
.ah-h1 .ah-ch{display:inline;will-change:opacity,filter;}
.ah-h1 .ah-word{display:inline;}
/* each rendered line is a block so scroll-drift can translate it independently */
.ah-h1 .ah-hline{display:block;will-change:transform,opacity;}
.ah-h1 .ah-hline:first-child{font-size:1em;line-height:.92;letter-spacing:-.02em;}
.ah-h1 .ah-hline:nth-child(2){font-size:1em;line-height:.9;letter-spacing:-.006em;margin-top:.08em;}
@media (prefers-reduced-motion:reduce){ .ah-h1 .ah-hline{transform:none!important;opacity:1!important;} }
.ah-h1 .ah-accent{white-space:nowrap;background:none;-webkit-background-clip:border-box;background-clip:border-box;}
/* Legacy per-letter accent support. The current hero keeps the accent as one
   glyph run so kerning and diagonal letters such as A remain intact. */
.ah-h1 .ah-accent-ch{
  background-image:var(--grad-anniv-loop);
  background-repeat:repeat-x;
  background-size:var(--wspan,100%) 100%;
  background-position-x:calc(var(--off,0px) * -1);
  -webkit-background-clip:text;background-clip:text;color:transparent;-webkit-text-fill-color:transparent;}
.ah-h1 .ah-accent.ah-accent-whole{
  display:inline-block;white-space:nowrap;opacity:0;
  background-image:var(--grad-anniv-loop);background-repeat:repeat-x;background-size:200% 100%;background-position:0 0;
  -webkit-background-clip:text;background-clip:text;color:transparent;-webkit-text-fill-color:transparent;
  will-change:opacity,filter,background-position;}
.ah-h1.ah-htype-on .ah-ch{animation:ah-ch-on .58s cubic-bezier(.2,.72,.24,1) both;}
.ah-h1.ah-htype-on .ah-accent-ch{animation:ah-ch-on-acc .58s cubic-bezier(.2,.72,.24,1) both, ah-accent-flow 8s linear infinite;}
.ah-h1.ah-htype-on .ah-accent-whole{animation:ah-ch-on-acc .65s cubic-bezier(.2,.72,.24,1) both,ah-accent-word-flow 8s linear infinite;}
@keyframes ah-ch-on{
  0%{opacity:0;filter:blur(10px) brightness(2.2);}
  55%{opacity:1;filter:blur(0) brightness(1.32) drop-shadow(0 0 18px rgba(var(--blue-rgb),.7));}
  100%{opacity:1;filter:blur(0) brightness(1) drop-shadow(0 0 0 rgba(var(--blue-rgb),0));}
}
@keyframes ah-ch-on-acc{
  0%{opacity:0;filter:blur(10px);}
  55%{opacity:1;filter:blur(0) drop-shadow(0 0 20px rgba(200,27,192,.6));}
  100%{opacity:1;filter:blur(0) drop-shadow(0 0 0 rgba(200,27,192,0));}
}
/* seamless colour scroll; the white sheen/highlight layer is intentionally disabled */
@keyframes ah-accent-flow{
  from{background-position-x:calc(var(--off,0px) * -1);}
  to{background-position-x:calc((var(--off,0px) + var(--wspan,0px)) * -1);}
}
@keyframes ah-accent-word-flow{from{background-position:0 0}to{background-position:200% 0}}
@media (prefers-reduced-motion:reduce){
  .ah-h1.ah-htype{opacity:1!important;}
  .ah-h1 .ah-ch{animation:none!important;filter:none!important;opacity:1!important;}
}
.ah-cta-row{display:flex;gap:var(--sp-12);justify-content:center;flex-wrap:wrap;margin-top:38px;}
/* enlarge the hero CTAs ("See what we do" / "Contact us") only */
.ah-cta-row .ah-btn{font-size:17.5px;padding:18px 32px;gap:var(--sp-12);}
.ah-cta-row .ah-btn .ah-arw{font-size:19px;}

/* section head */
.ah-sec-head{display:flex;justify-content:space-between;align-items:baseline;gap:var(--sp-20);flex-wrap:wrap;padding-top:66px;margin-bottom:30px;}
.ah-sec-head h2{margin:0;font:700 clamp(25px,3.4vw,39px)/1 var(--f-display);letter-spacing:-.025em;color:var(--ink);}
.ah-more{font:700 14px var(--f-body);color:var(--blue);white-space:nowrap;}
.ah-more:hover{color:var(--blue-hi);}

/* news marquee */
.ah-news{padding-bottom:54px;}
@keyframes ahscroll{from{transform:translateX(0);}to{transform:translateX(-50%);}}
/* news tiles — minimal dark card + hover "open" interaction */
/* faint tech dot-grid, fades from the top-right */
/* top accent line grows from centre on hover */
/* one-shot diagonal shine sweep on hover */
@media (prefers-reduced-motion:reduce){.ah-nc-cta{opacity:1;transform:none;}.ah-ncard::after{width:100%;}}
/* ---- Our Capabilities — glass-icon overview grid (icons swappable for 3D renders) ---- */
.ah-caps2{position:relative;isolation:isolate;overflow:hidden;padding:104px 0 96px;background:
  radial-gradient(54% 48% at 88% 4%,rgba(200,27,192,.075),transparent 68%),
  radial-gradient(52% 58% at 4% 72%,rgba(var(--blue-rgb),.11),transparent 70%),
  linear-gradient(180deg,#F9FCFE 0%,#EDF6FB 48%,#F7FAFD 100%);}
.ah-caps2::before{content:"";position:absolute;inset:0;z-index:0;pointer-events:none;opacity:.78;
  background-image:
    linear-gradient(rgba(46,116,148,.15) 1px,transparent 1px),
    linear-gradient(90deg,rgba(46,116,148,.15) 1px,transparent 1px);
  background-size:64px 64px;
  -webkit-mask-image:radial-gradient(ellipse 78% 72% at 50% 56%,#000 0%,rgba(0,0,0,.72) 46%,transparent 100%);
  mask-image:radial-gradient(ellipse 78% 72% at 50% 56%,#000 0%,rgba(0,0,0,.72) 46%,transparent 100%);}
.ah-caps2::after{content:"";position:absolute;inset:-24% -12%;z-index:0;pointer-events:none;opacity:.8;
  background:
    radial-gradient(circle at 21% 46%,rgba(var(--blue-rgb),.17) 0 5%,transparent 26%),
    radial-gradient(circle at 78% 54%,rgba(65,42,152,.13) 0 5%,transparent 27%),
    linear-gradient(112deg,transparent 30%,rgba(var(--white-rgb),.7) 48%,transparent 66%);
  filter:blur(12px);transform-origin:50% 50%;animation:ahCapsAmbient 18s ease-in-out infinite alternate;}
@keyframes ahCapsAmbient{
  0%{transform:translate3d(-2.5%,1%,0) scale(1) rotate(-1deg);}
  100%{transform:translate3d(2.5%,-1.5%,0) scale(1.06) rotate(1deg);}
}
.ah-caps2>.container{
  --maxw:1880px;
  --pad:clamp(28px,3.25vw,64px);
  position:relative;z-index:1;
}
.ah-caps2-head{text-align:center;max-width:880px;margin:0 auto 54px;}
.ah-caps2-head .ah-eyebrow{margin-bottom:18px;}
.ah-caps2-h2{font:800 clamp(26px,3.1vw,39px)/1.1 var(--f-display);letter-spacing:-.022em;color:var(--ink);margin:0 auto 16px;text-wrap:balance;}
.ah-caps2-lead{font-size:clamp(16px,1.5vw,18px);line-height:1.62;color:var(--text);max-width:760px;margin:0 auto;text-wrap:balance;}
.ah-caps2-grid{position:relative;isolation:isolate;display:grid;grid-template-columns:repeat(3,1fr);gap:var(--sp-16);}
/* all six devices share the approved blue-glass visual language */
.ah-caps2-grid .ah-cap2{--acc:var(--blue);}
.ah-cap2{--acc:var(--blue);--cap-rx:0deg;--cap-ry:0deg;
  position:relative;overflow:hidden;display:flex;flex-direction:column;align-items:flex-start;justify-content:flex-end;
  min-height:300px;padding:30px 30px 26px;border-radius:var(--radius-20);border:1px solid rgba(var(--blue-soft-rgb),.2);
  background:linear-gradient(145deg,rgba(var(--white-rgb),.9),rgba(var(--white-rgb),.68));
  -webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);
  box-shadow:0 20px 52px -42px rgba(11,73,104,.55);
  text-decoration:none;color:inherit;isolation:isolate;
  transition:transform var(--dur-base) var(--ease-out),box-shadow var(--dur-base) var(--ease-out),border-color var(--dur-base);}
.ah-cap2::before{content:"";position:absolute;inset:0;z-index:-1;border-radius:var(--radius-20);opacity:0;
  background:
    linear-gradient(color-mix(in srgb,var(--acc) 7%,transparent) 1px,transparent 1px),
    linear-gradient(90deg,color-mix(in srgb,var(--acc) 7%,transparent) 1px,transparent 1px);
  background-size:28px 28px,28px 28px;
  transition:opacity var(--dur-base) var(--ease-out);}
.ah-cap2::after{content:"";position:absolute;left:-42%;top:0;width:38%;height:2px;z-index:5;opacity:0;pointer-events:none;
  /* The ramp used to end on rgba(var(--white-rgb),.95) — a bright leading spark, which is the
     right idea on a dark card and the wrong one here: this card's top edge is rgb(254,254,255),
     so the head measured 1.01:1 and the comet visibly died halfway across. On a light ground
     the brightest point of a trace is the most saturated one, not the whitest, so the ramp is
     inverted: pale accent leads in, full --acc is the head at 3.99:1. */
  background:linear-gradient(90deg,transparent,color-mix(in srgb,var(--acc) 45%,#fff),var(--acc),transparent);
  filter:drop-shadow(0 0 8px color-mix(in srgb,var(--acc) 65%,transparent));}
.ah-cap2:hover{transform:translateY(-7px);border-color:color-mix(in srgb,var(--acc) 42%,#E7ECF4);box-shadow:0 34px 66px -36px color-mix(in srgb,var(--acc) 42%,rgba(3,60,120,.5));}
.ah-cap2:hover::before{opacity:1;}
.ah-cap2:hover::after{animation:c2EdgeTrace .9s var(--ease-out) both;}
@keyframes c2EdgeTrace{0%{left:-42%;opacity:0}18%{opacity:1}82%{opacity:.8}100%{left:108%;opacity:0}}
.ah-cap2-no{position:absolute;left:30px;top:27px;z-index:2;font:800 13px/1 var(--f-mono);letter-spacing:.18em;color:color-mix(in srgb,var(--acc) 74%,#4B4F54);}
.ah-cap2-ic{position:absolute;right:22px;top:22px;width:128px;height:128px;display:grid;place-items:center;border-radius:50%;
  background:radial-gradient(circle at 50% 46%,color-mix(in srgb,var(--acc) 20%,transparent) 0%,transparent 66%);}
.ah-cap2-ic img{position:relative;z-index:2;width:108px;height:108px;object-fit:contain;
  transition:transform var(--dur-base) var(--ease-spring),filter var(--dur-base) var(--ease-out);}
.ah-cap2:hover .ah-cap2-ic img{transform: translateY(-3px);
  filter:drop-shadow(0 16px 22px color-mix(in srgb,var(--acc) 55%,transparent));}
.ah-cap2-copy{position:relative;z-index:2;display:flex;flex-direction:column;align-items:flex-start;width:100%;max-width:440px;}
.ah-cap2 h3{font:700 20px/1.2 var(--f-display);letter-spacing:-.012em;color:var(--ink);}
.ah-cap2 p{font-size:14.5px;line-height:1.56;color:var(--text);margin:2px 0 0;}
.ah-cap2-go{margin-top:12px;color:var(--acc);font-weight:800;font-size:19px;line-height:1;
  transition:transform var(--dur-base) var(--ease-out);}
.ah-cap2:hover .ah-cap2-go{transform:translateX(6px);}
@media(max-width:960px){
  .ah-caps2{padding-top:80px;}.ah-caps2-grid{grid-template-columns:repeat(2,1fr);}
  .ah-cap2{min-height:330px;}.ah-cap2-copy{width:100%;max-width:420px;}
}
@media(max-width:600px){
  .ah-hero{min-height:max(600px,calc(100svh - 70px));}
  .ah-h1{font-size:clamp(31px,8.7vw,44px);}
  .ah-h1 .ah-hline{white-space:nowrap;}
  .ah-caps2-grid{grid-template-columns:1fr;}.ah-cap2{min-height:300px;padding:28px 24px 24px;}
  .ah-cap2-no{left:24px;top:24px}.ah-cap2-ic{right:12px;top:14px;width:136px;height:136px}
  .ah-cap2-ic img{width:112px;height:112px}.ah-cap2-copy{width:100%;max-width:none;}
}
@media(prefers-reduced-motion:reduce){.ah-caps2::after{animation:none;}}

/* ---- Clients & Partners — greyscale logo wall ---- */
.ah-cp{position:relative;padding:72px 0 84px;background:linear-gradient(180deg,#FFFFFF 0%,#F1F8FB 55%,#E9F4F9 100%);}
.ah-cp::before{content:"";position:absolute;inset:0;pointer-events:none;z-index:0;background:radial-gradient(60% 55% at 88% 12%,rgba(var(--blue-rgb),.07),transparent 70%),radial-gradient(50% 50% at 8% 92%,rgba(144,71,153,.05),transparent 70%);}
.ah-cp > .container{position:relative;z-index:1;}
.ah-cp-head{text-align:center;max-width:840px;margin:0 auto 44px;}
.ah-cp-h2{font:800 clamp(24px,2.6vw,34px)/1.15 var(--f-display);letter-spacing:-.02em;color:var(--ink);margin:0 auto 12px;text-wrap:balance;}
.ah-cp-lead{font-size:16px;line-height:1.6;color:var(--text);max-width:700px;margin:0 auto;text-wrap:balance;}
.ah-cp-groups{display:flex;flex-direction:column;gap:var(--sp-28);max-width:1120px;margin:0 auto;}
.ah-cp-label{font:600 12px/1 var(--f-mono);letter-spacing:.18em;text-transform:uppercase;color:var(--muted);text-align:center;margin-bottom:16px;}
.ah-cp-row{display:grid;grid-template-columns:repeat(6,1fr);gap:var(--sp-12);}
.ah-cp-logo{height:78px;display:grid;place-items:center;text-align:center;padding:0 14px;border-radius:var(--radius-14);border:1px solid var(--card-line);background:color-mix(in srgb,var(--blue) 4%,#fff);color:#4B4F54;
  font:700 clamp(14px,1.2vw,18px)/1.15 var(--f-display);letter-spacing:-.012em;
  transition:color var(--dur-base) var(--ease-out),border-color var(--dur-base),transform var(--dur-base) var(--ease-out),box-shadow var(--dur-base);}
.ah-cp-logo svg{width:34px;height:34px;}
.ah-cp-logo--img img{max-height:36px;max-width:82%;width:auto;object-fit:contain;opacity:.96;
  transition:opacity var(--dur-base) var(--ease-out),transform var(--dur-base) var(--ease-out);}
.ah-cp-logo--img:hover img{opacity:1;}
.ah-cp-logo:hover{color:var(--blue);border-color:color-mix(in srgb,var(--blue) 40%,var(--card-line));transform:translateY(-3px);box-shadow:0 16px 30px -18px rgba(var(--blue-rgb),.32);}
@media(max-width:820px){.ah-cp-row{grid-template-columns:repeat(3,1fr);}}
@media(max-width:480px){.ah-cp-row{grid-template-columns:repeat(2,1fr);}}
/* partner logo marquee — seamless auto-scroll */
.ah-cp-marquee{position:relative;overflow:hidden;padding:10px 0;
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent);}
.ah-cp-track{display:flex;align-items:center;gap:var(--sp-32);width:max-content;
  animation:ahCpScroll 46s linear infinite;will-change:transform;}
.ah-cp-marquee:hover .ah-cp-track{animation-play-state:paused;}
.ah-cp-item{flex:none;width:168px;height:58px;display:flex;align-items:center;justify-content:center;opacity:.88;
  transition:opacity var(--dur-base) var(--ease-out),transform var(--dur-base) var(--ease-out);}
.ah-cp-item img{display:block;width:auto;height:auto;max-width:142px;max-height:34px;object-fit:contain;}
.ah-cp-item:hover{opacity:1;transform:translateY(-2px);}
@keyframes ahCpScroll{from{transform:translateX(0);}to{transform:translateX(-50%);}}
@media(prefers-reduced-motion:reduce){.ah-cp-track{animation:none;flex-wrap:wrap;justify-content:center;gap:var(--sp-40) var(--sp-56);width:auto;}}

/* ---- Capabilities tiles — refined light editorial cards ---- */
/* subtle tinted wash (not stark white) + faint brand glows — less white, more life */
.ah-caps{position:relative;padding:8px 0 76px;
  background:
    radial-gradient(42% 40% at 88% 30%,color-mix(in srgb,var(--aux-orange) 5%,transparent),transparent 62%),
    radial-gradient(40% 42% at 6% 66%,color-mix(in srgb,var(--aux-cyan) 5%,transparent),transparent 64%),
    linear-gradient(180deg,#FFFFFF 0%,#FCFDFE 100%);}
/* wider breakout so the cards fill more of the viewport (less side whitespace) */
.ah-caps .container{--maxw:1600px;--pad:40px;position:relative;z-index:1;}
.ah-caps .ah-sec-head{padding-top:44px;}
/* ---- What we do: interactive expanding image panels ---- */
.ah-cap-grid{display:flex;gap:var(--sp-16);align-items:stretch;}
.ah-cap{position:relative;overflow:hidden;flex:1 1 0;min-width:0;display:flex;flex-direction:column;justify-content:flex-end;
  min-height:512px;border-radius:var(--radius-20);text-decoration:none;color:#fff;isolation:isolate;
  box-shadow:var(--sh-float);
  transition:flex-grow var(--dur-base) var(--ease),box-shadow var(--dur-base) var(--ease);}
/* hovering one panel expands it and eases the others narrower */
@media (hover:hover) and (min-width:821px){
  .ah-cap-grid:hover > .ah-cap{flex-grow:.68;}
  .ah-cap-grid > .ah-cap:hover{flex-grow:2.9;box-shadow:0 40px 80px -34px rgba(4,21,46,.75);}
}
/* big index number */
.ah-cap-no{position:absolute;top:20px;right:26px;z-index:3;pointer-events:none;
  font:700 clamp(30px,3vw,46px)/1 var(--f-display);letter-spacing:-.02em;color:rgba(var(--white-rgb),.30);
  transition:color var(--dur-base) var(--ease);}
.ah-cap:hover .ah-cap-no{color:rgba(var(--white-rgb),.62);}
/* image + slow ambient Ken-Burns zoom (the cards "breathe") */
.ah-cap-media{position:absolute;inset:0;z-index:0;overflow:hidden;}
.ah-cap-media img{width:100%;height:100%;object-fit:cover;display:block;transform-origin:60% 40%;transition:filter var(--dur-base) var(--ease);}
.cap-b .ah-cap-media img{animation-delay:-7s;} .cap-c .ah-cap-media img{animation-delay:-14s;}
.ah-cap:hover .ah-cap-media img{filter:saturate(1.08) brightness(1.05);}

/* navy gradient overlay for text legibility (deepens on hover) */
.ah-cap-shade{position:absolute;inset:0;z-index:1;pointer-events:none;
  background:linear-gradient(180deg,rgba(4,21,46,.12) 0%,rgba(4,21,46,.30) 42%,rgba(4,21,46,.90) 100%);
  transition:background var(--dur-base) var(--ease);}
.ah-cap:hover .ah-cap-shade{background:linear-gradient(180deg,rgba(var(--blue-rgb),.20) 0%,rgba(4,21,46,.42) 45%,rgba(3,17,38,.94) 100%);}
/* growing accent line at the very bottom on hover */
.ah-cap::after{content:"";position:absolute;left:0;bottom:0;height:3px;width:0;z-index:3;pointer-events:none;
  background:linear-gradient(90deg,var(--blue),var(--blue-soft));transition:width var(--dur-base) var(--ease);}
.ah-cap:hover::after{width:100%;}
/* small white brand mark, top-left */
.ah-cap-mark{position:absolute;top:22px;left:24px;z-index:3;width:30px;height:30px;pointer-events:none;
  background:var(--mark) center/contain no-repeat;filter:brightness(0) invert(1);opacity:.9;
  transition:transform var(--dur-base) var(--ease);}
.ah-cap:hover .ah-cap-mark{transform:rotate(90deg);}
/* body sits at the bottom */
.ah-cap-body{position:relative;z-index:2;padding:30px 30px 28px;}
.ah-cap-ic{width:46px;height:46px;border-radius:var(--radius-14);display:flex;align-items:center;justify-content:center;margin-bottom:16px;
  background:rgba(var(--white-rgb),.14);border:1px solid rgba(var(--white-rgb),.28);backdrop-filter:blur(4px);
  transition:transform var(--dur-base) var(--ease),background var(--dur-base);}
.ah-cap-ic svg{width:24px;height:24px;stroke:#fff;}
.ah-cap:hover .ah-cap-ic{transform:translateY(-3px);background:rgba(var(--blue-rgb),.5);}
.ah-cap h3{margin:0;font:700 23px/1.2 var(--f-display);letter-spacing:-.015em;color:#fff;text-shadow:0 2px 14px rgba(0,16,38,.5);}
.ah-cap p{margin:0;font-size:14.5px;line-height:1.6;color:rgba(var(--white-rgb),.86);text-shadow:0 1px 10px rgba(0,16,38,.5);}
.ah-cap-tags{display:block;margin:0;font:600 12px/1.55 var(--f-mono);letter-spacing:.02em;color:#8FD6E6;text-shadow:0 1px 8px rgba(0,16,38,.55);}
.ah-cap-go{margin-top:16px;display:inline-flex;align-items:center;gap:var(--sp-8);font:700 13.5px var(--f-body);letter-spacing:.02em;color:#fff;}
.ah-cap-go i{font-style:normal;font-size:15px;color:var(--blue-soft);transition:transform var(--dur-fast) var(--ease);}
.ah-cap:hover .ah-cap-go i{transform:translateX(6px);}
/* hover-capable: collapse the description, slide it open on hover/focus */
/* revealed content lives in a scroll container — long text scrolls inside the card */
.ah-cap-scroll{display:block;margin-top:12px;max-height:184px;overflow-y:auto;overscroll-behavior:contain;
  scrollbar-width:thin;scrollbar-color:rgba(var(--white-rgb),.55) transparent;}
.ah-cap-scroll::-webkit-scrollbar{width:6px;}
.ah-cap-scroll::-webkit-scrollbar-thumb{background:rgba(var(--white-rgb),.45);border-radius:var(--radius-4);}
.ah-cap-scroll::-webkit-scrollbar-thumb:hover{background:rgba(var(--white-rgb),.7);}
.ah-cap-scroll::-webkit-scrollbar-track{background:transparent;}
.ah-cap-scroll .ah-cap-tags{margin-top:10px;}
@media (hover:hover){
  .ah-cap-scroll{max-height:0;opacity:0;margin-top:0;transform:translateY(8px);overflow:hidden;
    transition:max-height var(--dur-base) var(--ease),opacity var(--dur-base) var(--ease),transform var(--dur-base) var(--ease),margin-top var(--dur-base) var(--ease);}
  .ah-cap:hover .ah-cap-scroll,.ah-cap:focus-within .ah-cap-scroll{max-height:150px;opacity:1;transform:none;margin-top:12px;overflow-y:auto;}
}
@media (prefers-reduced-motion:reduce){
  .ah-cap-media img{animation:none;transform:scale(1.02);}
  .ah-cap-scroll{max-height:184px!important;opacity:1!important;transform:none!important;margin-top:12px!important;overflow-y:auto;}
}
/* DRAMATIC reveal — cards fly in from the LEFT and swing open like doors (3D), staggered by fx.js.
   perspective on the grid makes the rotateY read; translate/scale/rotate/filter are individual
   props so they compose with the hover flex-grow (no transform conflict). */
.ah-cap-grid{perspective:1500px;perspective-origin:50% 45%;}
.ah-cap-grid.caps-armed .ah-cap{opacity:0;translate:-150px 0;scale:.86;rotate:y -24deg;
  transform-origin:left center;
  transition:opacity var(--dur-slow) var(--ease),
    translate var(--dur-slow) var(--ease),scale var(--dur-slow) var(--ease),rotate var(--dur-slow) var(--ease),
    filter var(--dur-slow) var(--ease),
    flex-grow var(--dur-base) var(--ease),box-shadow var(--dur-base) var(--ease),transform var(--dur-base) var(--ease),border-color var(--dur-base);}
.ah-cap-grid.caps-armed .ah-cap.cap-in{opacity:1;translate:0 0;scale:1;rotate:y 0deg;filter:blur(0);}
/* index number leads in, then the body block — deeper parallax layering as the panel swings in */
.ah-cap-grid.caps-armed .ah-cap .ah-cap-no{translate:-40px 0;opacity:0;
  transition:translate var(--dur-slow) var(--ease) var(--dur-fast),opacity var(--dur-base) var(--ease) .16s,color var(--dur-base) var(--ease);}
.ah-cap-grid.caps-armed .ah-cap.cap-in .ah-cap-no{translate:0 0;opacity:1;}
.ah-cap-grid.caps-armed .ah-cap .ah-cap-body{translate:-54px 0;opacity:0;
  transition:translate var(--dur-slow) var(--ease) var(--dur-base),opacity var(--dur-base) var(--ease) .26s;}
.ah-cap-grid.caps-armed .ah-cap.cap-in .ah-cap-body{translate:0 0;opacity:1;}
/* EXIT — as the section scrolls up out of view the panels swing up-and-back and blur away,
   staggered (reuses the entrance transitions above; fully reversible on scroll-back) */
.ah-cap-grid.caps-armed .ah-cap.cap-out{opacity:0;translate:-30px -90px;scale:.9;rotate:y 18deg;}
@media (prefers-reduced-motion:reduce){
  .ah-cap-grid.caps-armed .ah-cap,
  .ah-cap-grid.caps-armed .ah-cap.cap-out,
  .ah-cap-grid.caps-armed .ah-cap .ah-cap-no,
  .ah-cap-grid.caps-armed .ah-cap .ah-cap-body{opacity:1!important;translate:0!important;scale:1!important;rotate:none!important;filter:none!important;}}
/* ---- Stats band ---- */
/* faint inner tick-ring + a rotating dashed ring frame the emblem */
/* a glowing signal orbits the emblem */
@keyframes ahspin{to{transform:rotate(360deg);}}
@keyframes ahorbit{to{transform:translate(-50%,-50%) rotate(360deg) translateY(-66px);}}
/* stagger the orbiting signals so they sit at different angles */
@media (prefers-reduced-motion:reduce){.ah-stat-ic::before,.ah-stat-ic::after{animation:none;}}
/* stat icons — modern glyphs, subtle life */
.ah-stat-ic .globe-land{animation:stLand 9s ease-in-out infinite;}
@keyframes stPing{0%{transform:scale(.5);opacity:.9}70%{transform:scale(2.5);opacity:0}100%{opacity:0}}
@keyframes stLand{0%,100%{transform:translateX(-2.4px)}50%{transform:translateX(2.4px)}}
@keyframes stWin{0%,100%{opacity:1}22%{opacity:.28}50%{opacity:.85}72%{opacity:.4}}
@media (prefers-reduced-motion:reduce){.ah-stat-ic .pin-ping,.ah-stat-ic .globe-land,.ah-stat-ic .bldg-win rect{animation:none;}}
/* ---- AI / Innovation Lab band (synthwave grid) ---- */
/* The only section on /service-ai-solutioning/ and /robotics/ with no min-height, and its
   content is three text elements, so it rendered as a 470px band between 615-765px
   neighbours. The flex column is what makes min-height usable — without it the extra
   height pools below the content instead of centring it. */
.ah-ai{position:relative;overflow:hidden;display:flex;flex-direction:column;justify-content:center;min-height:640px;padding:120px 0 130px;color:#fff;background:linear-gradient(180deg,#04152E 0%,#04152E 55%,#04152E 100%);}
.ah-ai-grid{position:absolute;left:0;right:0;bottom:0;height:60%;perspective:300px;overflow:hidden;pointer-events:none;}
/* Perspective grid, deliberately quiet. It was 2px lines at .55/.40 cycling every 2.7s,
   which glared: rotateX(74deg) means the near edge sweeps far faster than the raw 54px /
   2.7s suggests, and the mask only faded the far edge, so the fastest band was also the
   brightest. Now 1px at .26/.20 over 7.5s, and the mask fades BOTH ends so the near edge
   — where apparent speed peaks — dims out instead of running at full strength. */
.ah-ai-plane{position:absolute;left:-60%;right:-60%;bottom:-20%;height:200%;background-image:linear-gradient(rgba(var(--blue-soft-rgb),.26) 1px,transparent 1px),linear-gradient(90deg,rgba(var(--blue-soft-rgb),.20) 1px,transparent 1px);background-size:54px 54px;transform:rotateX(74deg);transform-origin:bottom center;animation:ahgridmove 7.5s linear infinite;-webkit-mask-image:linear-gradient(180deg,transparent,#000 55%,#000 86%,transparent);mask-image:linear-gradient(180deg,transparent,#000 55%,#000 86%,transparent);}
@keyframes ahgridmove{from{background-position:0 0;}to{background-position:0 54px;}}
.ah-ai-glow{position:absolute;left:50%;bottom:32%;width:120%;height:280px;transform:translateX(-50%);pointer-events:none;background:radial-gradient(50% 100% at 50% 100%,rgba(var(--blue-soft-rgb),.5),transparent 70%);filter:blur(22px);}
.ah-ai-in{position:relative;z-index:1;text-align:center;max-width:880px;}
.ah-ai-eyebrow{display:inline-flex;align-items:center;gap:var(--sp-8);margin:0 0 20px;font:600 12.5px/1 var(--f-mono);letter-spacing:.16em;text-transform:uppercase;color:var(--blue-soft);}
.ah-ai-in h2{margin:0;font:700 clamp(30px,4.4vw,56px)/1.05 var(--f-display);letter-spacing:-.02em;background:linear-gradient(120deg,#fff 32%,var(--blue-soft));-webkit-background-clip:text;background-clip:text;color:transparent;}
.ah-ai-lead{margin:22px auto 0;max-width:54ch;font-size:16px;line-height:1.6;color:rgba(var(--white-rgb),.78);}
.ah-ai .ah-btn{margin-top:34px;background:linear-gradient(125deg,var(--blue),#0E079E);box-shadow:0 16px 34px -14px rgba(var(--blue-rgb),.8);}
@media (prefers-reduced-motion:reduce){.ah-ai-plane{animation:none;}}
/* ---- Global network (wireframe globe) ---- */
.ah-globe{position:relative;overflow:hidden;padding:90px 0;color:#fff;background:radial-gradient(120% 92% at 82% 4%,#001F4D,#06101F 58%),linear-gradient(180deg,#06101F,#040A14);}
.ah-globe-in{display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-40);align-items:center;}
.ah-globe-copy{max-width:540px;}

/* Global Locations wears a wider variant: the deck asks for the globe centred and
   bigger, with the connecting lines for every office rather than just the four labs.
   The two-column split that suits the homepage puts the globe in half the width, so
   here the copy sits above a full-bleed stage instead of beside a small one. */
.ah-globe--wide .ah-globe-in{grid-template-columns:1fr;gap:var(--sp-32);}
.ah-globe--wide .ah-globe-copy{max-width:none;text-align:center;margin:0 auto;}
.ah-globe--wide .ah-globe-stage{max-width:min(860px,86vw);}
@media (max-width:720px){
  .ah-globe--wide .ah-globe-stage{max-width:100%;}
}
.ah-globe-copy h2{margin:0;font:700 clamp(28px,3.6vw,46px)/1.06 var(--f-display);letter-spacing:-.02em;color:#fff;}
.ah-globe-lead{margin:18px 0 28px;font-size:15.5px;line-height:1.6;color:rgba(var(--white-rgb),.72);}
.ah-globe-stage{position:relative;width:100%;max-width:520px;margin:0 auto;aspect-ratio:1/1;}
.ah-globe-cv{position:absolute;inset:0;width:100%;height:100%;display:block;}
/* bilingual labels embedded on the rotating globe (JS-positioned, fade by depth) */
.ah-glabels{position:absolute;inset:0;pointer-events:none;overflow:visible;z-index:3;}
.ah-glabel{position:absolute;top:0;left:0;transform:translate(-9999px,-9999px);opacity:0;transition:opacity var(--dur-base) var(--ease);will-change:transform,opacity;}
.ah-glabel-txt{position:absolute;left:12px;top:50%;transform:translateY(-50%);white-space:nowrap;padding-left:11px;}
.ah-glabel-txt::before{content:"";position:absolute;left:0;top:50%;width:8px;height:1px;background:rgba(var(--blue-soft-rgb),.75);}
.ah-glabel b{display:block;font:700 13px/1.15 var(--f-display);color:#fff;letter-spacing:-.005em;text-shadow:0 1px 8px rgba(0,20,40,.65);}
.ah-glabel em{display:block;font-style:normal;font:600 9px/1.25 var(--f-mono);letter-spacing:.13em;text-transform:uppercase;color:#7FD4E4;margin-top:2px;text-shadow:0 1px 6px rgba(0,20,40,.65);}
@media (max-width:600px){.ah-glabel b{font-size:11px;}.ah-glabel em{font-size:8px;}.ah-glabel-txt{left:9px;padding-left:8px;}}
@media (max-width:900px){
  .ah-caps .container{--pad:28px;}
  .ah-cap-grid{flex-direction:column;}
  .ah-cap{min-height:360px;}
  .ah-stats-in{grid-template-columns:repeat(2,1fr);gap:var(--sp-32) var(--sp-16);}
  .ah-globe-in{grid-template-columns:1fr;gap:var(--sp-32);}
  .ah-globe-stage{max-width:380px;order:-1;}
  .ah-labs{grid-template-columns:1fr 1fr;}
}

/* client logos */

/* contact */
/* overflow:hidden is the hard stop for the entrance below: whatever the swing projects,
   it cannot paint outside this section. */
.ah-contact{position:relative;padding:72px 0 104px;overflow:hidden;}
/* ambient design so the card doesn't float in blank white — soft brand glows + faint tech dot-grid, masked into the white above/below */
.ah-contact::before{content:"";position:absolute;inset:0;z-index:0;pointer-events:none;
  background:
    radial-gradient(46% 54% at 87% 20%,rgba(var(--blue-rgb),.09),transparent 62%),
    radial-gradient(42% 48% at 4% 84%,rgba(var(--blue-rgb),.08),transparent 62%),
    radial-gradient(rgba(var(--blue-rgb),.06) 1px,transparent 1.5px);
  background-size:auto,auto,26px 26px;
  -webkit-mask-image:linear-gradient(180deg,transparent,#000 15%,#000 80%,transparent);
          mask-image:linear-gradient(180deg,transparent,#000 15%,#000 80%,transparent);}
.ah-contact > .container{position:relative;z-index:1;perspective:3000px;perspective-origin:56% 42%;}
/* Door-opening entrance, then the form fields appear.

   It used to hinge on the card's left edge at -78deg, and that is a lot further than it
   sounds. Hinged at the edge, the whole card is on one side of the axis, so the far edge
   swings toward the camera: at -78deg it travelled ~1320px forward, and 1600px of
   perspective magnifies something that close by about 5.7x. The card projected to roughly
   1600px wide inside a ~1350px container — it hung out past the section on its way in, and
   at that angle the panel is so near edge-on that its type reads as squashed and reversed.

   Hinging at the centre puts half the card on each side of the axis, so what one half gains
   the other loses. That is most of the fix but not all of it: perspective magnifies the near
   half more than it foreshortens the far half, so the projection still peaks slightly wider
   than the card. Measured across the sweep, 18deg over 3000px peaks at ~1380px against a
   1350px container. The 5% settle closes that gap — it lands at ~1311px, inside the
   container at every angle — and the section's overflow:hidden backs it up. Relying on the
   clip alone would have cut the card's edge off mid-swing, which is worse than the overhang. */
.ah-contact-card.co-armed{transform-origin:center;opacity:0;rotate:y -18deg;scale:.95;
  transition:rotate var(--dur-slow) var(--ease),scale var(--dur-slow) var(--ease),
    opacity var(--dur-base) var(--ease),box-shadow var(--dur-base) var(--ease);}
.ah-contact-card.co-armed.co-in{opacity:1;rotate:y 0deg;scale:1;}
.ah-contact-card.co-armed .ah-form > *{opacity:0;translate:0 18px;
  transition:opacity var(--dur-base) var(--ease),translate var(--dur-base) var(--ease);}
.ah-contact-card.co-armed.co-in .ah-form > *{opacity:1;translate:0 0;}
.ah-contact-card.co-armed.co-in .ah-form > :nth-child(1){transition-delay:.58s}
.ah-contact-card.co-armed.co-in .ah-form > :nth-child(2){transition-delay:.66s}
.ah-contact-card.co-armed.co-in .ah-form > :nth-child(3){transition-delay:.74s}
.ah-contact-card.co-armed.co-in .ah-form > :nth-child(4){transition-delay:.82s}
.ah-contact-card.co-armed.co-in .ah-form > :nth-child(5){transition-delay:.90s}
.ah-contact-card.co-armed.co-in .ah-form > :nth-child(6){transition-delay:.98s}
@media (prefers-reduced-motion:reduce){.ah-contact-card.co-armed,.ah-contact-card.co-armed .ah-form > *{opacity:1!important;rotate:none!important;scale:1!important;translate:none!important;}}
/* richer ambient decoration layer — drifting brand glows, floating diamonds, a network constellation */
.ah-contact-deco{position:absolute;inset:0;z-index:0;pointer-events:none;overflow:hidden;}
.ah-c-glow{position:absolute;border-radius:50%;filter:blur(8px);}
.ah-c-glow-a{width:540px;height:540px;left:-150px;top:20px;background:radial-gradient(circle,rgba(var(--blue-rgb),.11),transparent 62%);animation:ah-cglow 15s ease-in-out infinite;}
.ah-c-glow-b{width:460px;height:460px;right:-130px;bottom:-40px;background:radial-gradient(circle,rgba(var(--blue-rgb),.10),transparent 64%);animation:ah-cglow 18s ease-in-out infinite reverse;}
/* Client feedback: too many logo watermarks. The four floating brand diamonds that
   sat around the contact band are hidden — the soft glows and the network graphic
   below still carry the section. Markup is left in place so this is a one-line revert. */
.ah-c-dia{display:none;}
.ah-c-net{position:absolute;right:60px;bottom:24px;width:220px;height:auto;}
@keyframes ah-cglow{0%,100%{translate:0 0}50%{translate:50px 26px}}
@media (prefers-reduced-motion:reduce){.ah-c-glow{animation:none;}}
.ah-contact-card{position:relative;border-radius:24px;overflow:hidden;display:grid;grid-template-columns:.86fr 1.14fr;
  box-shadow:0 50px 90px -48px rgba(0,31,77,.55);border:1px solid rgba(var(--blue-rgb),.06);}
/* ---- left assurance panel ---- */
.ah-contact-intro{position:relative;overflow:hidden;padding:48px 44px;color:#fff;display:flex;flex-direction:column;gap:var(--sp-24);
  background:radial-gradient(125% 95% at 88% 6%,rgba(var(--blue-rgb),.75),transparent 56%),linear-gradient(150deg,#001B45,var(--blue) 55%,var(--blue));}
.ah-contact-intro .ah-cx{position:absolute;inset:0;width:100%;height:100%;display:block;z-index:0;}
/* Client feedback: too many logo watermarks — the 216px mark behind the contact intro
   is hidden. Markup kept so this is a one-line revert. */
.ah-ci-mark{display:none;}
.ah-ci-top{position:relative;z-index:1;}
.ah-ci-eyebrow{display:flex;align-items:center;gap:var(--sp-8);margin:0 0 15px;font:600 12px/1 var(--f-mono);letter-spacing:.13em;text-transform:uppercase;color:#8FD6E6;}
.ah-contact-intro h2{position:relative;z-index:1;margin:0 0 14px;font:700 clamp(26px,2.9vw,39px)/1.03 var(--f-display);letter-spacing:-.02em;color:#fff;}
.ah-ci-lead{position:relative;z-index:1;margin:0;max-width:34ch;font-size:15px;line-height:1.62;color:rgba(var(--white-rgb),.85);}
.ah-ci-points{position:relative;z-index:1;list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:var(--sp-12);}
.ah-ci-points li{display:flex;align-items:flex-start;gap:var(--sp-12);font-size:14.5px;line-height:1.45;color:rgba(var(--white-rgb),.94);}
.ah-ci-points li .ah-ci-ic{margin-top:1px;}
.ah-ci-ic{flex:0 0 auto;width:32px;height:32px;border-radius:var(--radius-8);display:flex;align-items:center;justify-content:center;
  background:rgba(var(--white-rgb),.1);border:1px solid rgba(var(--white-rgb),.17);}
.ah-ci-ic svg{width:16px;height:16px;stroke:#8FD6E6;}
/* colourful checklist icons (iHQ auxiliary palette) on the contact panel */
.ah-contact-intro li:nth-of-type(1) .ah-ci-ic{background:color-mix(in srgb,var(--blue) 22%,transparent);border-color:color-mix(in srgb,var(--blue) 40%,transparent);}
.ah-contact-intro li:nth-of-type(1) .ah-ci-ic svg{stroke:#4FD0E6;}
.ah-contact-intro li:nth-of-type(2) .ah-ci-ic{background:color-mix(in srgb,var(--aux-purple) 26%,transparent);border-color:color-mix(in srgb,var(--aux-purple) 44%,transparent);}
.ah-contact-intro li:nth-of-type(2) .ah-ci-ic svg{stroke:#B7A6F0;}
.ah-contact-intro li:nth-of-type(3) .ah-ci-ic{background:color-mix(in srgb,#C81BC0 24%,transparent);border-color:color-mix(in srgb,#C81BC0 42%,transparent);}
.ah-contact-intro li:nth-of-type(3) .ah-ci-ic svg{stroke:#EE8AE8;}
.ah-ci-direct{position:relative;z-index:1;margin-top:auto;display:flex;align-items:center;gap:var(--sp-12);padding-top:24px;
  border-top:1px solid rgba(var(--white-rgb),.15);text-decoration:none;color:#fff;transition:transform var(--dur-fast) var(--ease),opacity var(--dur-fast);}
.ah-ci-direct:hover{opacity:.9;transform:translateX(3px);}
.ah-ci-direct .ah-ci-ic{width:38px;height:38px;border-radius:var(--radius-8);}
.ah-ci-direct-t{display:flex;flex-direction:column;line-height:1.28;}
.ah-ci-direct-t em{font-style:normal;font-size:11.5px;letter-spacing:.02em;color:rgba(var(--white-rgb),.6);}
.ah-ci-direct-t b{font-size:14.5px;font-weight:600;}
/* ---- right form: floating labels ---- */
.ah-form{position:relative;overflow:hidden;background:#fff;padding:44px 46px;display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-16);align-content:start;}
/* Client feedback: too many logo watermarks — the mark that filled the space below the
   form fields is removed. The whitespace it was covering is intentional. */
.ah-field{position:relative;z-index:1;display:block;}
.ah-field-full{grid-column:1/-1;}
.ah-field input,.ah-field select,.ah-field textarea{width:100%;font:500 15px var(--f-body);color:var(--ink);
  background:#F4F8FD;border:1px solid #E1E8F1;border-radius:var(--radius-14);padding:23px 15px 8px;
  transition:border-color var(--dur-fast),background var(--dur-fast),box-shadow var(--dur-fast);}
.ah-field textarea{padding-top:26px;resize:vertical;min-height:112px;line-height:1.5;}
.ah-field-sel select{appearance:none;-webkit-appearance:none;cursor:pointer;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none' stroke='%234B4F54' stroke-width='1.8' stroke-linecap='round'%3E%3Cpath d='M1 1.8 6 6.2 11 1.8'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 15px center;padding-right:38px;}
.ah-field label{position:absolute;left:16px;top:15px;font:500 14.5px var(--f-body);color:var(--muted);
  pointer-events:none;transition:top var(--dur-fast) var(--ease),font-size var(--dur-fast) var(--ease),color var(--dur-fast) var(--ease),font-weight var(--dur-fast);}
.ah-field input:focus,.ah-field select:focus,.ah-field textarea:focus{outline:none;border-color:var(--blue);background:#fff;
  box-shadow:0 12px 28px -16px rgba(var(--blue-rgb),.42);}
.ah-field input:focus-visible,.ah-field select:focus-visible,.ah-field textarea:focus-visible{outline:2px solid var(--blue);outline-offset:2px;}
.ah-field input:focus+label,.ah-field input:not(:placeholder-shown)+label,
.ah-field textarea:focus+label,.ah-field textarea:not(:placeholder-shown)+label,
.ah-field-sel label{top:8px;font-size:10.5px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--blue);}
.ah-form-foot{position:relative;z-index:1;grid-column:1/-1;display:flex;align-items:center;gap:var(--sp-20);flex-wrap:wrap;margin-top:6px;}
.ah-form-btn{font-size:15px;padding:15px 28px;}
.ah-form-note{margin:0;font-size:12px;line-height:1.45;color:var(--muted);max-width:26ch;}

@media (max-width:860px){
  .ah-hero-in{padding:64px 0 58px;}
  .ah-contact-card{grid-template-columns:1fr;}
  .ah-form{grid-template-columns:1fr;padding:32px 26px;}
  .ah-contact-intro{padding:36px 28px;gap:var(--sp-20);}
  .ah-ci-mark{width:150px;height:150px;right:-24px;bottom:-24px;}
  .ah-form-foot{flex-direction:column;align-items:flex-start;gap:var(--sp-12);}
  .ah-form-btn{width:100%;justify-content:center;}
}
@media (prefers-reduced-motion:reduce){
  .ah-blob,.ah-track,.ah-logos-track{animation:none;}
}
/* ===== Contact page (ct-) ===== */
.ct-wrap{max-width:1120px;}

/* Heading */
.ct-head{margin-bottom:36px;}
.ct-title{margin:0;font:700 clamp(36px,5vw,62px)/1.04 var(--f-display);letter-spacing:-.03em;color:var(--ink);}
.ct-grad{background:linear-gradient(100deg,var(--blue-hi),var(--teal));-webkit-background-clip:text;background-clip:text;color:transparent;}
.ct-blurb{margin:16px 0 0;max-width:520px;font:400 19px/1.5 var(--f-body);color:var(--text-2);}

/* Grid */
.ct-grid{display:grid;grid-template-columns:1.5fr 1fr;gap:var(--sp-20);align-items:stretch;}

/* Form card */
.ct-card{background:var(--card);border:1px solid var(--card-line);border-radius:var(--radius);padding:34px 36px;box-shadow:var(--sh-raised);}
.ct-row{display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-16);}
.ct-field{display:flex;flex-direction:column;gap:var(--sp-8);margin-bottom:18px;}
.ct-field label{font:600 13px/1 var(--f-body);color:var(--text-2);}
.ct-field input,
.ct-field textarea,
.ct-select-wrap select{
  width:100%;box-sizing:border-box;font:400 15px/1.4 var(--f-body);color:var(--ink);
  background:#fff;border:1px solid var(--card-line);border-radius:var(--radius-8);padding:13px 15px;
  outline:3px solid transparent;
  transition:border-color var(--dur-fast) var(--ease),outline-color var(--dur-fast) var(--ease);
}
.ct-field input::placeholder,
.ct-field textarea::placeholder{color:var(--muted);}
.ct-field input:hover,
.ct-field textarea:hover,
.ct-select-wrap select:hover{border-color:var(--card-line-hi);}
.ct-field input:focus,
.ct-field textarea:focus,
/* Same outline-instead-of-shadow fix as .field above — see the note there. */
.ct-select-wrap select:focus{border-color:var(--blue);outline-color:rgba(var(--blue-rgb),.15);}
.ct-field textarea{resize:vertical;min-height:128px;}

/* Select */
.ct-select-wrap{position:relative;}
.ct-select-wrap select{appearance:none;-webkit-appearance:none;-moz-appearance:none;padding-right:42px;cursor:pointer;}
.ct-caret{position:absolute;right:14px;top:50%;transform:translateY(-50%);width:18px;height:18px;color:var(--muted);pointer-events:none;}

/* Submit */
.ct-submit{margin-top:6px;display:inline-flex;align-items:center;gap:var(--sp-8);width:100%;justify-content:center;}
.ct-submit svg{width:18px;height:18px;transition:transform var(--dur-fast) var(--ease);}
.ct-submit:hover svg{transform:translateX(3px);}

/* Gradient accent panel */
.ct-panel{position:relative;overflow:hidden;border-radius:var(--radius);background:linear-gradient(150deg,var(--blue),var(--aux-purple));color:#fff;box-shadow:0 24px 54px -30px rgba(var(--blue-rgb),.7);}
.ct-panel-glow{position:absolute;width:300px;height:300px;top:-90px;right:-90px;border-radius:50%;background:radial-gradient(circle at 50% 50%,rgba(var(--white-rgb),.35),rgba(var(--white-rgb),0) 62%);pointer-events:none;}
.ct-panel-inner{position:relative;padding:34px 34px 30px;display:flex;flex-direction:column;height:100%;box-sizing:border-box;}
.ct-panel-kicker{margin:0 0 6px;font:600 12px/1 var(--f-mono);letter-spacing:.14em;text-transform:uppercase;color:rgba(var(--white-rgb),.82);}
.ct-panel-title{margin:0 0 26px;font:700 30px/1.05 var(--f-display);letter-spacing:-.02em;color:#fff;}
.ct-info{display:flex;gap:var(--sp-12);align-items:flex-start;margin-bottom:22px;color:#fff;text-decoration:none;}
a.ct-info .ct-info-value{transition:color var(--dur-fast) var(--ease);}
a.ct-info:hover .ct-info-value{color:#fff;text-decoration:underline;text-underline-offset:3px;}
.ct-ico{flex:0 0 auto;width:42px;height:42px;border-radius:var(--radius-8);display:grid;place-items:center;background:rgba(var(--white-rgb),.16);border:1px solid rgba(var(--white-rgb),.22);}
.ct-ico svg{width:21px;height:21px;color:#fff;}
.ct-info-text{display:flex;flex-direction:column;gap:var(--sp-4);padding-top:2px;}
.ct-info-label{font:600 12px/1 var(--f-mono);letter-spacing:.1em;text-transform:uppercase;color:rgba(var(--white-rgb),.72);}
.ct-info-value{font:500 15px/1.45 var(--f-body);color:rgba(var(--white-rgb),.96);}
.ct-panel-link{margin-top:auto;display:inline-flex;align-items:center;gap:var(--sp-8);font:600 14.5px/1 var(--f-body);color:#fff;text-decoration:none;padding-top:8px;}
.ct-panel-link svg{width:17px;height:17px;transition:transform var(--dur-fast) var(--ease);}
.ct-panel-link:hover svg{transform:translateX(3px);}

/* Responsive */
@media (max-width:900px){
  .ct-grid{grid-template-columns:1fr;}
}
@media (max-width:560px){
  .ct-card{padding:26px 22px;}
  .ct-row{grid-template-columns:1fr;gap:0;}
  .ct-panel-inner{padding:28px 24px;}
}/* ===== Careers page (cr-) ===== */
.cr-hero{position:relative;overflow:hidden;padding:96px 0 80px;background:linear-gradient(150deg,var(--blue) 0%,var(--blue) 100%);isolation:isolate;}
.cr-hero-bg{position:absolute;inset:0;z-index:-1;background:
  radial-gradient(1000px 480px at 82% -10%,rgba(var(--white-rgb),.22),transparent 60%),
  radial-gradient(700px 420px at 8% 120%,rgba(var(--blue-rgb),.55),transparent 60%);}
.cr-hero-inner{position:relative;}
.cr-hero .eyebrow{color:#CFF3EC;}
.cr-hero .eyebrow .dot{background:var(--blue-soft);box-shadow:0 0 12px var(--blue-soft);}
.cr-hero-title{color:#fff;max-width:820px;}
.cr-hero .grad-text{background:linear-gradient(100deg,#C4E4F2,var(--blue-soft));background-size:200% auto;-webkit-background-clip:text;background-clip:text;color:transparent;}
.cr-hero-sub{color:rgba(var(--white-rgb),.9);max-width:560px;margin:22px 0 32px;}

.cr-lead{margin-bottom:40px;}
.cr-lead-p{color:var(--text-2);max-width:520px;margin:14px 0 0;}

/* Location cards */
.cr-loc-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--sp-20);}
.cr-loc{position:relative;display:flex;flex-direction:column;gap:var(--sp-24);overflow:hidden;
  padding:26px 24px;border-radius:var(--radius);text-decoration:none;color:#fff;
  background:linear-gradient(150deg,var(--blue),var(--aux-purple));
  border:1px solid rgba(var(--white-rgb),.14);isolation:isolate;
  transition:transform var(--dur-base) var(--ease),box-shadow var(--dur-base) var(--ease);}
.cr-loc::before{content:"";position:absolute;inset:0;z-index:-1;opacity:0;
  background:radial-gradient(420px 300px at 80% 0%,rgba(var(--white-rgb),.28),transparent 62%);
  transition:opacity var(--dur-base) var(--ease);}
.cr-loc:hover{transform:translateY(-6px);box-shadow:0 22px 46px -20px rgba(var(--blue-rgb),.65);}
.cr-loc:hover::before{opacity:1;}
/* per-card colour variety (iHQ palette, blue→deep accent — safe with white text) */
.cr-loc:nth-child(1){background:linear-gradient(150deg,var(--blue),var(--aux-purple));}
.cr-loc:nth-child(2){background:linear-gradient(150deg,var(--blue),var(--aux-purple));}
.cr-loc:nth-child(3){background:linear-gradient(150deg,var(--blue),#8A2A5E);}
.cr-loc:nth-child(4){background:linear-gradient(150deg,var(--blue),var(--aux-purple));}
.cr-loc-pin{width:52px;height:52px;flex:none;display:grid;place-items:center;border-radius:var(--radius-14);
  background:rgba(var(--white-rgb),.16);border:1px solid rgba(var(--white-rgb),.24);}
.cr-loc-pin svg{width:26px;height:26px;color:#fff;}
.cr-loc-body{display:flex;flex-direction:column;gap:var(--sp-4);}
.cr-loc-name{font:700 27px/1.05 var(--f-display);letter-spacing:-.02em;color:#fff;}
.cr-loc-tag{font:600 12px/1.3 var(--f-mono);letter-spacing:.06em;color:rgba(var(--white-rgb),.82);}
.cr-loc-cta{margin-top:auto;display:inline-flex;align-items:center;gap:var(--sp-8);
  font:600 13.5px/1 var(--f-display);color:#fff;}
.cr-loc-cta svg{width:15px;height:15px;transition:transform var(--dur-base) var(--ease);}
.cr-loc:hover .cr-loc-cta svg{transform:translate(3px,-3px);}

/* Life strip */
.cr-life{border-radius:var(--radius-14);border:1px solid var(--card-line);background:var(--card);
  padding:40px 40px 44px;position:relative;overflow:hidden;}
.cr-life::before{content:"";position:absolute;left:0;top:0;bottom:0;width:5px;
  background:linear-gradient(180deg,var(--blue),var(--aux-purple));}
.cr-life-head{margin-bottom:32px;}
.cr-life-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--sp-20);}
.cr-life-card{display:flex;flex-direction:column;gap:var(--sp-12);padding:24px;border-radius:var(--radius-14);
  background:var(--bg);border:1px solid var(--card-line);
  transition:border-color var(--dur-base) var(--ease),transform var(--dur-base) var(--ease);}
.cr-life-card:hover{border-color:var(--card-line-hi);transform:translateY(-3px);}
.cr-life-ic{width:46px;height:46px;display:grid;place-items:center;border-radius:var(--radius-8);color:#fff;
  background:linear-gradient(150deg,var(--blue),var(--aux-purple));}
.cr-life-card:nth-child(1) .cr-life-ic{background:linear-gradient(150deg,var(--blue),var(--aux-purple));}
.cr-life-card:nth-child(2) .cr-life-ic{background:linear-gradient(150deg,var(--blue),var(--aux-purple));}
.cr-life-card:nth-child(3) .cr-life-ic{background:linear-gradient(150deg,var(--blue),#8A2A5E);}
.cr-life-ic svg{width:24px;height:24px;}
.cr-life-t{font:700 20px/1.1 var(--f-display);letter-spacing:-.01em;color:var(--ink);}
.cr-life-d{font-size:15px;line-height:1.5;color:var(--text-2);}

/* CTA */
.cr-cta{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-28);flex-wrap:wrap;
  padding:44px 44px;border-radius:var(--radius-14);overflow:hidden;position:relative;
  background:linear-gradient(150deg,var(--blue),var(--aux-purple));}
.cr-cta::before{content:"";position:absolute;inset:0;
  background:radial-gradient(600px 300px at 90% -20%,rgba(var(--white-rgb),.2),transparent 60%);}
.cr-cta-copy{position:relative;}
.cr-cta-h{color:#fff;margin-bottom:8px;}
.cr-cta-p{color:rgba(var(--white-rgb),.9);margin:0;font-size:16px;}
.cr-cta-btn{position:relative;background:#fff;color:var(--blue);font-weight:700;}
.cr-cta-btn:hover{background:#F2F7FC;}

@media(max-width:960px){
  .cr-loc-grid{grid-template-columns:repeat(2,1fr);}
  .cr-life-grid{grid-template-columns:1fr;}
  .cr-life{padding:32px 26px 34px;}
}
@media(max-width:560px){
  .cr-hero{padding:72px 0 60px;}
  .cr-loc-grid{grid-template-columns:1fr;}
  .cr-cta{padding:32px 26px;}
}/* ===== Services / Industries page (sv-) ===== */
.sv-hero{padding-bottom:44px;}
.pg-services .sv-hero+.section{position:relative;isolation:isolate;}
/* The wash and the grid are two layers because they want different treatment, and running
   them off one pseudo-element meant they could not have it.

   The grid used to sit on ::before alongside the background colour, which made it the only
   grid on the site with no mask and no opacity reduction: rgba(46,116,148,.145) at full
   strength, edge to edge. That is 3.4x the site-wide interior-hero grid (.052 at opacity
   .82 = .043 effective) and it rendered as graph paper straight across "Where we go deep".
   A mask could not be added while the colour shared the element — masking the grid would
   have masked the ground out with it.

   Split, the grid now takes .ah-caps2's exact treatment: same .15 line, same .78 opacity,
   same radial vignette, so the two light content bands on this site carry one texture
   rather than two. It fades out under the copy and survives only at the edges, which is
   what makes .ah-caps2 read as texture instead of as ruling. */
.pg-services .sv-hero+.section::before{content:"";position:absolute;top:0;bottom:0;left:50%;z-index:-1;width:100vw;transform:translateX(-50%);
  background-color:#F5FAFD;
  background-image:
    radial-gradient(46% 72% at 4% 44%,rgba(var(--blue-rgb),.13),transparent 72%),
    radial-gradient(42% 70% at 96% 58%,rgba(65,42,152,.1),transparent 74%);
  animation:svCapabilityWash 18s ease-in-out infinite alternate;}
.pg-services .sv-hero+.section::after{content:"";position:absolute;top:0;bottom:0;left:50%;z-index:-1;width:100vw;transform:translateX(-50%);
  pointer-events:none;opacity:.78;
  background-image:
    linear-gradient(rgba(46,116,148,.15) 1px,transparent 1px),
    linear-gradient(90deg,rgba(46,116,148,.15) 1px,transparent 1px);
  background-size:64px 64px;
  -webkit-mask-image:radial-gradient(ellipse 78% 72% at 50% 56%,#000 0%,rgba(0,0,0,.72) 46%,transparent 100%);
          mask-image:radial-gradient(ellipse 78% 72% at 50% 56%,#000 0%,rgba(0,0,0,.72) 46%,transparent 100%);
  animation:svCapabilityGrid 18s ease-in-out infinite alternate;}
@keyframes svCapabilityWash{
  from{background-position:0 0,0 0;}
  to{background-position:22px -10px,-18px 12px;}
}
@keyframes svCapabilityGrid{
  from{background-position:0 0,0 0;}
  to{background-position:18px 10px,18px 10px;}
}

/* (2) Scrollable service boxes */
.sv-rowhead{display:flex;align-items:flex-end;justify-content:space-between;gap:var(--sp-20);margin-bottom:26px;flex-wrap:wrap;}
.sv-swipe{display:inline-flex;align-items:center;gap:var(--sp-4);font:600 12.5px/1 var(--f-mono);letter-spacing:.06em;text-transform:uppercase;color:var(--muted);}
.sv-swipe svg{color:var(--teal);}

.sv-scroll{display:flex;gap:var(--sp-20);overflow-x:auto;padding:4px 0 20px;scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch;scrollbar-width:thin;scrollbar-color:var(--blue) transparent;}
.sv-scroll::-webkit-scrollbar{height:8px;}
.sv-scroll::-webkit-scrollbar-track{background:var(--card-line);border-radius:var(--radius-8);}
.sv-scroll::-webkit-scrollbar-thumb{background:linear-gradient(90deg,var(--blue),var(--teal));border-radius:var(--radius-8);}

.sv-card{position:relative;flex:1 1 260px;min-width:260px;scroll-snap-align:start;display:flex;flex-direction:column;padding:30px 30px 26px;border-radius:var(--radius);color:#fff;text-decoration:none;overflow:hidden;background:linear-gradient(150deg,var(--blue),var(--aux-purple));box-shadow:0 18px 40px -24px rgba(var(--blue-rgb),.55);transition:transform var(--dur-base) var(--ease),box-shadow var(--dur-base) var(--ease);}
.sv-card::after{content:"";position:absolute;inset:0;background:radial-gradient(120% 90% at 100% 0%,rgba(var(--white-rgb),.20),transparent 55%);opacity:0;transition:opacity var(--dur-base) var(--ease);pointer-events:none;}
.sv-card:hover{transform:translateY(-6px);box-shadow:0 26px 54px -22px rgba(var(--blue-rgb),.6);}
.sv-card:hover::after{opacity:1;}
/* per-card colour variety (iHQ palette) */
.sv-card:nth-child(4n+1){background:linear-gradient(150deg,var(--blue),var(--aux-purple));}
.sv-card:nth-child(4n+2){background:linear-gradient(150deg,var(--blue),var(--aux-purple));}
.sv-card:nth-child(4n+3){background:linear-gradient(150deg,var(--blue),#8A2A5E);}
.sv-card:nth-child(4n+4){background:linear-gradient(150deg,var(--blue),var(--aux-purple));}
.sv-ic{width:52px;height:52px;border-radius:var(--radius-14);display:grid;place-items:center;color:#fff;background:rgba(var(--white-rgb),.16);border:1px solid rgba(var(--white-rgb),.26);margin-bottom:auto;}
.sv-card h3{margin:26px 0 8px;font:600 22px/1.15 var(--f-display);letter-spacing:-.01em;color:#fff;}
.sv-card p{margin:0;font-size:14.5px;line-height:1.5;color:rgba(var(--white-rgb),.9);}
.sv-go{position:absolute;top:30px;right:28px;color:rgba(var(--white-rgb),.75);transform:translateX(-4px);opacity:.7;transition:transform var(--dur-base) var(--ease),opacity var(--dur-base) var(--ease);}
.sv-card:hover .sv-go{transform:translateX(0);opacity:1;}

/* (3) Client stories */

/* (4) Compact contact form */
.sv-contact{display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-40);align-items:center;padding:44px;border-radius:var(--radius-14);background:linear-gradient(150deg,rgba(var(--blue-rgb),.06),rgba(var(--blue-rgb),.06));border:1px solid var(--card-line);}
.sv-contact-intro .eyebrow{margin-bottom:14px;}
.sv-contact-intro h2{margin-bottom:14px;}
.sv-contact-intro p{margin:0;max-width:420px;font-size:16px;line-height:1.55;color:var(--text-2);}
.sv-form{padding:30px;border-radius:var(--radius);background:var(--card);border:1px solid var(--card-line);box-shadow:var(--sh-contact);}
.sv-form .field:last-of-type{margin-bottom:22px;}
.sv-form textarea{min-height:96px;}

/* Responsive */
@media (max-width:860px){
  .sv-stories{grid-template-columns:1fr;}
  .sv-contact{grid-template-columns:1fr;gap:var(--sp-28);padding:30px 24px;}
}
@media (max-width:560px){
  .sv-card{flex-basis:82%;min-width:82%;}
}
@media(prefers-reduced-motion:reduce){.pg-services .sv-hero+.section::before,
                                      .pg-services .sv-hero+.section::after{animation:none;}}
/* ============================================================
   FX — per-page signature effects (fx.js companions)
   ============================================================ */
/* hero canvas layers */
.fx-heroBg{position:absolute;inset:0;z-index:0;overflow:hidden;}
.fx-heroBg canvas,.hero-image .bg .fx-silk,.hero-image .bg .fx-pulse{position:absolute;inset:0;width:100%;height:100%;display:block;}
.fx-hero-on .container{position:relative;z-index:1;}
.fx-hero-on.page-hero .glow{display:none;}
/* silk: canvas covers the hero photo; keep the dark text-contrast overlay above it */
.fx-silk-dark .bg img{display:none;}
.fx-silk-dark .bg::after{background:linear-gradient(90deg,rgba(6,12,24,.72),rgba(6,12,24,.34) 52%,rgba(6,12,24,.12));}
.fx-silk-light.page-hero{border-bottom:1px solid var(--line);}
.fx-silk-fallback.fx-silk-dark .bg{background:linear-gradient(135deg,#001F4D,var(--blue));}
.fx-silk-fallback.fx-silk-dark .bg canvas{display:none;}
/* pulse: dot-field replaces the photo */
.fx-pulse-dark .bg img{display:none;}
.fx-pulse-dark .bg::after{background:linear-gradient(90deg,rgba(4,8,16,.55),rgba(4,8,16,.22) 55%,rgba(4,8,16,.05));}
/* film grain on hero sections (not the homepage) */
.fx-hero-on::before{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;opacity:.05;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)'/%3E%3C/svg%3E");}
/* signal strip (contact) */
.fx-signal{position:relative;height:96px;margin:6px 0 26px;}
.fx-signal canvas{position:absolute;inset:0;width:100%;height:100%;display:block;}
/* weight headline (careers) */
.fx-wchar{display:inline-block;font-variation-settings:'wght' 500;will-change:font-variation-settings;}
.cr-loc-clock{display:inline-flex;align-items:center;gap:var(--sp-4);margin-top:6px;font:500 12px/1 var(--f-mono);letter-spacing:.06em;color:var(--muted);font-variant-numeric:tabular-nums;}
.cr-loc-clock::before{content:"";width:6px;height:6px;border-radius:50%;background:#FF9E16;box-shadow:0 0 6px rgba(255,158,22,.7);}
.fx-night .cr-loc-clock::before{background:var(--blue);box-shadow:0 0 6px rgba(var(--blue-rgb),.7);}
.fx-colon{animation:fxblink 2s steps(1) infinite;}
@keyframes fxblink{50%{opacity:.25;}}
@media (prefers-reduced-motion:reduce){.fx-colon{animation:none;}}
/* reading progress (legal/article) */
.fx-progress{position:fixed;top:0;left:0;right:0;height:2px;z-index:400;transform-origin:0 50%;transform:scaleX(0);
  background:linear-gradient(90deg,var(--blue),var(--teal));}
/* --- beams (partners ecosystem) --- */
.fx-beams-sec{padding:26px 0 8px;}
.fx-beams{display:block;width:100%;height:auto;margin-top:14px;}
.fxb-line{fill:none;stroke:rgba(var(--blue-rgb),.16);stroke-width:1.5;}
.fxb-beam{fill:none;stroke:url(#fxbGrad);stroke:var(--blue);stroke-width:1.8;stroke-linecap:round;
  stroke-dasharray:16 620;animation:fxbflow 2.8s linear infinite;opacity:.85;}
@keyframes fxbflow{to{stroke-dashoffset:-636;}}
.fxb-hub rect{fill:#001F4D;stroke:rgba(var(--blue-rgb),.4);rx:13;}
.fxb-hub text{fill:#fff;font:600 15px var(--f-display);letter-spacing:.08em;text-anchor:middle;}
.fxb-node rect{fill:#fff;stroke:rgba(var(--ink-rgb),.14);transition:stroke var(--dur-fast),filter var(--dur-fast);}
.fxb-node text{fill:#002E72;font:600 13.5px var(--f-display);text-anchor:middle;}
.fxb-node{cursor:default;}
.fx-beams[data-focus]:not([data-focus=""]) .fxb-beam{opacity:.14;}
.fx-beams[data-focus="0"] .fxb-beam[data-p="0"],.fx-beams[data-focus="1"] .fxb-beam[data-p="1"],
.fx-beams[data-focus="2"] .fxb-beam[data-p="2"],.fx-beams[data-focus="3"] .fxb-beam[data-p="3"],
.fx-beams[data-focus="4"] .fxb-beam[data-p="4"],.fx-beams[data-focus="5"] .fxb-beam[data-p="5"]{opacity:1;animation-duration:1.2s;}
.fx-beams[data-focus="0"] .fxb-node[data-p="0"] rect,.fx-beams[data-focus="1"] .fxb-node[data-p="1"] rect,
.fx-beams[data-focus="2"] .fxb-node[data-p="2"] rect,.fx-beams[data-focus="3"] .fxb-node[data-p="3"] rect,
.fx-beams[data-focus="4"] .fxb-node[data-p="4"] rect,.fx-beams[data-focus="5"] .fxb-node[data-p="5"] rect{stroke:var(--blue);filter:drop-shadow(0 0 8px rgba(var(--blue-rgb),.4));}
@media (prefers-reduced-motion:reduce){.fxb-beam{animation:none;stroke-dasharray:none;opacity:.35;}}
@media (max-width:760px){.fx-beams-sec{display:none;}}
/* --- thread (about) --- */
.fx-thread{position:fixed;left:26px;top:0;bottom:0;width:2px;z-index:120;background:rgba(var(--ink-rgb),.08);}
.fx-thread-fill{position:absolute;inset:0;transform-origin:0 0;transform:scaleY(0);
  background:linear-gradient(180deg,var(--blue),var(--teal));}
.fx-thread-tip{position:absolute;left:50%;top:0;width:10px;height:10px;border-radius:50%;transform:translate(-50%,-50%);
  background:var(--teal);box-shadow:0 0 12px rgba(var(--blue-rgb),.8);}
.interior-v2 .fx-thread{display:none!important;}
/* --- evidence chart (case-study) --- */
.fx-chart{margin-top:8px;}
.fx-chart svg{display:block;width:100%;max-width:760px;height:auto;}
.fxc-axis{stroke:rgba(var(--ink-rgb),.14);stroke-width:1;}
.fxc-line{fill:none;stroke:var(--blue);stroke-width:2.4;stroke-linecap:round;transition:stroke-dashoffset var(--dur-slow) var(--ease);}
.fxc-area{fill:url(#x);fill:rgba(var(--blue-rgb),.07);opacity:0;transition:opacity var(--dur-base) .9s;}
.fxc-go .fxc-area{opacity:1;}
.fxc-dot{fill:var(--teal);opacity:0;}
.fxc-go .fxc-dot{opacity:1;transition:opacity var(--dur-fast) .3s;}
.fxc-lab{font:600 11px var(--f-mono);letter-spacing:.12em;fill:rgba(var(--ink-rgb),.45);}
.fxc-lab2{fill:var(--teal);font-size:15px;}
/* --- cross-page morph (customer stories -> case study) --- */
@media (prefers-reduced-motion: no-preference){
  @view-transition { navigation: auto; }
  ::view-transition-old(case-hero),::view-transition-new(case-hero){animation-duration:.32s;}
}
/* ============================================================
   CARDS — interactive card system (fx.js companion, home excluded)
   ============================================================ */
.fx-card{transform-style:preserve-3d;
  transition:transform var(--dur-base) var(--ease),box-shadow var(--dur-base) var(--ease),border-color var(--dur-base);}
.fx-card.fx-card{transform:perspective(900px) rotateX(var(--rx,0deg)) rotateY(var(--ry,0deg));}
.fx-card.fx-card-on{transition:box-shadow var(--dur-base) var(--ease),border-color var(--dur-base);}
/* moving glare + cursor spotlight (one overlay, above media, below text) */
.fx-card::before{content:"";position:absolute;inset:0;z-index:3;pointer-events:none;opacity:0;
  border-radius:inherit;mix-blend-mode:soft-light;transition:opacity var(--dur-base) var(--ease);
  background:radial-gradient(240px circle at var(--gx,50%) var(--gy,0%),rgba(var(--white-rgb),.55),transparent 60%);}
.fx-card.fx-card-on::before{opacity:.9;}
/* keep the rcard text/gradient legible above the glare */
.rcard.fx-card .rc-body{z-index:4;}
/* subtle accent ring that intensifies on hover for solid cards */
.sv-card.fx-card.fx-card-on,.card.fx-card.fx-card-on{box-shadow:0 40px 80px -34px rgba(0,31,77,.5),0 0 0 1px rgba(var(--blue-soft-rgb),.35);}
.rcard.fx-card{will-change:transform;}
/* magnetic careers cards: layered depth on the inner text */
.cr-loc{transition:transform var(--dur-base) var(--ease),box-shadow var(--dur-base) var(--ease),border-color var(--dur-base);will-change:transform;}
.cr-loc .cr-loc-name{transition:transform var(--dur-base) var(--ease);}
.cr-loc:hover .cr-loc-name{transform:translateZ(0) translateX(3px);}
@media (prefers-reduced-motion:reduce){
  .fx-card{transform:none!important;}
  .fx-card::before{display:none;}
}
/* --- drift: scroll-linked horizontal line parallax (fx.js) --- */
.fx-drift-on .fx-dl{display:block;will-change:transform;}
@media (prefers-reduced-motion:reduce){.fx-drift-on .fx-dl{transform:none!important;}}
/* --- word-by-word highlight (fx.js) --- */
.fx-hl .fx-hw{opacity:.26;transition:opacity var(--dur-base) var(--ease);}
.fx-hl.fx-hl-in .fx-hw{opacity:1;}
.hero-image .fx-hl .fx-hw,.fx-silk-dark .fx-hl .fx-hw{opacity:.34;}
@media (prefers-reduced-motion:reduce){.fx-hl .fx-hw{opacity:1!important;transition:none;}}
/* ============================================================
   AI ASSISTANT WIDGET (chat.js)
   ============================================================ */
.bx-chat{position:fixed;right:22px;bottom:22px;z-index:600;font-family:var(--f-body);transition:bottom var(--dur-base) var(--ease);}
/* When the cookie banner is open, lift the chat launcher clear of it (no overlap on the consent controls) */
body.bs-cookie-open .bx-chat{bottom:calc(var(--cookie-h,84px) + 18px);}
@media(max-width:600px){body.bs-cookie-open .bx-tip{display:none;}body.bs-cookie-open .bx-chat{bottom:calc(var(--cookie-h,180px) + 18px);}}
/* floating brand-logo launcher */
.bx-chat-btn{position:relative;width:64px;height:64px;border-radius:50%;border:none;cursor:pointer;padding:0;overflow:visible;
  background:linear-gradient(140deg,var(--blue),var(--teal));box-shadow:0 18px 40px -14px rgba(var(--blue-rgb),.7);
  display:flex;align-items:center;justify-content:center;
  transition:transform var(--dur-base) var(--ease),box-shadow var(--dur-base) var(--ease);animation:bx-bob 3.6s ease-in-out infinite;}
.bx-btn-logo{width:32px;height:32px;object-fit:contain;position:relative;z-index:2;filter:brightness(0) invert(1);
  translate:var(--tx,0) var(--ty,0);
  transition:rotate var(--dur-base) var(--ease),scale var(--dur-base) var(--ease),translate var(--dur-fast) var(--ease);}
.bx-btn-ring{position:absolute;inset:0;border-radius:50%;z-index:0;pointer-events:none;
  box-shadow:0 0 0 2px rgba(var(--white-rgb),.55);animation:bx-pulse 2.8s ease-out infinite;}
.bx-chat-btn:hover{box-shadow:0 24px 52px -14px rgba(var(--blue-rgb),.85),0 0 0 4px rgba(var(--blue-rgb),.25);}
.bx-chat-btn:hover .bx-btn-logo{rotate:90deg;}
.bx-chat-btn:active{transform:scale(1.02);}
.bx-open .bx-chat-btn{animation:none;transform:scale(.9);}
.bx-open .bx-chat-btn:hover .bx-btn-logo{rotate:0deg;}
.bx-open .bx-btn-ring{display:none;}
@keyframes bx-bob{0%,100%{translate:0 0}50%{translate:0 -6px}}
@keyframes bx-pulse{0%{transform:scale(1);opacity:.6}70%{opacity:0}100%{transform:scale(1.85);opacity:0}}
/* greeting teaser bubble — invites interaction */
.bx-tip{position:absolute;right:74px;bottom:12px;width:212px;background:#fff;color:var(--ink);text-align:left;
  padding:12px 14px;border-radius:var(--radius-14);border-bottom-right-radius:5px;
  box-shadow:0 20px 44px -18px rgba(0,31,77,.45),0 0 0 1px rgba(var(--blue-rgb),.06);
  opacity:0;visibility:hidden;transform:translateX(10px) scale(.95);transform-origin:100% 100%;
  transition:opacity var(--dur-base) var(--ease),transform var(--dur-base) var(--ease),visibility var(--dur-base);cursor:pointer;}
.bx-tip.show{opacity:1;visibility:visible;transform:none;}
.bx-tip b{display:block;font:600 12px var(--f-display);color:var(--blue);margin-bottom:3px;letter-spacing:.01em;}
.bx-tip span{font-size:13px;line-height:1.42;color:var(--text);}
.bx-tip::after{content:"";position:absolute;right:-5px;bottom:16px;width:12px;height:12px;background:#fff;transform:rotate(45deg);border-radius:var(--radius-4);}
/* header logo chip */
.bx-logo-chip{width:34px;height:34px;border-radius:var(--radius-8);flex:none;display:flex;align-items:center;justify-content:center;
  background:rgba(var(--white-rgb),.16);border:1px solid rgba(var(--white-rgb),.25);}
.bx-logo-chip img{width:20px;height:20px;object-fit:contain;filter:brightness(0) invert(1);}
.bx-chat-panel{position:absolute;right:0;bottom:76px;width:min(370px,calc(100vw - 32px));height:min(540px,70vh);
  background:#fff;border:1px solid var(--card-line);border-radius:var(--radius-20);overflow:hidden;display:flex;flex-direction:column;
  box-shadow:0 40px 90px -30px rgba(0,31,77,.5);opacity:0;visibility:hidden;transform:translateY(16px) scale(.98);
  transform-origin:bottom right;transition:opacity var(--dur-fast) var(--ease),transform var(--dur-base) var(--ease),visibility var(--dur-fast);}
.bx-open .bx-chat-panel{opacity:1;visibility:visible;transform:none;}
.bx-chat-head{display:flex;align-items:center;gap:var(--sp-12);padding:16px 16px;color:#fff;
  background:linear-gradient(135deg,#001F4D,var(--blue));}
.bx-chat-head b{font:600 15px/1.2 var(--f-display);display:block;}
.bx-chat-head small{display:flex;align-items:center;gap:var(--sp-4);font-size:11.5px;opacity:.8;}
.bx-chat-dot{width:9px;height:9px;border-radius:50%;background:var(--blue);box-shadow:0 0 10px var(--blue);flex:none;}
.bx-chat-x{margin-left:auto;background:none;border:none;color:#fff;font-size:24px;line-height:1;cursor:pointer;opacity:.8;}
.bx-chat-x:hover{opacity:1;}
.bx-chat-log{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:var(--sp-8);background:#F6F8FC;}
.bx-msg{max-width:82%;padding:11px 14px;border-radius:var(--radius-14);font-size:14px;line-height:1.5;}
.bx-msg a{color:var(--blue);font-weight:600;text-decoration:underline;}
.bx-bot{align-self:flex-start;background:#fff;border:1px solid var(--card-line);color:var(--ink);border-bottom-left-radius:5px;}
.bx-me{align-self:flex-end;background:linear-gradient(135deg,var(--blue),var(--blue));color:#fff;border-bottom-right-radius:5px;}
.bx-typing{display:flex;gap:var(--sp-4);align-items:center;}
.bx-typing span{width:6px;height:6px;border-radius:50%;background:var(--muted);animation:bxdot 1s infinite;}
.bx-typing span:nth-child(2){animation-delay:.15s;} .bx-typing span:nth-child(3){animation-delay:.3s;}
@keyframes bxdot{0%,60%,100%{opacity:.3;transform:translateY(0);}30%{opacity:1;transform:translateY(-3px);}}
.bx-chat-chips{display:flex;flex-wrap:wrap;gap:var(--sp-8);padding:0 14px 4px;background:#F6F8FC;}
.bx-chip{font-size:12.5px;padding:7px 12px;border-radius:999px;border:1px solid color-mix(in srgb,var(--blue) 30%,transparent);
  background:color-mix(in srgb,var(--blue) 7%,#fff);color:var(--blue);cursor:pointer;transition:background var(--dur-fast);}
.bx-chip:hover{background:color-mix(in srgb,var(--blue) 14%,#fff);}
.bx-chat-form{display:flex;gap:var(--sp-8);padding:12px 14px;border-top:1px solid var(--card-line);background:#fff;}
.bx-chat-form input{flex:1;border:1px solid var(--card-line);border-radius:999px;padding:11px 15px;font-size:14px;color:var(--ink);outline:none;}
.bx-chat-form input:focus{border-color:var(--blue);box-shadow:0 0 0 3px rgba(var(--blue-rgb),.12);}
.bx-chat-form button{width:42px;height:42px;flex:none;border:none;border-radius:50%;cursor:pointer;color:#fff;
  background:linear-gradient(135deg,var(--blue),var(--teal));display:flex;align-items:center;justify-content:center;}
@media (prefers-reduced-motion:reduce){.bx-chat-panel,.bx-chat-btn{transition:opacity var(--dur-fast);}.bx-typing span{animation:none;}
  .bx-chat-btn{animation:none;}.bx-btn-ring{animation:none;opacity:.35;}.bx-btn-logo{transition:none;}.bx-tip{transition:opacity var(--dur-fast);}}
/* --- about metrics: brand icons above the number (light bg) --- */
.metric-ic{display:inline-flex;margin-bottom:12px;color:var(--blue);line-height:0;}
.metric-ic svg{width:46px;height:46px;filter:drop-shadow(0 0 5px color-mix(in srgb,currentColor 32%,transparent));}
.metrics .metric:nth-child(2) .metric-ic,.metrics .metric:nth-child(4) .metric-ic{color:var(--teal);}
/* ============================================================
   News parallax tiles (Accenture-style) — fx.js drives data-speed
   ============================================================ */
/* light but colourful — glows sit LOWER so the top edge stays a clean pale blue that continues the
   stats fade (no re-colouring bump at the seam); brightness rises monotonically to white for the form */
.ah-news2{--news-overlap:88px;position:relative;z-index:1;overflow:hidden;
  background:
    radial-gradient(46% 40% at 50% 4%,rgba(var(--blue-rgb),.22),transparent 60%),
    radial-gradient(58% 48% at 90% 42%,rgba(var(--blue-rgb),.20),transparent 62%),
    radial-gradient(52% 46% at 2% 48%,rgba(var(--blue-rgb),.12),transparent 64%),
    radial-gradient(66% 44% at 66% 66%,rgba(var(--blue-soft-rgb),.12),transparent 62%),
    linear-gradient(180deg,#FFFFFF 0%,#F1F8FC 11%,#DFEEF8 40%,#E7F3FA 72%,#ffffff 100%);
  margin-top:calc(var(--news-overlap) * -1);
  padding:calc(58px + var(--news-overlap)) 0 130px;
  -webkit-mask-image:linear-gradient(180deg,transparent 0,#000 var(--news-overlap),#000 100%);
          mask-image:linear-gradient(180deg,transparent 0,#000 var(--news-overlap),#000 100%);}
/* carry the hero's dot-grid texture down into the news top — visual continuity across the seam */
/* The dot texture now runs the whole band rather than the top 360px. With the ghost word
   removed the lower half was bare gradient, and a section that is textured at the top and
   empty at the bottom reads as unfinished rather than as quiet. */
.ah-news2::before{content:"";position:absolute;inset:0;z-index:0;pointer-events:none;
  background-image:radial-gradient(rgba(var(--blue-rgb),.16) 1px,transparent 1.4px);background-size:26px 26px;
  -webkit-mask-image:linear-gradient(180deg,transparent 0%,#000 14%,#000 72%,transparent 100%);
          mask-image:linear-gradient(180deg,transparent 0%,#000 14%,#000 72%,transparent 100%);opacity:.6;}
@media (max-width:860px){.ah-news2{--news-overlap:56px;}}
/* The ground for this band is the gradient wash plus the dot texture above — nothing else.
   Two devices have now come off this spot and it is worth recording why, because the answer
   was the same both times and it was not "find a better graphic".

   First the oversized ghost word "Insights": the old site's idiom, and it printed a word the
   heading already says two lines below. Then a set of horizontal hairlines meant to read as
   motion streaks — the client's note was "why so many lines", and the arithmetic agrees:
   139px and 47px pitches over a 987px band draw 22 rules, which is not texture, it is ruled
   paper. A brand diamond was never a candidate; the client had already said there are too
   many logo watermarks (see the note at .ah-c-dia).

   What the band actually carries is a four-stop radial wash, a white-to-pale-blue gradient
   and the dot grid at .6 — three layers before anything decorative is added, under eight
   raised tiles that already stagger vertically. A fourth layer had nowhere to sit that was
   not on top of one of those. So the ground stays as it is; the tiles are the subject. */
.ah-news2-head{position:relative;z-index:2;margin-bottom:8px;}
.ah-news2-head h2{color:var(--ink);}
.ah-news2-head .ah-more{color:var(--blue);}
.ah-news2-head .ah-more:hover{color:var(--blue);}
/* full-width auto-scroll marquee; each tile also floats up/down */
/* Four at a time, stepped by the arrows above — not an auto-running marquee.
   The grab cursor went with the drag-scroll it advertised, and so did the edge mask:
   that faded tiles into an endlessly looping track, and against a fixed set it only made
   the first and last card look damaged. scroll-snap leaves a card edge at the rail's left
   after any step, whether it came from an arrow, a swipe or the keyboard. */
/* The rail shows FOUR and only four.

   It is capped and centred rather than running to the viewport edges. Left full-bleed, the
   only way to keep exactly four visible on a wide window is to let the tiles grow with the
   window, and at 2000px that makes each card 474px — a card the size of a small hero. The
   cap is the width four tiles at their intended size actually need:
   4 x 340 + 3 x 20 (gap) + 44 (the track's own side padding) = 1464px. Below that the rail
   is full width and the tiles shrink to fit; above it the rail stops growing and centres,
   so the fifth card is outside the scrollport instead of peeking in.

   scroll-padding-left matches the track's padding-left. Without it, scroll-snap aligns the
   first tile's start edge to the scrollport edge and parks the rail at scrollLeft 22 on
   load — which slid a 22px sliver of the fifth card into view no matter how the widths
   were computed. */
.ah-news2-marquee{position:relative;z-index:1;overflow-x:auto;overflow-y:hidden;padding:14px 0 30px;
  max-width:1464px;margin-inline:auto;scroll-padding-left:22px;
  scrollbar-width:none;scroll-snap-type:x mandatory;overscroll-behavior-x:contain;}
.ah-news2-marquee::-webkit-scrollbar{display:none;}
/* --news-cols is the whole control: four across the desktop rail, fewer as it narrows.
   The tile takes its width from that rather than a fixed 330px, so four fit the rail
   exactly instead of the fourth being clipped at unlucky widths. */
.ah-news2-track{display:flex;gap:var(--sp-20);width:max-content;padding:72px 22px 30px;align-items:flex-start;--news-cols:4;}
/* Two things were wrong with the old width and both put a fifth card on screen.
   It subtracted 2 x --pad, the container's gutters — but this rail is full-bleed and has no
   gutters, so 96px at 1440 (136px at 2000) came out of the tiles and reappeared as bare
   rail on the right. And it subtracted 22px per gap while the flex gap is --sp-20, 20px.
   The width is now exactly what four tiles need inside the rail, and max-width is gone:
   the rail's own cap does that job now, in one place. */
.ah-news2-track .ah-tile{scroll-snap-align:start;
  /* cols x tile + cols x gap + the track's padding-left = the rail. Note it is cols gaps,
     not cols-1: the gap after the fourth tile has to be inside the rail too, or the fifth
     tile begins 2px before the edge and shows a hairline of itself. The track's
     padding-right is not in the sum — padding only lands after the last tile, never
     between the fourth and the fifth. */
  flex:0 0 calc((min(100vw,1464px) - 22px - var(--news-cols) * var(--sp-20)) / var(--news-cols));
  min-width:236px;}
@media (max-width:1200px){.ah-news2-track{--news-cols:3;}}
@media (max-width:900px){.ah-news2-track{--news-cols:2;}}

/* The arrows FLANK the band — one at each end, on the cards' own centre line — rather than
   stacking in the top-right corner. Rendered in the template rather than by script so they
   exist before JS runs; fx.js only wires them and manages the disabled state, and hides the
   pair when there is nothing to page through.

   They were in the corner, tucked under the "All insights" link, and the client had already
   reported once that they could not find them. The corner is where a pager goes when it is
   an afterthought; the ends of the band are where a reader's hand already is, and it is what
   every carousel they use elsewhere does.

   Centred on .ah-news2-stage rather than on a measured offset: the tiles are staggered
   (0 / 66 / 24 / 88 / 44px of top margin) and their height follows --news-cols, which steps
   at 1200 and 900. Any fixed top would be right at one width and wrong at the other two;
   the stage is exactly as tall as the marquee, so align-items:center tracks all of them.

   pointer-events:none on the strip, auto on the buttons — the strip spans the whole band and
   would otherwise swallow every click and drag meant for the cards under it. */
.ah-news2-stage{position:relative;}
.ah-news2-nav-wrap{
  position:absolute;top:0;bottom:0;left:0;right:0;z-index:3;
  /* Bottom corners, at the client's call — not the vertical centre. The tiles are
     staggered by up to 88px, so a centred pager sits on a different part of each card as
     the rail moves and reads as floating; the floor of the band is one line, and both
     arrows sit on it. The stage ends 30px below the lowest tile (the track's own bottom
     padding), which is the gap that keeps them off the cards. */
  display:flex;align-items:flex-end;margin-bottom:0;pointer-events:none;
}
.ah-news2-nav{display:flex;justify-content:space-between;width:100%;gap:var(--sp-8);}
.ah-news2-arrow{pointer-events:auto;}
/* Touch pages the band by swiping, and an arrow parked over the first card costs more than
   it gives on a 390px screen. */
@media (max-width:720px){.ah-news2-nav-wrap{display:none;}}
/* These were white — glyph, border and fill all rgba(var(--white-rgb),...) — which was written for
   a dark band and never revisited when this one became a white-to-pale-blue wash. Measured
   against the ground under them, rgb(230,242,250): the chevron came out at 1.14:1 and the
   ring at 1.04:1, so both were invisible and the control read as empty space.

   It is a raised white chip now, which is the band's own vocabulary — every tile beside it is
   a raised chip with a navy shadow, so the pager belongs to the same family. The chevron is
   --blue, the same ink as the "All insights" link it sits under, at 4.02:1 on the white fill.

   Disabled swaps colour instead of dropping opacity. opacity:.3 over an already-faint control
   removed it from the page entirely; a grey hairline ring with a grey chevron at 3.26:1 stays
   legible while reading clearly as unavailable.

   Hover borrows .ah-btn-ghost's own values rather than inventing a second set — same
   border-color:var(--blue), same #00606F ink. That button is already this site's secondary
   control on a light ground, so the two now behave identically, which is the sort of thing
   the client meant by the design not reading as tied together.

   Hover moves colour and shadow, never scale — the tiles beside it do the same (see the
   outline-color on .ah-tile:hover). */
.ah-news2-arrow{
  width:44px;height:44px;display:grid;place-items:center;
  border:1px solid color-mix(in srgb,var(--blue) 55%,transparent);border-radius:999px;
  background:#fff;color:var(--blue);cursor:pointer;
  box-shadow:0 1px 2px rgba(0,31,77,.10),0 8px 20px -10px rgba(0,31,77,.34);
  transition:background var(--dur-fast) var(--ease),border-color var(--dur-fast) var(--ease),
             color var(--dur-fast) var(--ease),box-shadow var(--dur-fast) var(--ease);
}
.ah-news2-arrow:hover:not(:disabled){
  border-color:var(--blue);color:#00606F;
  box-shadow:0 2px 4px rgba(0,31,77,.12),0 14px 28px -12px rgba(0,31,77,.42);
}
.ah-news2-arrow:focus-visible{outline:2px solid var(--blue);outline-offset:3px;}
/* Disabled keeps the chip and changes only the ink.

   It used to drop the fill and the shadow as well — background:transparent over a
   border-color:var(--line-2) ring, which is rgba(43,46,49,.16). That was written when the
   pair sat in the corner over the band's pale wash, where a ring alone is legible. The
   arrows now stand at the ends of the card band, on top of the tiles, and the first tile is
   a photograph: measured against it, the ring and the shadow disappear completely and all
   that is left is a grey chevron floating on the picture. The prev arrow is disabled on
   load, so that was the state a first-time visitor met — the control read as absent.

   A disabled control still has to look like a control. Same white chip, same ring geometry,
   same shadow; the chevron goes grey and the ring goes neutral. Grey #7D868C on the white
   fill measures 3.71:1, clear of the 3:1 a UI glyph needs, and it separates from the live
   arrow by hue rather than by being harder to see. Opacity is deliberately NOT used: it
   would fade the white fill back into the photograph and bring the original fault back. */
.ah-news2-arrow:disabled{
  background:#fff;
  border-color:rgba(var(--ink-rgb),.28);
  color:var(--aux-grey);
  box-shadow:0 1px 2px rgba(0,31,77,.10),0 8px 20px -10px rgba(0,31,77,.34);
  cursor:default;
}
@keyframes ah-tilefloat{0%,100%{translate:0 0;}50%{translate:0 -18px;}}
.ah-news2-track .ah-tile:nth-child(5n+1){margin-top:0;animation-duration:5.4s;animation-delay:-0.2s;}
.ah-news2-track .ah-tile:nth-child(5n+2){margin-top:66px;animation-duration:6.6s;animation-delay:-2.1s;}
.ah-news2-track .ah-tile:nth-child(5n+3){margin-top:24px;animation-duration:5.9s;animation-delay:-3.4s;}
.ah-news2-track .ah-tile:nth-child(5n+4){margin-top:96px;animation-duration:7.1s;animation-delay:-1.2s;}
.ah-news2-track .ah-tile:nth-child(5n+5){margin-top:40px;animation-duration:6.2s;animation-delay:-4.0s;}
.ah-tile{position:relative;overflow:hidden;flex:0 0 330px;border-radius:var(--radius-14);aspect-ratio:3/4.1;display:block;text-decoration:none;color:#fff;
  box-shadow:0 26px 52px -30px rgba(0,31,77,.42);animation:ah-tilefloat 6s ease-in-out infinite;
  transition:box-shadow var(--dur-base) var(--ease),outline-color var(--dur-base);outline:1px solid transparent;outline-offset:-1px;}
.ah-tile:hover{box-shadow:0 38px 72px -28px rgba(0,31,77,.52);outline-color:rgba(var(--blue-rgb),.28);}
/* fallback tint if a photo is missing */
.nt-a{background:var(--blue);} .nt-b{background:var(--blue);} .nt-c{background:var(--blue);} .nt-d{background:var(--blue);} .nt-e{background:var(--blue);}
/* event photo + readability gradient (with a subtle brand-blue tint) */
.ah-tile-media{position:absolute;inset:0;z-index:0;overflow:hidden;}
.ah-tile-media img{width:100%;height:100%;object-fit:cover;display:block;transition:transform var(--dur-base) var(--ease);}

.ah-tile-shade{position:absolute;inset:0;z-index:1;pointer-events:none;
  background:linear-gradient(180deg,rgba(var(--blue-rgb),.12) 0%,rgba(0,28,68,.18) 42%,rgba(1,14,34,.72) 78%,rgba(1,11,28,.9) 100%);
  transition:opacity var(--dur-base) var(--ease);}
.ah-tile:hover .ah-tile-shade{background:linear-gradient(180deg,rgba(var(--blue-rgb),.06) 0%,rgba(0,28,68,.14) 40%,rgba(1,14,34,.7) 78%,rgba(1,11,28,.9) 100%);}
.ah-tile-b{position:absolute;left:20px;right:20px;bottom:20px;z-index:2;}
.ah-tcat{font:600 9.5px/1.3 var(--f-mono);letter-spacing:.11em;text-transform:uppercase;color:rgba(var(--white-rgb),.82);}
.ah-tile h3{margin:9px 0 0;font:700 18px/1.28 var(--f-display);letter-spacing:-.01em;color:#fff;}
.ah-tile-go{margin-top:12px;display:inline-flex;align-items:center;gap:var(--sp-8);font:700 12.5px var(--f-body);color:#fff;opacity:0;transform:translateY(8px);transition:opacity var(--dur-base) var(--ease),transform var(--dur-base) var(--ease);}
.ah-tile-go i{font-style:normal;transition:transform var(--dur-fast) var(--ease);}
.ah-tile:hover .ah-tile-go{opacity:1;transform:none;}
.ah-tile:hover .ah-tile-go i{transform:translateX(4px);}
@media (max-width:1000px){
  .ah-news2-track{padding-top:80px;}
  .ah-news2-track .ah-tile{min-width:0;}
  
}
@media (max-width:600px){
  /* News on phones: manual swipe carousel — flat heights, snap-centered cards, no clipped edges */
  .ah-news2-marquee{scroll-padding:0 16px;}
  .ah-news2-track{padding:24px 16px 28px;gap:var(--sp-12);--news-cols:1;}
  /* One card per swipe. The selector matches the flex-basis rule above so it actually
     wins, and centre-snap is right here where a single card fills the rail. */
  .ah-news2-track .ah-tile{flex:0 0 80vw;max-width:320px;min-width:0;aspect-ratio:4/3.4;scroll-snap-align:center;animation:none;}
  /* Swipe is the natural control at this width and the arrows would crowd the heading. */
  .ah-news2-nav-wrap{display:none;}
  .ah-news2-track .ah-tile:nth-child(n){margin-top:0;} /* reset desktop vertical staggers -> flat snap row */
  .ah-tile-go{opacity:1;transform:none;}
  .home.motion-v1 .ah-news2-track .ah-tile{animation:none!important;translate:none!important;transform:none!important;}
}
@media (prefers-reduced-motion:reduce){
  .ah-news2-track{animation:none;}
  .ah-tile{animation:none;}
}

/* ===== Brand design element: the Diamond (SEA Brand Guide v2.1 §5) =====
   A single diamond of the mark, one corner cropped — used as an accent. */
.bs-diamond{
  position:absolute; display:block; pointer-events:none;
  background:var(--mark) center/contain no-repeat;
}
.bs-diamond-badge{ width:96px; height:96px; right:-14px; bottom:-14px; filter:drop-shadow(0 14px 22px rgba(var(--blue-rgb),.4)); }

/* ===== People band (brand-approved "People" photography) ===== */
.ah-people{ position:relative; overflow:hidden; padding:96px 0; background:linear-gradient(180deg,#FFFFFF,#F4F7FC); }
.ah-people::before{ content:""; position:absolute; z-index:0; left:-70px; bottom:-70px; width:280px; height:280px; opacity:.07;
  background:var(--mark) center/contain no-repeat; }
.ah-people-in{ position:relative; z-index:1; display:grid; grid-template-columns:1.05fr .95fr; gap:var(--sp-56); align-items:center; }
.ah-people-fig{ position:relative; margin:0; }
.ah-people-fig img{ width:100%; border-radius:var(--radius-20); display:block; object-fit:cover; box-shadow:0 34px 70px -30px rgba(0,31,77,.5); }
.ah-people-eyebrow{ display:flex; align-items:center; gap:var(--sp-8); margin:0 0 14px; font:600 12px/1 var(--f-mono); letter-spacing:.16em; text-transform:uppercase; color:var(--blue); }
.ah-people-eyebrow .ah-dot{ width:7px; height:7px; border-radius:50%; background:var(--blue); display:inline-block; }
.ah-people-copy h2{ margin:0 0 16px; font:700 clamp(28px,3.4vw,42px)/1.06 var(--f-display); letter-spacing:-.02em; color:var(--ink); }
.ah-people-copy p{ margin:0; font-size:17px; line-height:1.65; color:var(--muted); max-width:44ch; }
@media (max-width:820px){ .ah-people{ padding:64px 0; } .ah-people-in{ grid-template-columns:1fr; gap:var(--sp-32); } }

/* ===== Footer: registered slogan + stock code ===== */
.foot-brand p.foot-slogan{ margin:8px 0 6px; max-width:none; font-style:italic; font-size:18px; letter-spacing:.02em; color:var(--blue-soft); }
.foot-stock{ opacity:.85; }

/* ============================================================
   BRAND DIAMOND SYSTEM — a cohesive graphic language (SEA Guide §5)
   Reusable across every page: dividers, bullets, image crops,
   corner accents, markers, loaders, reveal.
   ============================================================ */
:root{ --dia:linear-gradient(150deg,var(--blue),var(--aux-purple)); --dia-sky:linear-gradient(150deg,var(--blue),var(--blue-soft)); --mark:url(img/mark.webp); }
/* the real Beyondsoft four-diamond mark, recoloured per context */

/* section divider: hairline —— ◆ —— hairline */
.bs-divider{ display:flex; align-items:center; gap:var(--sp-16); width:var(--maxw); max-width:100%; margin:56px auto; padding:0 var(--pad); }
.bs-divider::before,.bs-divider::after{ content:""; flex:1; height:1px; background:linear-gradient(90deg,transparent,var(--card-line) 22%,var(--card-line) 78%,transparent); }
.bs-divider i{ width:12px; height:12px; flex:0 0 auto; background:var(--dia); clip-path:polygon(50% 0,100% 50%,50% 100%,0 50%); }
.bs-divider i+i{ margin-left:-6px; opacity:.5; }
.bs-divider.lg i{ width:15px; height:15px; }
.bs-divider.dark::before,.bs-divider.dark::after{ background:linear-gradient(90deg,transparent,rgba(var(--white-rgb),.18) 22%,rgba(var(--white-rgb),.18) 78%,transparent); }

/* diamond bullet list */
ul.bs-list{ list-style:none; margin:0; padding:0; display:grid; gap:var(--sp-12); }
ul.bs-list li{ position:relative; padding-left:26px; color:var(--text); line-height:1.55; }
ul.bs-list li::before{ content:""; position:absolute; left:2px; top:.5em; width:9px; height:9px; background:var(--dia); clip-path:polygon(50% 0,100% 50%,50% 100%,0 50%); transition:transform var(--dur-fast) var(--ease); }
ul.bs-list li:hover::before{ transform:rotate(90deg); }

/* diamond eyebrow marker (swap the round dot for a diamond) */
.eyebrow.dia .dot,.eyebrow .dot.dia{ border-radius:0; box-shadow:none; background:var(--dia); clip-path:polygon(50% 0,100% 50%,50% 100%,0 50%); }

/* image cropped with a diamond-cut corner */
.dia-img.br{ clip-path:polygon(0 0,100% 0,100% 84%,84% 100%,0 100%); }   /* cut bottom-right */
.dia-img.tl{ clip-path:polygon(16% 0,100% 0,100% 100%,0 100%,0 16%); }   /* cut top-left */

/* Client feedback: too many logo watermarks. The corner diamond used to cascade to
   EVERY interior hero (28 templates), so it appeared on almost every page — removed. */
.page-hero .container{ position:relative; z-index:1; }

/* diamond reveal (rotate-scale in when scrolled into view) */
@keyframes bs-dia-in{ from{ opacity:0; transform:rotate(-28deg) scale(.55); } to{ opacity:1; transform:rotate(0) scale(1); } }
.bs-diamond.in-view,.dia-reveal.in-view{ animation:bs-dia-in .75s var(--ease) both; }

/* diamond spinner (loaders / async) */
@keyframes bs-spin{ to{ transform:rotate(360deg); } }

/* ============================================================
   MOTION / MICRO-INTERACTIONS (extends existing reveal system)
   ============================================================ */
/* magnetic buttons — JS sets --mx/--my; graceful without JS */
.btn,.ah-btn{ will-change:transform; }
.magnetic{ transition:transform var(--dur-fast) var(--ease); }
/* card shine that follows the cursor (JS sets --mx/--my as %) */
.shine{ position:relative; overflow:hidden; }
.shine::before{ content:""; position:absolute; inset:0; z-index:2; pointer-events:none; opacity:0; transition:opacity var(--dur-base);
  background:radial-gradient(220px circle at var(--mx,50%) var(--my,50%),rgba(var(--blue-soft-rgb),.20),transparent 60%); }
.shine:hover::before{ opacity:1; }
/* staggered children entrance — parent .stagger, children fade+rise as parent enters */
.stagger.in > *{ opacity:1; transform:none; }
.stagger > *{ opacity:0; transform:translateY(22px); transition:opacity var(--dur-base) var(--ease),transform var(--dur-base) var(--ease); }
.stagger > *:nth-child(1){ transition-delay:.04s } .stagger > *:nth-child(2){ transition-delay:.10s }
.stagger > *:nth-child(3){ transition-delay:.16s } .stagger > *:nth-child(4){ transition-delay:.22s }
.stagger > *:nth-child(5){ transition-delay:.28s } .stagger > *:nth-child(6){ transition-delay:.34s }
.stagger > *:nth-child(7){ transition-delay:.40s } .stagger > *:nth-child(8){ transition-delay:.46s }
/* underline-grow link */
.link-grow{ position:relative; color:var(--blue); font-weight:600; }
.link-grow::after{ content:""; position:absolute; left:0; bottom:-3px; width:100%; height:2px; background:var(--dia); transform:scaleX(0); transform-origin:left; transition:transform var(--dur-base) var(--ease); }
.link-grow:hover::after{ transform:scaleX(1); }
@media (prefers-reduced-motion:reduce){
  .bs-diamond.in-view,.dia-reveal.in-view{ animation:none; }
  ul.bs-list li:hover::before{ transform:none; }
  .stagger > *{ opacity:1; transform:none; }
  .bs-loader{ animation:none; }
}

/* ===== Homepage: Why Beyondsoft — modern bento (dark, glass, glow) ===== */
@keyframes wb-glow{ 0%{ transform:translate(0,0) scale(1); } 100%{ transform:translate(-4%,3%) scale(1.12); } }
.ah-why .container{ position:relative; z-index:1; }
.wb{ border-radius:var(--radius-20); padding:32px 30px; }
/* rich staggered entrance — 3D flip-up from the surface + blur-to-sharp + springy overshoot,
   with the icon springing and the number dropping a beat later. Uses translate/scale/rotate/
   filter (NOT transform) so it never fights the hover lift. */
.ah-why-bento.stagger > .wb{ transform:none; transform-origin:50% 94%; opacity:0; translate:0 66px; scale:.9; rotate:x 26deg;
  transition:opacity var(--dur-base) var(--ease), translate var(--dur-slow) var(--ease), scale var(--dur-slow) var(--ease), rotate var(--dur-slow) var(--ease), filter var(--dur-base) var(--ease), transform var(--dur-base) var(--ease); }
.ah-why-bento.stagger.in > .wb{ opacity:1; translate:0 0; scale:1; rotate:x 0deg; filter:blur(0); }
.ah-why-bento.stagger > .wb:nth-child(1){ transition-delay:.05s }
.ah-why-bento.stagger > .wb:nth-child(2){ transition-delay:.17s }
.ah-why-bento.stagger > .wb:nth-child(3){ transition-delay:.29s }
.ah-why-bento.stagger > .wb:nth-child(4){ transition-delay:.41s }
.ah-why-bento.stagger > .wb:nth-child(5){ transition-delay:.53s }
/* icon springs in, number drops in — a beat after the card */
.ah-why-bento.stagger > .wb .wb-ic{ opacity:0; scale:.35; rotate:-35deg;
  transition:opacity var(--dur-base) var(--ease), scale var(--dur-base) var(--ease), rotate var(--dur-base) var(--ease), transform var(--dur-base) var(--ease), background var(--dur-base), color var(--dur-base), box-shadow var(--dur-base); transition-delay:.36s; }
.ah-why-bento.stagger.in > .wb .wb-ic{ opacity:1; scale:1; rotate:0deg; }
.ah-why-bento.stagger > .wb .wb-no{ opacity:0; translate:0 -10px; transition:opacity var(--dur-base) var(--ease), translate var(--dur-base) var(--ease); transition-delay:.46s; }
.ah-why-bento.stagger.in > .wb .wb-no{ opacity:1; translate:0 0; }
@media (prefers-reduced-motion:reduce){
  .ah-why-bento.stagger > .wb,.ah-why-bento.stagger > .wb .wb-ic,.ah-why-bento.stagger > .wb .wb-no{ opacity:1!important; translate:none!important; scale:1!important; rotate:none!important; filter:none!important; }
}
@media (max-width:820px){ .ah-why{ padding:64px 0; } .ah-why-bento{ grid-template-columns:1fr; } .wb-lead{ grid-column:auto; } }

/* ===== Homepage: Testimonial / quote band ===== */
@media (max-width:820px){ .ah-quote{ padding:72px 0; } }

/* ============================================================
   INTRO + PAGE-TRANSITION — brand diamond veil
   Classes toggled by the <head> boot script + fx.js coverInit/navExit.
   Fail-safe: <head> timeout + reduced-motion guard can never trap the page.
   ============================================================ */
/* ── Page transitions ─────────────────────────────────────────────────────────
   Native cross-document view transitions, carrying Accenture's own numbers.

   THEIRS, read out of their shipped bundle rather than guessed at. accenture.com runs Barba.js
   with a transition named "rad-absorb-transition", sync:true, and these values:

     CustomEase.create("rad-animation-easing-function", "M0,0 C0.77,0 0.18,1 1,1")
     RIGHT_SIDE = { duration: 1.25, ease: <that>, left: "100vw" }
     leave  : .to(current, {duration:.7, opacity:0})
              .to(current, {duration:1.25, left:"-25vw"}, "-=0.7")
     enter  : .fromTo(next, RIGHT_SIDE, {...RIGHT_SIDE, left:<centred>})
     back   : the same two, mirrored

   So: 1.25s, cubic-bezier(.77,0,.18,1), horizontal. The outgoing page drifts left by a
   QUARTER of the viewport while the incoming sweeps the FULL width across it — the two move
   at different speeds, which is what makes it read as depth rather than as a slide. The
   outgoing also fades, but only over .7s of the 1.25s, so it is gone before it has finished
   travelling.

   The ease is the piece that matters most and the piece a guess will not land: .77,0,.18,1 is
   an ease-IN-out — it starts slowly, crosses the middle very fast, and settles long. An
   ease-out alone (what was here before, .16,1,.3,1 over 420ms) begins at full speed and has
   nothing to decelerate from, which is why it read as abrupt however short it was.

   None of this needs Barba. Barba exists to fetch and swap documents in JS; the browser now
   does that itself, and the same four keyframes below express the same motion. What is NOT
   copied is anything of theirs that is design rather than mechanics — no colours, no chrome,
   no graphic device. This is timing and direction.

   The one deliberate difference: their outgoing page holds a frozen scroll position via
   beforeLeave (position:relative, top:-scrollY, then scrollTo 0). Cross-document transitions
   do that for free — the old snapshot is a picture of the viewport, so it cannot scroll.

   Tunable in one place: --bs-vt-dur. */
:root{
  --bs-vt-dur:1.25s;
  --bs-vt-ease:cubic-bezier(.77,0,.18,1);
}
@view-transition{ navigation: auto; }

/* Forward. New sweeps in from the right, over the old. */
::view-transition-old(root){
  animation:bs-vt-out-fwd var(--bs-vt-dur) var(--bs-vt-ease) both;
}
::view-transition-new(root){
  animation:bs-vt-in-fwd var(--bs-vt-dur) var(--bs-vt-ease) both;
}
@keyframes bs-vt-out-fwd{
  /* opacity is done at 56% because their fade is .7s of a 1.25s move */
  0%{transform:translateX(0);opacity:1;}
  56%{opacity:0;}
  100%{transform:translateX(-25vw);opacity:0;}
}
@keyframes bs-vt-in-fwd{
  from{transform:translateX(100vw);}
  to{transform:translateX(0);}
}

/* Back. Mirrored, and the old sits on top because it is the thing being taken away. */
html.bs-nav-back::view-transition-old(root){
  animation-name:bs-vt-out-back;
  z-index:2;
}
html.bs-nav-back::view-transition-new(root){
  animation-name:bs-vt-in-back;
  z-index:1;
}
@keyframes bs-vt-out-back{
  from{transform:translateX(0);}
  to{transform:translateX(100vw);}
}
@keyframes bs-vt-in-back{
  0%{transform:translateX(-25vw);opacity:0;}
  56%{opacity:1;}
  100%{transform:translateX(0);opacity:1;}
}
@media (prefers-reduced-motion:reduce){
  ::view-transition-old(root),::view-transition-new(root){animation:none!important;}
}

html.bs-cover{ overflow:hidden; }
html.bs-cover::before{ content:""; position:fixed; inset:0; z-index:9998;
  background:radial-gradient(120% 120% at 70% 18%,rgba(var(--blue-rgb),.32),transparent 60%),linear-gradient(150deg,#001F4D,var(--blue) 58%,#00648f); }
/* intro: a brand diamond assembles centre-screen */
html.bs-cover-intro::after{ content:""; position:fixed; z-index:9999; left:50%; top:50%; width:78px; height:78px; margin:-39px;
  background:var(--mark) center/contain no-repeat; filter:brightness(0) invert(1) drop-shadow(0 16px 40px rgba(0,0,0,.35));
  animation:bs-intro-dia 1.15s cubic-bezier(.22,.61,.36,1) both; }
@keyframes bs-intro-dia{ 0%{opacity:0;transform:rotate(-45deg) scale(.25);} 45%{opacity:1;transform:rotate(0) scale(1);}
  72%{transform:rotate(0) scale(1);} 100%{opacity:.92;transform:scale(1.06);} }
/* exit: slide the cover UP into view before navigating away */
html.bs-cover-in::before{ animation:bs-cover-in .38s cubic-bezier(.76,0,.24,1) both; }
@keyframes bs-cover-in{ from{transform:translateY(101%);} to{transform:translateY(0);} }
/* lift out (intro + nav enter) */
html.bs-cover-out::before{ transform:translateY(-101%); transition:transform var(--dur-base) var(--ease); }
html.bs-cover-out::after{ opacity:0; transform:scale(.6); transition:opacity var(--dur-base),transform var(--dur-base); }
@media (prefers-reduced-motion:reduce){
  html.bs-cover{ overflow:visible!important; }
  html.bs-cover::before,html.bs-cover-intro::after{ display:none!important; }
}

/* ============================================================
   PARTNER LOGO WALL (page-partners) — grouped tiers + placeholder slots
   ============================================================ */
.prt-group{ margin-top:34px; }
.prt-tier{ display:flex; align-items:center; gap:var(--sp-8); margin:0 0 16px; font:600 12.5px/1 var(--f-mono); letter-spacing:.14em; text-transform:uppercase; color:var(--muted); }
.prt-tier-dia{ width:9px; height:9px; flex:0 0 auto; background:var(--dia); clip-path:polygon(50% 0,100% 50%,50% 100%,0 50%); }
.prt-logos{ display:grid; grid-template-columns:repeat(auto-fill,minmax(190px,1fr)); gap:var(--sp-16); }
.prt-logo{ display:flex; align-items:center; justify-content:center; height:104px; padding:20px 24px; background:var(--card);
  border:1px solid var(--card-line); border-radius:var(--radius-14); text-decoration:none;
  transition:transform var(--dur-base) var(--ease),box-shadow var(--dur-base) var(--ease),border-color var(--dur-base); }
.prt-logo img{ max-height:52px; max-width:100%; width:auto; object-fit:contain; filter:grayscale(1); opacity:.72; transition:filter var(--dur-base),opacity var(--dur-base); }
a.prt-logo:hover{ transform:translateY(-4px); border-color:var(--blue); box-shadow:0 20px 44px -26px rgba(var(--blue-rgb),.6); }
a.prt-logo:hover img{ filter:grayscale(0); opacity:1; }
.prt-logo.is-empty{ border-style:dashed; border-color:var(--card-line-hi); background:linear-gradient(180deg,#FFFFFF,#F6F9FD); }
.prt-ph{ display:flex; flex-direction:column; align-items:center; gap:var(--sp-8); }
.prt-ph i{ width:26px; height:26px; opacity:.4; background:var(--mark) center/contain no-repeat; }
.prt-ph em{ font-style:normal; font:600 12px/1.25 var(--f-mono); letter-spacing:.05em; text-align:center; color:var(--muted); }
@media (max-width:600px){ .prt-logos{ grid-template-columns:repeat(auto-fill,minmax(140px,1fr)); } .prt-logo{ height:88px; padding:16px; } }

/* ============ premium polish layer: motion tokens · atmosphere · cursor · loader ============ */
/* The rest of the motion vocabulary. Three curves and three durations, which is the size
   Accenture's system runs at: 550ms covers 47% of their durations and one curve covers 58% of
   their easings, and the generative rule behind the small set is that DURATION FOLLOWS
   DISTANCE, not importance — base for anything moving a few pixels or only changing colour,
   double it when the same element travels a card-height, and the page-scale figure only for
   viewport-width movement.

   --ease-out is no longer an ease-out. It is now their gentler cubic-bezier(.5,0,.35,1), the
   third curve in their set, and it is kept for pure cross-fades — opacity with no travel,
   where the house curve's violent middle has nothing to describe.

   --ease-spring kept its name and lost its overshoot: it was cubic-bezier(.16,1.08,.3,1), one
   of four springs in this file. Not one of Accenture's 450 easing values overshoots at all.
   Bounce is the difference between a consulting firm and a product launch page, and the name
   is retained only so the 15 call sites do not have to be rewritten.

   --dur-fast/-base/-slow were already declared here and used exactly zero times. They are
   wired up below. */
:root{
  --ease-out:cubic-bezier(.5,0,.35,1);
  --ease-spring:cubic-bezier(.85,0,0,1);
  --dur-fast:.2s;
  --dur-base:.55s;
  --dur-slow:1.1s;
  --stagger:60ms;
}

/* film grain + slow drifting light-leak — site-wide, very subtle, non-interactive */
.fx-atmos{position:fixed;inset:0;z-index:9990;pointer-events:none;overflow:hidden;}
.fx-atmos-grain{position:absolute;inset:-60%;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");opacity:.035;mix-blend-mode:overlay;}
.fx-atmos-leak{position:absolute;width:70%;height:70%;left:-12%;top:-16%;border-radius:50%;filter:blur(64px);opacity:.14;mix-blend-mode:screen;background:radial-gradient(circle,rgba(var(--blue-rgb),.55),transparent 62%);animation:fxLeak 28s ease-in-out infinite;}
@keyframes fxGrain{0%{transform:translate(0,0)}33%{transform:translate(-4%,3%)}66%{transform:translate(3%,-3%)}100%{transform:translate(0,0)}}
@keyframes fxLeak{0%,100%{transform:translate(0,0) scale(1)}50%{transform:translate(42vw,32vh) scale(1.25)}}
@media (prefers-reduced-motion:reduce){.fx-atmos-grain,.fx-atmos-leak{animation:none;}.fx-atmos-grain{opacity:.022;}}

/* custom cursor ring (desktop only; native cursor kept) */

/* richer intro loader — an accent ring pulses out while the brand diamond assembles */
html.bs-cover-intro::after{ animation:bs-intro-dia 1.15s cubic-bezier(.22,.61,.36,1) both, bs-intro-ring 1.9s ease-out .3s infinite; }
@keyframes bs-intro-ring{ 0%{box-shadow:0 0 0 4px rgba(var(--blue-rgb),.4);} 72%{box-shadow:0 0 0 52px rgba(var(--blue-rgb),0);} 100%{box-shadow:0 0 0 52px rgba(var(--blue-rgb),0);} }

/* ============ How we deliver — scroll-driven journey ============ */
.ah-journey{position:relative;padding:96px 0 104px;background:linear-gradient(180deg,#ffffff 0%,#FCFDFE 100%);}
.ah-journey-in{display:grid;grid-template-columns:.92fr 1.08fr;gap:var(--sp-64);align-items:start;}
.ah-journey-head{position:sticky;top:calc(var(--header-h) + 42px);}
.ah-journey-h2{font:700 clamp(26px,3vw,39px)/1.06 var(--f-display);letter-spacing:-.022em;color:var(--ink);margin:14px 0 0;}
.ah-journey-intro{margin:20px 0 0;max-width:40ch;font:500 16.5px/1.6 var(--f-body);color:var(--text-2);}
.ah-journey-steps{position:relative;list-style:none;margin:0;padding:6px 0;}
.ah-journey-line{position:absolute;left:22px;top:26px;bottom:26px;width:2px;background:rgba(var(--blue-rgb),.13);border-radius:var(--radius-4);overflow:hidden;}
.ah-journey-fill{position:absolute;left:0;top:0;width:100%;height:0;background:linear-gradient(180deg,var(--blue) 0%,var(--aux-purple) 50%,#C81BC0 100%);box-shadow:0 0 12px rgba(var(--blue-rgb),.4);border-radius:var(--radius-4);}
.ah-jstep{position:relative;display:flex;gap:var(--sp-24);padding-bottom:48px;}
.ah-jstep:last-child{padding-bottom:0;}
.ah-jstep{--jacc:var(--blue);}
.ah-jstep:nth-of-type(1){--jacc:var(--blue);}
.ah-jstep:nth-of-type(2){--jacc:var(--aux-purple);}
.ah-jstep:nth-of-type(3){--jacc:#C81BC0;}
.ah-jstep:nth-of-type(4){--jacc:var(--blue);}
.ah-jnode{position:relative;z-index:1;flex:0 0 auto;width:46px;height:46px;border-radius:50%;display:grid;place-items:center;font:700 15px/1 var(--f-mono);color:var(--jacc);background:#fff;border:2px solid color-mix(in srgb,var(--jacc) 26%,#E5EAF1);box-shadow:0 6px 20px -10px color-mix(in srgb,var(--jacc) 45%,transparent);transition:transform var(--dur-base) var(--ease-spring),background var(--dur-base),color var(--dur-base),border-color var(--dur-base),box-shadow var(--dur-base);}
.ah-jstep.active .ah-jnode{color:#fff;background:var(--jacc);border-color:transparent;box-shadow:0 12px 28px -8px color-mix(in srgb,var(--jacc) 70%,transparent);transform:scale(1.07);}
.ah-jstep.active .ah-jbody{opacity:1;transform:none;}
@media (max-width:860px){.ah-journey-in{grid-template-columns:1fr;gap:var(--sp-32);}.ah-journey-head{position:static;}}

/* ============ Trusted-by logo wall (marquee) ============ */
@keyframes ahLogoScroll{from{transform:translateX(0)}to{transform:translateX(-50%)}}
@media (prefers-reduced-motion:reduce){.ah-logos-track{animation:none;}}

/* ============ full-screen mega dropdown (large, immersive) ============ */
.mega{top:var(--header-h);bottom:0;height:auto;box-shadow:none;}
/* Was justify-content:center. The panel is full height and its four column blocks are not
     the same height — 9 links against 3 — so centring the stack left every title a different
     distance from the top: 248, 265, 275, 296. The heading is the first thing the eye lands
     on when a panel opens, and having it move between menus is the sort of thing you feel
     before you can name it.

     Top-aligned fixes that, but flush against a 60px inset it also left the content sitting
     high in a full-height panel with 300px of nothing under it. So the inset takes half the
     slack back: 100vh minus the header minus 514px — the tallest of the four content stacks,
     the eleven-link one — halved. That centres the panel that fills the most and leaves the
     shorter ones a little high, which is the right way round; centring each one separately is
     what moved the titles in the first place. A single inset shifts all four equally, so they
     still start on the same line.

     514 is measured, not guessed, and it is why the figure is hard-coded: CSS cannot size a
     box against its own tallest sibling. If a menu grows a column, re-measure it. Below 780px
     of viewport the tallest stack no longer fits at any inset, and the rule further down
     takes over with a small one and a scrollbar. */
  .mega-in{max-width:var(--maxw);height:100%;padding:clamp(60px,calc((100vh - 100px - 514px) / 2),190px) var(--pad) 60px;display:flex;flex-direction:column;justify-content:flex-start;gap:clamp(30px,5vh,54px);position:relative;}
/* oversized ghosted brand mark, bottom-right, for depth */
/* Client feedback: too many logo watermarks. The oversized ghosted mark in each of the
   four mega-menu panels collided with the header logo and the chat button — removed. */
.mega-head .mt{font:800 clamp(40px,5.2vw,76px)/1 var(--f-display);letter-spacing:-.03em;gap:var(--sp-20);margin:0 0 18px;}

.mega-head .tg{font-size:17.5px;line-height:1.55;max-width:54ch;margin:0 0 20px;}
.mega-head .all{font-size:15px;}
.mega-cols{gap:clamp(48px,7vw,120px);align-items:flex-start;}
.mega-col h5{font-size:12.5px;letter-spacing:.16em;margin:0 0 26px;}
.mega-col a{font-size:clamp(20px,1.9vw,27px);padding:12px 0 12px 28px;white-space:nowrap;}
.mega-col.grid{width:clamp(580px,54vw,760px);min-width:0;}
.mega-col.grid a{font-size:clamp(18px,1.45vw,23px);}
.mega-col a::before{width:9px;height:9px;margin-top:-4.5px;}
.mega-col a::after{font-size:.78em;margin-left:10px;}
.mega-col a:hover::after{margin-left:14px;}
@media (max-height:780px){ .mega-in{justify-content:flex-start;padding-top:46px;overflow-y:auto;} .mega-head .mt{font-size:clamp(34px,4.4vw,52px);} .mega-col a{font-size:20px;} }
@media (min-width:721px) and (max-width:1200px){
  .mobile-menu{display:block;position:fixed;inset:var(--header-h) 0 0;background:#fff;z-index:320;padding:24px var(--pad);transform:translateX(100%);transition:transform var(--dur-base) var(--ease);overflow-y:auto;}
  .mobile-menu.open{transform:none;}
  .mobile-menu :is(a,button.m-link){display:block;padding:16px 0;font:600 20px/1 var(--f-display);color:var(--ink);border-bottom:1px solid var(--line);}
  .mobile-menu .m-sub{padding:11px 0 11px 16px;font:500 15px/1 var(--f-body);color:var(--muted);}
}

/* =====================================================================
   HOMEPAGE MOTION V1 — section-to-section choreography
   Scoped by body.home.motion-v1 so the complete pass can be removed cleanly.
   ===================================================================== */

/* Insights: one intentional travelling wave instead of unrelated card cycles. */
.home.motion-v1 .ah-news2-track .ah-tile{
  animation-duration:6.8s;
  animation-timing-function:cubic-bezier(.45,0,.55,1);
}
.home.motion-v1 .ah-news2-track .ah-tile:nth-child(8n+1){animation-delay:0s;}
.home.motion-v1 .ah-news2-track .ah-tile:nth-child(8n+2){animation-delay:-.85s;}
.home.motion-v1 .ah-news2-track .ah-tile:nth-child(8n+3){animation-delay:-1.7s;}
.home.motion-v1 .ah-news2-track .ah-tile:nth-child(8n+4){animation-delay:-2.55s;}
.home.motion-v1 .ah-news2-track .ah-tile:nth-child(8n+5){animation-delay:-3.4s;}
.home.motion-v1 .ah-news2-track .ah-tile:nth-child(8n+6){animation-delay:-4.25s;}
.home.motion-v1 .ah-news2-track .ah-tile:nth-child(8n+7){animation-delay:-5.1s;}
.home.motion-v1 .ah-news2-track .ah-tile:nth-child(8n+8){animation-delay:-5.95s;}

/* Capabilities: shell assembles first; icon and copy resolve in subsequent beats. */
.home.motion-v1 .ah-caps2-grid.c2-motion-armed .ah-cap2{
  /* 16px and blur(4px) are the Innovation Lab's numbers. Nothing scales: a card that
     grows into place has no midpoint that looks right. */
  opacity:0;translate:0 16px;filter:blur(4px);transform:none;pointer-events:none;
  transition:opacity var(--dur-base) var(--ease) var(--c2-delay,0ms),
    translate var(--dur-slow) var(--ease-spring) var(--c2-delay,0ms),
    filter var(--dur-base) var(--ease) var(--c2-delay,0ms),
    transform var(--dur-base) var(--ease-out) 0s,
    border-color var(--dur-base) 0s,
    box-shadow var(--dur-base) 0s;
}
.home.motion-v1 .ah-caps2-grid.c2-motion-armed .ah-cap2.c2-motion-in{
  opacity:1;translate:0 0;filter:blur(0);pointer-events:auto;
}
.home.motion-v1 .c2-motion-armed .ah-cap2 .ah-cap2-ic{
  opacity:0;scale:.35;rotate:-30deg;
  transition:opacity var(--dur-base) var(--ease) calc(var(--c2-delay,0ms) + 250ms),
    scale var(--dur-base) var(--ease) calc(var(--c2-delay,0ms) + 250ms),
    rotate var(--dur-base) var(--ease) calc(var(--c2-delay,0ms) + 250ms);
}
.home.motion-v1 .c2-motion-armed .ah-cap2.c2-motion-in .ah-cap2-ic{opacity:1;scale:1;rotate:0deg;}
.home.motion-v1 .c2-motion-armed .ah-cap2 h3,
.home.motion-v1 .c2-motion-armed .ah-cap2 p,
.home.motion-v1 .c2-motion-armed .ah-cap2 .ah-cap2-go{
  opacity:0;translate:0 34px;
  transition:opacity var(--dur-base) var(--ease),translate var(--dur-base) var(--ease-out),transform var(--dur-base) var(--ease-out);
}
.home.motion-v1 .c2-motion-armed .ah-cap2 h3{transition-delay:calc(var(--c2-delay,0ms) + 330ms);}
.home.motion-v1 .c2-motion-armed .ah-cap2 p{transition-delay:calc(var(--c2-delay,0ms) + 400ms);}
.home.motion-v1 .c2-motion-armed .ah-cap2 .ah-cap2-go{transition-delay:calc(var(--c2-delay,0ms) + 470ms);}
.home.motion-v1 .c2-motion-armed .ah-cap2.c2-motion-in h3,
.home.motion-v1 .c2-motion-armed .ah-cap2.c2-motion-in p,
.home.motion-v1 .c2-motion-armed .ah-cap2.c2-motion-in .ah-cap2-go{opacity:1;translate:0 0;}
.home.motion-v1 .c2-motion-armed .ah-cap2.c2-motion-in .ah-cap2-ic img{
  animation:c2MotionFloat 5.8s ease-in-out calc(var(--c2-phase,0s) + 1.2s) infinite;
}
@keyframes c2MotionFloat{0%,100%{translate:0 0}50%{translate:0 -6px}}

/* Partners: the heading hands off to a centre-opening logo mask, then chips ripple in. */
.home.motion-v1 .ah-cp.cp-motion-armed .ah-cp-head{
  opacity:0;translate:0 32px;filter:blur(7px);
  transition:opacity var(--dur-base) var(--ease),translate var(--dur-base) var(--ease-out),filter var(--dur-base) var(--ease);
}
.home.motion-v1 .ah-cp.cp-motion-armed .ah-cp-group{
  opacity:0;translate:0 26px;
  transition:opacity var(--dur-base) var(--ease),translate var(--dur-slow) var(--ease-out);
}
.home.motion-v1 .ah-cp.cp-motion-armed .ah-cp-group:nth-child(2){transition-delay:.16s;}
.home.motion-v1 .ah-cp.cp-motion-armed.cp-motion-in .ah-cp-head,
.home.motion-v1 .ah-cp.cp-motion-armed.cp-motion-in .ah-cp-group{opacity:1;translate:0 0;filter:blur(0);}
.home.motion-v1 .ah-cp.cp-motion-armed .ah-cp-marquee{
  opacity:0;clip-path:inset(0 50% 0 50%);
  transition:clip-path var(--dur-slow) var(--ease-spring) .2s,opacity var(--dur-base) var(--ease) .2s;
}
.home.motion-v1 .ah-cp.cp-motion-armed.cp-motion-in .ah-cp-marquee{opacity:1;clip-path:inset(0 0 0 0);}
.home.motion-v1 .ah-cp.cp-motion-armed .ah-cp-track{animation-play-state:paused;}
.home.motion-v1 .ah-cp.cp-motion-armed.cp-motion-in .ah-cp-marquee:not(:hover) .ah-cp-track{animation-play-state:running;}
.home.motion-v1 .ah-cp.cp-motion-armed .ah-cp-logo{
  opacity:0;translate:0 20px;scale:.88;
  transition:opacity var(--dur-base) var(--ease) var(--cp-chip-delay,0ms),
    translate var(--dur-base) var(--ease-spring) var(--cp-chip-delay,0ms),
    scale var(--dur-base) var(--ease-spring) var(--cp-chip-delay,0ms),
    color var(--dur-base) 0s,border-color var(--dur-base) 0s,transform var(--dur-base) var(--ease-out) 0s,box-shadow var(--dur-base) 0s;
}
.home.motion-v1 .ah-cp.cp-motion-armed.cp-motion-in .ah-cp-logo{opacity:1;translate:0 0;scale:1;}

/* Partners → Contact: a signal draws down and arrives before the card opens. */
.home.motion-v1 .ah-cp{overflow:visible;z-index:2;}
.home.motion-v1 .ah-flow-bridge{
  position:absolute;left:50%;top:calc(100% - 8px);width:72px;height:76px;z-index:6;
  transform:translateX(-50%);pointer-events:none;opacity:0;
}
.home.motion-v1 .ah-flow-bridge::before{
  content:"";position:absolute;left:50%;top:0;width:2px;height:68px;transform:translateX(-50%) scaleY(0);
  transform-origin:top;background:linear-gradient(180deg,rgba(var(--blue-rgb),0),var(--blue) 30%,var(--aux-purple) 72%,#C81BC0);
  box-shadow:0 0 14px rgba(var(--blue-rgb),.48);
}
.home.motion-v1 .ah-flow-bridge::after{
  content:"";position:absolute;left:50%;top:0;width:13px;height:13px;opacity:0;
  background:linear-gradient(145deg,var(--blue),#C81BC0);
  clip-path:polygon(50% 0,100% 50%,50% 100%,0 50%);
  transform:translate(-50%,0) rotate(45deg);
}
.home.motion-v1 .ah-flow-bridge i{
  position:absolute;left:50%;bottom:0;width:12px;height:12px;border-radius:50%;opacity:0;
  border:2px solid rgba(65,42,152,.65);transform:translate(-50%,-50%) scale(.4);
}
.home.motion-v1 .ah-flow-bridge.flow-go{opacity:1;}
.home.motion-v1 .ah-flow-bridge.flow-go::before{animation:mv1LineFlow 1.75s var(--ease-out) both;}
.home.motion-v1 .ah-flow-bridge.flow-go::after{animation:mv1SignalTravel .68s cubic-bezier(.34,.05,.22,1) .05s both;}
.home.motion-v1 .ah-flow-bridge.flow-go i{animation:mv1SignalPing .7s ease-out .62s both;}
/* The connector between the partners band and the contact card is a piece of scaffolding:
   it exists to carry the signal down into the card, which then swings open. The diamond and
   the ping already clear themselves; the line did not — mv1LineDraw ended on scaleY(1) with
   a `both` fill, so it held that frame for the life of the page and what was left, long
   after the gesture was over, was a 3px stick floating in the white gap between two
   sections with nothing above or below it.

   So the line now completes its own gesture. It draws from the top, holds while the signal
   lands and the card opens, then retracts from the BOTTOM — withdrawing in the direction
   the signal went, rather than rewinding back up the way it came. The pivot migrates from
   top to bottom across the hold, which is free: scaleY is 1 for that whole stretch, and at
   scale 1 the origin has no visual effect. */
@keyframes mv1LineFlow{
  0%  {transform-origin:top;   transform:translateX(-50%) scaleY(0);opacity:1}
  35% {transform-origin:top;   transform:translateX(-50%) scaleY(1);opacity:1}
  78% {transform-origin:bottom;transform:translateX(-50%) scaleY(1);opacity:1}
  100%{transform-origin:bottom;transform:translateX(-50%) scaleY(0);opacity:0}
}
@keyframes mv1SignalTravel{
  0%{opacity:0;transform:translate(-50%,0) rotate(45deg) scale(.5)}
  12%{opacity:1}
  82%{opacity:1}
  100%{opacity:0;transform:translate(-50%,62px) rotate(225deg) scale(1.15)}
}
@keyframes mv1SignalPing{
  0%{opacity:.9;transform:translate(-50%,-50%) scale(.35)}
  100%{opacity:0;transform:translate(-50%,-50%) scale(4.5)}
}

@media (max-width:600px){
  .home.motion-v1 .ah-caps2-grid.c2-motion-armed .ah-cap2{translate:0 12px;}
  .home.motion-v1 .ah-flow-bridge{height:68px;}
}
@media (prefers-reduced-motion:reduce){
  .home.motion-v1 .ah-caps2-grid.c2-motion-armed .ah-cap2,
  .home.motion-v1 .c2-motion-armed .ah-cap2 .ah-cap2-ic,
  .home.motion-v1 .c2-motion-armed .ah-cap2 h3,
  .home.motion-v1 .c2-motion-armed .ah-cap2 p,
  .home.motion-v1 .c2-motion-armed .ah-cap2 .ah-cap2-go,
  .home.motion-v1 .ah-cp.cp-motion-armed .ah-cp-head,
  .home.motion-v1 .ah-cp.cp-motion-armed .ah-cp-group,
  .home.motion-v1 .ah-cp.cp-motion-armed .ah-cp-marquee,
  .home.motion-v1 .ah-cp.cp-motion-armed .ah-cp-logo{
    opacity:1!important;translate:none!important;scale:1!important;rotate:none!important;filter:none!important;
    clip-path:none!important;animation:none!important;transition:none!important;
  }
  .home.motion-v1 .ah-flow-bridge{display:none!important;}
}

/* =====================================================================
   MOTION V1.1 — stronger presentation pass
   Makes each section change unmistakable while keeping the same content.
   ===================================================================== */

/* Insights enters as one deep stage, then resolves into the travelling wave. */
.home.motion-v1 .ah-news2.news-motion-armed .ah-news2-head{
  opacity:0;translate:0 54px;scale:.94;filter:blur(12px);
  transition:opacity var(--dur-base) var(--ease),translate var(--dur-slow) var(--ease-spring),scale var(--dur-slow) var(--ease-spring),filter var(--dur-base) var(--ease);
}

.home.motion-v1 .ah-news2.news-motion-armed .ah-news2-track{
  opacity:0;translate:0 16px;filter:blur(4px);
  transition:opacity var(--dur-base) var(--ease) .18s,translate var(--dur-slow) var(--ease-out) .18s,filter var(--dur-base) var(--ease) .18s;
}
.home.motion-v1 .ah-news2.news-motion-armed.news-motion-in .ah-news2-head{opacity:1;translate:0 0;scale:1;filter:blur(0);}

.home.motion-v1 .ah-news2.news-motion-armed.news-motion-in .ah-news2-track{
  opacity:1;translate:0 0;filter:blur(0);
}
.home.motion-v1 .ah-news2.news-motion-armed::after{
  content:"";position:absolute;inset:0;z-index:0;pointer-events:none;opacity:0;
  background:linear-gradient(108deg,transparent 20%,rgba(var(--white-rgb),.88) 43%,rgba(var(--blue-rgb),.16) 50%,transparent 67%);
  transform:translateX(-120%) skewX(-12deg);
}
.home.motion-v1 .ah-news2.news-motion-armed.news-motion-in::after{animation:mv11NewsSweep 1.55s var(--ease-out) .15s both;}
@keyframes mv11NewsSweep{
  0%{opacity:0;transform:translateX(-120%) skewX(-12deg)}
  18%{opacity:.78}
  82%{opacity:.42}
  100%{opacity:0;transform:translateX(120%) skewX(-12deg)}
}

/* The capability cards used to arrive as 3D panels: 110px back, 190px deep, tilted 34
   degrees under two stacked perspectives, at 72% scale behind blur(16px) and saturate(.55),
   with fx.js adding another ±92px sideways and 20 degrees of yaw per card. The end state
   was fine; the middle of it was not — scroll-linked, the second row sits mid-flight for as
   long as it takes to scroll past, and a half-scaled, half-desaturated card reads as a
   rendering fault rather than as motion. Removed, which hands the section back to the
   milder rule further up this file (:2506) that this block had been overriding all along. */
.home.motion-v1 .c2-motion-armed .ah-cap2 .ah-cap2-ic{
  position:relative;opacity:0;scale:.18;rotate:-58deg;filter:brightness(1.8) blur(6px);
  transition:opacity var(--dur-base) var(--ease) .2s,scale var(--dur-base) var(--ease) var(--dur-fast),
    rotate var(--dur-base) var(--ease) var(--dur-fast),filter var(--dur-base) var(--ease) .2s;
}
.home.motion-v1 .c2-motion-armed .ah-cap2.c2-motion-in .ah-cap2-ic{
  opacity:1;scale:1;rotate:0deg;filter:brightness(1) blur(0);
}
.home.motion-v1 .c2-motion-armed .ah-cap2 .ah-cap2-ic::before{
  content:"";position:absolute;inset:8px;border-radius:50%;opacity:0;scale:.3;
  border:2px solid color-mix(in srgb,var(--acc) 72%,white);
  box-shadow:0 0 0 0 color-mix(in srgb,var(--acc) 44%,transparent),0 0 34px color-mix(in srgb,var(--acc) 55%,transparent);
  pointer-events:none;
}
.home.motion-v1 .c2-motion-armed .ah-cap2.c2-motion-in .ah-cap2-ic::before{
  animation:mv11EnergyRing 1.05s ease-out .28s both;
}
@keyframes mv11EnergyRing{
  0%{opacity:0;scale:.28;box-shadow:0 0 0 0 color-mix(in srgb,var(--acc) 50%,transparent)}
  24%{opacity:1}
  100%{opacity:0;scale:1.55;box-shadow:0 0 0 22px transparent}
}
.home.motion-v1 .c2-motion-armed .ah-cap2 h3,
.home.motion-v1 .c2-motion-armed .ah-cap2 p,
.home.motion-v1 .c2-motion-armed .ah-cap2 .ah-cap2-go{
  opacity:0;translate:-28px 0;filter:blur(7px);
  transition:opacity var(--dur-base) var(--ease),translate var(--dur-base) var(--ease-spring),filter var(--dur-base) var(--ease),transform var(--dur-base) var(--ease-out);
}
.home.motion-v1 .c2-motion-armed .ah-cap2 h3{transition-delay:.28s;}
.home.motion-v1 .c2-motion-armed .ah-cap2 p{transition-delay:.38s;}
.home.motion-v1 .c2-motion-armed .ah-cap2 .ah-cap2-go{transition-delay:.48s;}
.home.motion-v1 .c2-motion-armed .ah-cap2.c2-motion-in h3,
.home.motion-v1 .c2-motion-armed .ah-cap2.c2-motion-in p,
.home.motion-v1 .c2-motion-armed .ah-cap2.c2-motion-in .ah-cap2-go{opacity:1;translate:0 0;filter:blur(0);}

/* Partners unfolds in perspective and receives a bright scanner pass. */
.home.motion-v1 .ah-cp.cp-motion-armed .ah-cp-head{translate:0 58px;scale:.9;filter:blur(13px);}
.home.motion-v1 .ah-cp.cp-motion-armed .ah-cp-group{translate:0 48px;scale:.94;filter:blur(9px);}
.home.motion-v1 .ah-cp.cp-motion-armed.cp-motion-in .ah-cp-head,
.home.motion-v1 .ah-cp.cp-motion-armed.cp-motion-in .ah-cp-group{translate:0 0;scale:1;filter:blur(0);}
.home.motion-v1 .ah-cp.cp-motion-armed .ah-cp-marquee{
  transform-origin:50% 50%;transform:perspective(900px) rotateX(34deg) scale(.76);
  filter:blur(12px) saturate(.55);
  transition:clip-path var(--dur-slow) var(--ease-spring) .16s,opacity var(--dur-base) var(--ease) .16s,
    transform var(--dur-slow) var(--ease-spring) .16s,filter var(--dur-base) var(--ease) .16s;
}
.home.motion-v1 .ah-cp.cp-motion-armed.cp-motion-in .ah-cp-marquee{
  transform:perspective(900px) rotateX(0deg) scale(1);filter:blur(0) saturate(1);
}
.home.motion-v1 .ah-cp.cp-motion-armed .ah-cp-marquee::after{
  content:"";position:absolute;top:-30%;bottom:-30%;left:-35%;width:24%;z-index:4;pointer-events:none;opacity:0;
  background:linear-gradient(90deg,transparent,rgba(var(--white-rgb),.92),rgba(var(--blue-rgb),.3),transparent);
  transform:skewX(-16deg);
}
.home.motion-v1 .ah-cp.cp-motion-armed.cp-motion-in .ah-cp-marquee::after{animation:mv11PartnerScan 1.25s var(--ease-out) .55s both;}
@keyframes mv11PartnerScan{
  0%{left:-35%;opacity:0}
  18%{opacity:.9}
  78%{opacity:.55}
  100%{left:120%;opacity:0}
}
.home.motion-v1 .ah-cp.cp-motion-armed .ah-cp-logo{
  opacity:0;translate:0 34px;scale:.72;rotate:x -72deg;transform-origin:50% 100%;
  transition:opacity var(--dur-base) var(--ease) var(--cp-chip-delay,0ms),
    translate var(--dur-base) var(--ease-spring) var(--cp-chip-delay,0ms),
    scale var(--dur-base) var(--ease-spring) var(--cp-chip-delay,0ms),
    rotate var(--dur-base) var(--ease-spring) var(--cp-chip-delay,0ms),
    color var(--dur-base),border-color var(--dur-base),transform var(--dur-base) var(--ease-out),box-shadow var(--dur-base);
}
.home.motion-v1 .ah-cp.cp-motion-armed.cp-motion-in .ah-cp-logo{opacity:1;translate:0 0;scale:1;rotate:x 0deg;}

/* A brighter signal hands off at the Contact edge, then passes behind the card. */
.home.motion-v1 .ah-contact{position:relative;z-index:3;}
.home.motion-v1 .ah-contact-card{position:relative;z-index:2;}
.home.motion-v1 .ah-flow-bridge{width:92px;height:56px;top:calc(100% - 12px);z-index:1;}
.home.motion-v1 .ah-flow-bridge::before{
  width:3px;height:48px;
  background:linear-gradient(180deg,rgba(var(--blue-rgb),0),#20D9F1 20%,var(--blue) 45%,#7B45D6 73%,#F04AE8);
  box-shadow:0 0 8px #20D9F1,0 0 24px rgba(65,42,152,.7);
}
.home.motion-v1 .ah-flow-bridge::after{width:18px;height:18px;filter:drop-shadow(0 0 12px rgba(200,27,192,.9));}
.home.motion-v1 .ah-flow-bridge i{width:17px;height:17px;border-width:3px;}
/* Kept in step with the desktop timing: the line has to stay up long enough for the
     signal to land and the card to open before it retracts. */
  .home.motion-v1 .ah-flow-bridge.flow-go::before{animation-duration:1.75s;}
.home.motion-v1 .ah-flow-bridge.flow-go::after{animation-duration:.68s;}
@keyframes mv1SignalTravel{
  0%{opacity:0;transform:translate(-50%,0) rotate(45deg) scale(.4)}
  10%{opacity:1}
  84%{opacity:1}
  100%{opacity:0;transform:translate(-50%,44px) rotate(315deg) scale(1.25)}
}

@media (max-width:600px){
  .home.motion-v1 .ah-flow-bridge{height:56px;}
}
@media (prefers-reduced-motion:reduce){
  .home.motion-v1 .ah-news2.news-motion-armed .ah-news2-head,
  .home.motion-v1 .ah-news2.news-motion-armed .ah-news2-track,
  .home.motion-v1 .ah-caps2-grid.c2-motion-armed .ah-cap2,
  .home.motion-v1 .c2-motion-armed .ah-cap2 .ah-cap2-ic,
  .home.motion-v1 .c2-motion-armed .ah-cap2 h3,
  .home.motion-v1 .c2-motion-armed .ah-cap2 p,
  .home.motion-v1 .c2-motion-armed .ah-cap2 .ah-cap2-go,
  .home.motion-v1 .ah-cp.cp-motion-armed .ah-cp-head,
  .home.motion-v1 .ah-cp.cp-motion-armed .ah-cp-group,
  .home.motion-v1 .ah-cp.cp-motion-armed .ah-cp-marquee,
  .home.motion-v1 .ah-cp.cp-motion-armed .ah-cp-logo{
    opacity:1!important;translate:none!important;scale:1!important;rotate:none!important;transform:none!important;
    filter:none!important;animation:none!important;transition:none!important;
  }
}

/* =====================================================================
   INTERIOR DESIGN V2 — homepage-aligned system for every client page
   Neutral-first surfaces, pale network fields, generous rhythm and one
   shared reveal language. Scoped so the approved homepage is untouched.
   ===================================================================== */
.interior-v2{
  --iv-ink:#16283f;
  --iv-paper:#fff;
  --iv-soft:#f4f8fb;
  --iv-line:rgba(22,40,63,.10);
  --iv-shadow:0 28px 70px -48px rgba(22,40,63,.46);
  background:var(--iv-paper);
}

/* Light heroes inherit the homepage's white → atmospheric transition. */

.interior-v2 .page-hero::before{
  content:"";position:absolute;inset:0;z-index:0;pointer-events:none;
  background-image:
    linear-gradient(rgba(var(--blue-rgb),.055) 1px,transparent 1px),
    linear-gradient(90deg,rgba(var(--blue-rgb),.055) 1px,transparent 1px);
  background-size:72px 72px;
  -webkit-mask-image:linear-gradient(90deg,transparent 2%,#000 30%,#000 72%,transparent 98%);
          mask-image:linear-gradient(90deg,transparent 2%,#000 30%,#000 72%,transparent 98%);
}
.interior-v2 .page-hero .container{width:100%;}
.interior-v2 .page-hero .h1,
.interior-v2 .hero-image .h1,
.interior-v2 .cr-hero .h1{
  font-size:clamp(44px,6.3vw,82px);
  line-height:.98;letter-spacing:-.045em;
  max-width:1040px;
}
.interior-v2 .page-hero .lead,
.interior-v2 .hero-image .lead,
.interior-v2 .cr-hero .lead{
  font-size:clamp(17px,1.5vw,21px);
  line-height:1.58;
}
.interior-v2 .page-hero .eyebrow{color:#007e9e;}

/* Dark/media heroes use the same depth and scale as the homepage feature bands. */

.interior-v2 .hero-image .container{
  width:100%;padding-top:clamp(96px,11vw,150px);padding-bottom:clamp(76px,9vw,118px);
}
.interior-v2 .hero-image .bg::after{
  background:
    linear-gradient(90deg,rgba(4,18,36,.93) 0%,rgba(10,28,48,.68) 54%,rgba(8,28,46,.30) 100%),
    radial-gradient(58% 88% at 88% 30%,rgba(var(--blue-rgb),.24),transparent 72%);
}

/* The first-generation careers grid stood here: a 72px lattice in rgba(var(--white-rgb),.045),
   written when this hero's ground was solid var(--blue). It has been fully superseded since the
   ground went light — the live rule further down sets `background` shorthand, which resets
   background-image, so this one contributed nothing to the computed style. Deleted rather
   than left as a third copy of one selector; two were already one too many. */

/* Consistent section rhythm and alternating full-width fields. */
/* One rhythm for the whole page. The first content section used to open on 126px
   while every section after it used 94px, so the page started on a beat it never
   returned to. Both now share the same scale; .section keeps a slightly deeper
   bottom because it is the one that carries the heaviest block. */
.interior-v2 .section{padding-top:clamp(64px,7vw,94px);padding-bottom:clamp(60px,6.4vw,88px);}
.interior-v2 .section-tight{padding-top:clamp(64px,7vw,94px);padding-bottom:clamp(54px,6vw,80px);}

.interior-v2 .iv-section{position:relative;isolation:isolate;}
.interior-v2 .iv-section.iv-tone::before{
  content:"";position:absolute;z-index:-1;top:0;bottom:0;left:50%;width:100vw;transform:translateX(-50%);
  background:
    radial-gradient(48% 72% at 96% 18%,rgba(var(--blue-rgb),.07),transparent 70%),
    radial-gradient(40% 62% at 3% 90%,rgba(65,42,152,.045),transparent 72%),
    linear-gradient(180deg,#f8fafc,#f2f7fa);
  border-top:1px solid rgba(22,40,63,.05);
  border-bottom:1px solid rgba(22,40,63,.05);
}
.interior-v2 .section-head{margin-bottom:clamp(30px,4vw,52px);}
.interior-v2 .h2{font-size:clamp(32px,4.1vw,54px);line-height:1.03;letter-spacing:-.035em;}
.interior-v2 .eyebrow{margin-bottom:15px;}
.interior-v2 .grid{gap:clamp(18px,2.2vw,28px);}

/* Homepage-like cards: spacious, pale, clearly interactive, not blue-heavy. */
.interior-v2 .card,
.interior-v2 .sv-card,
.interior-v2 .rcard,
.interior-v2 .cr-life,
.interior-v2 .ct-card{
  border-radius:var(--radius-20);
  border-color:rgba(22,40,63,.10);
  background:rgba(var(--white-rgb),.92);
  box-shadow:var(--iv-shadow);
  backdrop-filter:blur(12px);
}
/* .rcard takes the shared interior surface above for its radius, border and shadow, but not
   its background. That rule gives five different components one white translucent surface,
   and .rcard is the one of the five that is not a white card at all — it is a photograph with
   white type on it. The white never showed because the image covers the box at every moment,
   which is exactly why it survived; it only becomes visible in the pointer state below, where
   the photograph drops to half opacity and used to blend into white and come out washed.
   Only the background is overridden here; the rest of the shared surface still applies.
   #09182D is the scrim's own colour, already in .rcard::after. */
.interior-v2 .rcard{background:#09182D;}
.interior-v2 .card{padding:clamp(26px,3vw,38px);}
.interior-v2 .card h3{color:var(--iv-ink);}
.interior-v2 .card p{color:#637184;}
.interior-v2 .card.feature{
  background:
    radial-gradient(70% 80% at 100% 0%,rgba(var(--blue-rgb),.10),transparent 68%),
    linear-gradient(180deg,#fff,#f5f9fb);
}
.interior-v2 .card.feature-teal{
  background:
    radial-gradient(70% 90% at 100% 0%,rgba(var(--blue-soft-rgb),.16),transparent 68%),
    linear-gradient(145deg,#eef7f8,#f8fafc);
}
.interior-v2 .card-link:hover,
.interior-v2 .sv-card:hover{
  border-color:rgba(var(--blue-rgb),.34);
  box-shadow:0 34px 72px -46px rgba(0,93,120,.52);
}
.interior-v2 .icon-soft{background:#edf5f7;color:#007e9e;}
.interior-v2 .pill{background:rgba(var(--white-rgb),.76);border-radius:999px;}

/* Shared CTA language: dark neutral canvas with measured brand light. */
.interior-v2 .cta-band{
  margin-top:clamp(54px,7vw,96px)!important;
  padding:clamp(78px,9vw,118px) 0;
  background:
    radial-gradient(48% 130% at 88% 10%,rgba(var(--blue-rgb),.34),transparent 68%),
    radial-gradient(42% 110% at 8% 100%,rgba(65,42,152,.25),transparent 70%),
    linear-gradient(135deg,#12273a,#1d3147 58%,#24344d);
}
.interior-v2 .cta-band::before{
  content:"";position:absolute;inset:0;pointer-events:none;opacity:.32;
  background-image:radial-gradient(rgba(var(--white-rgb),.24) 1px,transparent 1.5px);
  background-size:32px 32px;
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 20%,#000 80%,transparent);
          mask-image:linear-gradient(90deg,transparent,#000 20%,#000 80%,transparent);
}
.interior-v2 .cta-band>.container{position:relative;z-index:1;}
.interior-v2 .btn{border-radius:999px;}
.interior-v2 .btn-primary{
  background:#007f9f;color:#fff;
  box-shadow:0 18px 34px -20px rgba(0,92,118,.65);
}
.interior-v2 .btn-primary:hover{background:#006f8c;}

/* Contact becomes a true first-view page while retaining its custom form. */
.interior-v2.pg-contact .ct-wrap{
  max-width:1240px;padding-top:clamp(92px,10vw,138px);padding-bottom:clamp(84px,9vw,120px);
}
.interior-v2.pg-contact .ct-wrap::before{
  content:"";position:absolute;z-index:-1;top:0;bottom:0;left:50%;width:100vw;transform:translateX(-50%);
  background:
    radial-gradient(44% 58% at 86% 16%,rgba(var(--blue-rgb),.10),transparent 72%),
    linear-gradient(180deg,#fff,#f2f7fa);
}
.interior-v2 .ct-grid{gap:clamp(24px,3vw,38px);}
.interior-v2 .ct-card{padding:clamp(28px,3.6vw,46px);}
.interior-v2 .ct-panel{
  border-radius:var(--radius-20);
  background:
    radial-gradient(90% 70% at 100% 0%,rgba(var(--blue-soft-rgb),.32),transparent 66%),
    linear-gradient(145deg,#163247,#253952);
  box-shadow:var(--sh-float);
}

/* Section entrance: a stronger but calm version of the homepage choreography. */
/* Entrance DISABLED 2026-08-13, same call as .reveal (base.css:522). This was the
   second, independent entrance system — blur(10px) over .92s — and it is the one that
   still hazed this page after .reveal was switched off: the .acx panel sits inside an
   .iv-enter section, so the whole panel was blurred on the way in even though its own
   styles were fine. Content paints in place now.

   The ::after sweep line below still runs off .iv-in, which the JS keeps adding.
   To restore: opacity:0 / translate:0 54px / blur(10px). */
.interior-v2 .iv-enter{
  opacity:0;translate:0 30px;
  transition:opacity var(--dur-base) var(--ease),translate var(--dur-base) var(--ease-spring);
}
.interior-v2 .iv-enter.iv-in{opacity:1;translate:0 0;}
.interior-v2 .iv-enter::after{
  content:"";position:absolute;z-index:8;top:0;left:50%;width:0;height:2px;pointer-events:none;
  background:linear-gradient(90deg,transparent,var(--blue),var(--blue-soft),transparent);
  transition:left var(--dur-slow) var(--ease-out) .1s,width var(--dur-slow) var(--ease-out) .1s;
}
.interior-v2 .iv-enter.iv-in::after{left:0;width:100%;}

@media (max-width:720px){
  .interior-v2 .page-hero{min-height:380px;padding:72px 0 66px;}
  .interior-v2 .hero-image,.interior-v2 .cr-hero{min-height:470px;}
  .interior-v2 .page-hero .h1,
  .interior-v2 .hero-image .h1,
  .interior-v2 .cr-hero .h1{font-size:clamp(39px,12vw,56px);}
  .interior-v2 .section{padding-top:72px;padding-bottom:56px;}
  .interior-v2 .section-tight{padding-top:56px;padding-bottom:48px;}
  .interior-v2 .h2{font-size:clamp(30px,9vw,42px);}
}
@media (prefers-reduced-motion:reduce){
  .interior-v2 .iv-enter{opacity:1!important;translate:none!important;filter:none!important;transition:none!important;}
  .interior-v2 .iv-enter::after{display:none;}
}

/* =====================================================================
   INTERIOR DATA-PAGE FORMAT V3
   The Data card currently resolves to /services/. Use that page's light,
   editorial hero and measured content rhythm across every interior page,
   while retaining each template's copy, media and interactive modules.
   ===================================================================== */
.interior-v2{
  --df-hero-min:clamp(500px,48vw,560px);
  --df-radius:20px;
  --df-line:rgba(22,40,63,.10);
  --df-surface:rgba(var(--white-rgb),.92);
}

/* One hero format: the same scale, alignment and atmospheric field. */
.interior-v2 :is(.page-hero,.hero-image,.cr-hero),
.interior-v2>section.hero{
  position:relative;
  /* min-height removed: superseded by the shell rule further down. The rest of this
     block is still in force — it carries the flex centring, the clip and the padding. */
  display:flex;
  align-items:center;
  overflow:hidden;
  padding:clamp(88px,10vw,132px) 0 clamp(76px,8vw,108px);
  border:0;
  color:var(--iv-ink);
  background:
    radial-gradient(52% 82% at 90% 16%,rgba(var(--blue-soft-rgb),.24),transparent 70%),
    radial-gradient(42% 68% at 7% 96%,rgba(var(--blue-rgb),.10),transparent 72%),
    linear-gradient(180deg,#fff 0%,#f5fafc 55%,#eaf4f8 100%);
}
.interior-v2 :is(.page-hero,.hero-image,.cr-hero)::before,
.interior-v2>section.hero::before{
  content:"";
  position:absolute;
  inset:0;
  z-index:0;
  pointer-events:none;
  opacity:.82;
  background-image:
    linear-gradient(rgba(var(--blue-rgb),.052) 1px,transparent 1px),
    linear-gradient(90deg,rgba(var(--blue-rgb),.052) 1px,transparent 1px);
  background-size:72px 72px;
  -webkit-mask-image:linear-gradient(90deg,transparent 2%,#000 29%,#000 74%,transparent 98%);
          mask-image:linear-gradient(90deg,transparent 2%,#000 29%,#000 74%,transparent 98%);
}
.interior-v2 :is(.page-hero,.hero-image,.cr-hero)>.container,
.interior-v2>section.hero>.container{
  position:relative;
  z-index:2;
  width:100%;
  padding-top:0;
  padding-bottom:0;
}
.interior-v2 :is(.page-hero,.hero-image,.cr-hero) .h1,
.interior-v2>section.hero .h1{
  max-width:940px;
  color:var(--iv-ink);
  text-wrap:balance;
}
.interior-v2 :is(.page-hero,.hero-image,.cr-hero) .lead,
.interior-v2>section.hero .lead{
  max-width:660px;
  color:#526173;
}
.interior-v2 :is(.page-hero,.hero-image,.cr-hero) .btn-ghost,
.interior-v2>section.hero .btn-ghost{
  color:var(--iv-ink);
  border-color:rgba(22,40,63,.22);
  background:rgba(var(--white-rgb),.38);
}
.interior-v2 :is(.page-hero,.hero-image,.cr-hero) .btn-ghost:hover,
.interior-v2>section.hero .btn-ghost:hover{
  border-color:rgba(var(--blue-rgb),.46);
  background:rgba(var(--white-rgb),.82);
}

/* Existing hero photography becomes a restrained right-side editorial layer. */
.interior-v2 .hero-image .bg{
  z-index:0;
  background:#edf6f9;
}
.interior-v2 .hero-image .bg img{
  inset:0;
  top:0;
  width:100%;
  height:100%;
  opacity:.18;
  object-position:center right;
  filter:saturate(.68) contrast(.92) brightness(1.08);
  mix-blend-mode:multiply;
  -webkit-mask-image:linear-gradient(90deg,transparent 0%,transparent 34%,#000 72%,#000 100%);
          mask-image:linear-gradient(90deg,transparent 0%,transparent 34%,#000 72%,#000 100%);
}
.interior-v2 .hero-image .bg::after{
  background:
    linear-gradient(90deg,#f7fbfd 0%,rgba(247,251,253,.97) 37%,rgba(239,247,250,.52) 72%,rgba(234,244,248,.26) 100%),
    radial-gradient(58% 88% at 88% 30%,rgba(var(--blue-rgb),.10),transparent 72%);
}
.interior-v2 .cr-hero-bg{
  opacity:.62;
  background:
    radial-gradient(48% 80% at 86% 12%,rgba(var(--blue-rgb),.14),transparent 72%),
    linear-gradient(rgba(var(--blue-rgb),.045) 1px,transparent 1px),
    linear-gradient(90deg,rgba(var(--blue-rgb),.045) 1px,transparent 1px);
  background-size:auto,72px 72px,72px 72px;
}
.interior-v2 .cr-hero :is(.cr-hero-title,.cr-hero-sub){color:var(--iv-ink);}
.interior-v2 .cr-hero .cr-hero-sub{color:#526173;}

/* Shared Data-page surfaces for content modules across all templates. */
.interior-v2 :is(.acc,.metrics,.trust,.sv-story,.sv-contact,.cr-life,.ct-card,.policy-card){
  border:1px solid var(--df-line);
  border-radius:var(--df-radius);
  background:var(--df-surface);
  box-shadow:var(--iv-shadow);
}
.interior-v2 .acc{overflow:hidden;}
.interior-v2 .metrics{overflow:hidden;}
.interior-v2 .metric{background:rgba(var(--white-rgb),.72);}
.interior-v2 .tile{
  min-height:132px;
  border-radius:var(--df-radius);
  border-color:var(--df-line);
  background:rgba(var(--white-rgb),.86);
  box-shadow:var(--sh-raised);
}
.interior-v2 .tile:hover{
  border-color:rgba(var(--blue-rgb),.32);
  box-shadow:0 30px 62px -44px rgba(0,93,120,.48);
}
.interior-v2 :is(.section,.section-tight) p{
  max-width:72ch;
}
.interior-v2 .cta-band p{max-width:520px;}

@media (max-width:720px){
  .interior-v2{
    --df-hero-min:420px;
  }
  .interior-v2 :is(.page-hero,.hero-image,.cr-hero),
  .interior-v2>section.hero{
    padding:72px 0 66px;
  }
  .interior-v2 .hero-image .bg img{
    opacity:.11;
    object-position:68% center;
    -webkit-mask-image:linear-gradient(90deg,transparent 0%,#000 70%);
            mask-image:linear-gradient(90deg,transparent 0%,#000 70%);
  }
}

/* Media-led heroes keep their approved full-image treatment. The shared
   Data-page format controls scale and rhythm, not the artwork itself. */

.interior-v2 .hero-image::before{opacity:0;}
.interior-v2 .hero-image>.container{
  padding-top:clamp(96px,11vw,150px);
  padding-bottom:clamp(76px,9vw,118px);
}
.interior-v2 .hero-image .bg{background:#0a1220;}
.interior-v2 .hero-image .bg img{
  inset:auto;
  top:-9%;
  left:0;
  width:100%;
  height:118%;
  opacity:1;
  object-position:center;
  filter:none;
  mix-blend-mode:normal;
  -webkit-mask-image:none;
          mask-image:none;
}
.interior-v2 .hero-image .bg::after{
  background:
    linear-gradient(90deg,rgba(4,18,36,.93) 0%,rgba(10,28,48,.68) 54%,rgba(8,28,46,.30) 100%),
    radial-gradient(58% 88% at 88% 30%,rgba(var(--blue-rgb),.24),transparent 72%);
}
.interior-v2 .hero-image .h1{
  width:min(100%,940px);
  max-width:940px;
  overflow:visible;
  color:var(--hero-ink,#fff);
  font-size:clamp(44px,5.4vw,76px);
  line-height:1.01;
  word-break:normal;
  overflow-wrap:normal;
}
.interior-v2 .hero-image .lead{color:var(--hero-lead-ink,rgba(var(--white-rgb),.94));}
.interior-v2 .hero-image .btn-ghost{
  color:#fff;
  border-color:rgba(var(--white-rgb),.42);
  background:rgba(4,18,36,.16);
}
.interior-v2 .hero-image .btn-ghost:hover{
  color:#fff;
  border-color:rgba(var(--white-rgb),.72);
  background:rgba(4,18,36,.34);
}

/* Light-artwork heroes.
   Two of the fifteen .hero-image pages ship light artwork — /industry-manufacturing/ and
   /industry-bfsi/ — and every one of the fifteen was styled for a dark one. Measured on the
   rendered page: the headline area of both is 93% near-white, and the h1, the lead and the
   ghost button were all painted #fff on it. On /industry-manufacturing/ the only pixels the
   headline contributed were the teal highlight word; "Manufacturing &" did not exist.

   The h1 and the lead need nothing but the tokens — .interior-v2 .hero-image .h1 already reads
   var(--hero-ink,#fff) and the lead var(--hero-lead-ink,...), so setting the two custom
   properties on the section is enough and there is no specificity fight to win. That is what
   hero-art--light is for; it was declared for the .page-hero pages and never wired to any
   .hero-image page.

   The ghost button is the exception: the rule above hardcodes #fff instead of reading a token,
   so it takes an explicit override. Its ink is --logo-blue, which is what the same situation on
   /certifications/ settled on, and the fill stays a tint of the same colour rather than the
   dark rgba(4,18,36,...) wash, which would have read as a bruise on a white ground.

   The highlight word needs no rule here: .hero-art--light .grad-text further down already
   swaps the teal ramp for solid --logo-blue, and it now matches because the class sits on an
   ancestor of the span. */
.hero-image.hero-art--light{
  --hero-ink:var(--ink);
  --hero-lead-ink:var(--text);
}
.interior-v2 .hero-image.hero-art--light .btn-ghost{
  color:var(--logo-blue);
  border-color:color-mix(in srgb,var(--logo-blue) 38%,transparent);
  background:color-mix(in srgb,var(--logo-blue) 6%,transparent);
}
.interior-v2 .hero-image.hero-art--light .btn-ghost:hover{
  color:var(--logo-blue);
  border-color:var(--logo-blue);
  background:color-mix(in srgb,var(--logo-blue) 12%,transparent);
}

/* "Careers also keeps its previous dark hero" is what this block used to say, and it is
   why the hero's headline was unreadable: the hero is not dark any more. Measured on the
   live page, .cr-hero computes to radial-gradient(rgba(var(--blue-soft-rgb),.24)...) over white —
   a later rule had turned the ground light — while this block was still painting #fff ink
   and a white 72px grid on top of it. Off the rendered pixels that is 1.81:1 for the
   headline and 1.13:1 for the sub, against floors of 3:1 and 4.5:1. The grid measured
   1.00:1: white lines at .045 alpha on white, i.e. not drawn at all.

   The generation before this one (see .interior-v2 .cr-hero-bg further up) had already
   done the right thing — light ground, --iv-ink title, #526173 sub, blue grid — and this
   block simply out-ranked it. It is deleted rather than out-ranked in turn, so what is left
   is one treatment instead of two arguing. That also puts careers on the same footing as
   every other interior hero, which are light-ground with dark ink.

   The ::before dimming is kept: it is a density reduction on the shared 72px hero grid,
   and less grid is the direction the client asked for. */
.interior-v2 .cr-hero::before{opacity:.34;}
/* The gradient headline word was the third white-on-white layer here: #C4E4F2 -> var(--blue-soft)
   measures 1.23:1 to 2.32:1 on this ground, so "next" was the least visible word in the
   line. Same remedy the light artwork heroes got — the gradient is dropped for flat
   --logo-blue, which is 4.82:1 here. */
.interior-v2 .cr-hero .grad-text{
  background:none;
  -webkit-background-clip:border-box;background-clip:border-box;
  -webkit-text-fill-color:var(--logo-blue);color:var(--logo-blue);
}

@media (max-width:720px){
  .interior-v2 .hero-image>.container{
    padding-top:82px;
    padding-bottom:72px;
  }
  .interior-v2 .hero-image .bg img{
    opacity:1;
    object-position:center;
    -webkit-mask-image:none;
            mask-image:none;
  }
  .interior-v2 .hero-image .h1{
    font-size:clamp(38px,11vw,54px);
    overflow-wrap:anywhere;
  }
}

/* Capability hero artwork: client-supplied, Retina-ready and still replaceable
   through the per-page WordPress image control. */
.interior-v2 .capability-hero .h1{
  max-width:980px;
  text-wrap:balance;
}
.interior-v2 .capability-hero .lead{
  max-width:690px;
  margin:24px 0 34px;
}
.interior-v2 .capability-hero .fx-hw{
  opacity:1;
  transition:none;
}
.interior-v2 .capability-hero .grad-text{
  background:var(--grad-anniv);
  background-size:100% auto;
  -webkit-background-clip:text;
          background-clip:text;
  color:transparent;
}
/* Data and Systems: the highlight word follows the artwork, and the artwork changed.

   Both of these were sampled off the banners they used to carry — Data's was a red-and-
   orange database plate, so its highlighted word was solid --aux-orange and its CTA was an
   orange button with an orange shadow; Systems' was a gold circuit board, so its word ran
   yellow-to-orange. Neither banner is on the page any more. An orange word and an orange
   button on a dark-teal banner is not an accent, it is a clash, and it was the one thing
   left on those two pages still pointing at artwork nobody can see.

   Both now run in the same cyan-to-blue the new plates are built from, which is also what
   .capability-hero--infrastructure already uses — so the three capability heroes finally
   agree with each other instead of each answering to a different picture. */
.interior-v2 .capability-hero--data .grad-text,
.interior-v2 .capability-hero--systems .grad-text{
  background:linear-gradient(100deg,var(--aux-cyan),var(--blue));
  -webkit-background-clip:text;
          background-clip:text;
}
.interior-v2 .capability-hero--infrastructure .grad-text{
  background:linear-gradient(100deg,var(--aux-cyan),var(--blue));
  -webkit-background-clip:text;
          background-clip:text;
}
/* The CTA went orange for the same reason and loses it for the same reason — it now
   matches the other capability heroes rather than a banner that has been replaced. */
.interior-v2 .capability-hero--data .btn-primary,
.interior-v2 .capability-hero--systems .btn-primary,
.interior-v2 .capability-hero--infrastructure .btn-primary{
  background:var(--blue);
}
.capability-hero-actions{display:flex;gap:var(--sp-12);flex-wrap:wrap;}
/* The left column of a capability page was a heading, a rule and two paragraphs set
   identically — flat against the dense panel beside it. These are not the same kind of
   sentence, so they are no longer set the same way: the first states what the practice
   is, the ones after it say how it runs. Same treatment the AI page already uses, so
   the six capability pages read as one family. No markup changed — the split is by
   position, so every page picks it up as it stands. */
/* One treatment for every paragraph in the block. At the client's call: the paragraphs are
   not to be broken further into different styling.

   What was here split two paragraphs of one intro into three appearances. :first-of-type got
   its own size (clamp 17.5-19.5px against 16px), its own colour (--text-2 against --text) and
   its own spacing; :nth-of-type(n+2) got a smaller 16.2px, a 20px indent and a gradient bar
   drawn down its left edge; and :first-of-type::first-line recoloured the opening LINE of the
   first paragraph to --ink, so a single paragraph was two colours. Every template that uses
   this class — page-systems, page-data, page-robotics and template-parts/independent-page,
   which is five industry pages — writes exactly two <p class="capability-copy">, so the split
   was never in the markup. The markup was already right; the stylesheet was inventing a
   hierarchy that the copy does not have.

   Kept the larger of the two sizes rather than the smaller: this block is the section's lede
   and it sits opposite an accordion, so it needs the weight. What is dropped is the idea that
   the second sentence is a lesser thing.

   The bar is also gone for a second reason — .cap-lede already draws a rail down the left of
   this whole block, so a second vertical line 20px inside it was two rules doing one job.

   :last-child keeps its zero bottom margin. That is spacing hygiene, not a style: it removes
   a trailing gap and cannot be seen as a difference between paragraphs. */
.capability-copy{
  font:400 clamp(17.5px,1.55vw,19.5px)/1.58 var(--f-body);
  letter-spacing:-.004em;
  color:var(--text-2);
  margin:0 0 20px;
  max-width:52ch;
}
.capability-copy:last-child{margin-bottom:0;}
@media (max-width:720px){
  .capability-copy{max-width:none;font-size:17px;}
}
.capability-note{font-size:11px;color:var(--muted-2);margin-top:12px;}
.interior-v2 .capability-hero--systems .bg::after{
  background:linear-gradient(90deg,rgba(var(--ground-rgb),.97) 0%,rgba(var(--ground-rgb),.87) 36%,rgba(5,23,42,.49) 62%,rgba(5,23,42,.12) 100%);
}
.interior-v2 .capability-hero--data .bg::after{
  background:linear-gradient(90deg,rgba(7,15,21,.97) 0%,rgba(7,15,21,.84) 34%,rgba(18,29,34,.39) 62%,rgba(18,29,34,.08) 100%);
}
.interior-v2 .capability-hero--infrastructure .bg::after{
  background:linear-gradient(90deg,rgba(3,20,62,.94) 0%,rgba(3,20,62,.79) 38%,rgba(3,20,62,.36) 67%,rgba(3,20,62,.08) 100%);
}

/* Shared depth layer. The existing scroll parallax continues to move the image
   inside this wrapper; idle breathing and pointer depth live on the wrapper. */
.capability-hero .bg{isolation:isolate;}
.capability-hero .ch-art{
  position:absolute;
  inset:-2%;
  z-index:0;
  overflow:hidden;
  opacity:.82;
  scale:1.055;
  translate:var(--ch-x,0) var(--ch-y,0);
  transition:opacity var(--dur-slow) var(--ease),translate var(--dur-fast) linear;
  will-change:scale,translate;
}
.capability-hero.ch-motion-in .ch-art{opacity:1;}
.capability-hero .ch-art img{
  top:-9%;
  left:0;
  width:100%;
  height:118%;
}
.capability-hero .ch-fx{
  position:absolute;
  inset:0;
  z-index:1;
  overflow:hidden;
  pointer-events:none;
  opacity:0;
  translate:var(--ch-fx-x,0) var(--ch-fx-y,0);
  transition:opacity var(--dur-slow) var(--ease) .2s,translate var(--dur-fast) linear;
}
.capability-hero.ch-motion-in .ch-fx{opacity:1;}
.capability-hero .bg::after{z-index:2;}
.ch-fx i{position:absolute;display:block;pointer-events:none;}
.ch-orb{border-radius:50%;opacity:.3;filter:blur(2px);}
.ch-packet{width:9px;height:9px;border-radius:50%;opacity:0;}

/* AI — Pantone 1788 C energy travels through the supplied mesh. */
.capability-hero--ai .ch-fx::before{
  content:"";position:absolute;inset:0;
  background:
    radial-gradient(circle at 73% 46%,rgba(var(--cyan-rgb),.72) 0 2px,transparent 7px),
    radial-gradient(circle at 84% 28%,rgba(144,71,153,.66) 0 2px,transparent 8px),
    radial-gradient(circle at 91% 63%,rgba(var(--cyan-rgb),.68) 0 2px,transparent 8px),
    radial-gradient(circle at 66% 74%,rgba(144,71,153,.5) 0 2px,transparent 7px);
  filter:drop-shadow(0 0 8px rgba(var(--cyan-rgb),.72));
  animation:chAiNodes 2.9s ease-in-out infinite alternate;
}
.capability-hero--ai .ch-scan{
  right:3%;top:38%;width:43%;height:2px;rotate:-12deg;opacity:.45;
  background:linear-gradient(90deg,transparent,var(--aux-red) 30%,#fff 54%,var(--aux-cyan) 72%,transparent);
  filter:blur(.2px) drop-shadow(0 0 7px rgba(var(--cyan-rgb),.78));
  animation:chAiSignal 5.6s ease-in-out infinite;
}
.capability-hero--ai .ch-packet{background:#fff;box-shadow:0 0 6px 3px rgba(var(--cyan-rgb),.62);}
.capability-hero--ai .ch-packet-a{left:65%;top:70%;animation:chAiPacketA 5.4s linear .2s infinite;}
.capability-hero--ai .ch-packet-b{left:78%;top:52%;animation:chAiPacketB 6.2s linear 1.7s infinite;}
.capability-hero--ai .ch-packet-c{left:88%;top:34%;animation:chAiPacketC 5.8s linear 3.1s infinite;}
/* Ken Burns — slow, tasteful drift + zoom so the AI mesh hero reads as alive (auto-disabled under prefers-reduced-motion, base.css:349) */
.capability-hero--ai .ch-art img{transform-origin:72% 42%;}
/* No horizontal pan. transform-origin is 72% 42%, so a 1.05 zoom leaves only
   (1 - 0.72) x 5% = 1.4% of cover past the right edge, and the -3.4% x-translate this
   used to carry pushed the art 2% further left than that — which is exactly the pale
   strip that appeared down the right side of the hero. Vertically there is room:
   (1 - 0.42) x 6% = 3.5% of cover against a 2% drift, so the drift stays. */

/* Blinking light dots stay removed (twinkle maps + node pulse + packets were too dazzling) */
.capability-hero--ai .ch-ai-light-map,
.capability-hero--ai .ch-fx::before,
.capability-hero--ai .ch-packet{display:none;}
/* Movement without dazzle: a soft energy band flows continuously through the mesh (right side only, so it never crosses the headline). Auto-disabled under prefers-reduced-motion (base.css:349). */
.capability-hero--ai .bg::before{
  content:"";position:absolute;inset:0;z-index:3;pointer-events:none;
  background:linear-gradient(115deg,transparent 34%,rgba(var(--cyan-rgb),.20) 47%,rgba(var(--white-rgb),.13) 50%,rgba(144,71,153,.17) 53%,transparent 66%);
  background-size:230% 100%;background-repeat:no-repeat;
  -webkit-mask-image:linear-gradient(90deg,transparent 0 40%,#000 62%);
  mask-image:linear-gradient(90deg,transparent 0 40%,#000 62%);
  mix-blend-mode:screen;
  animation:chAiFlow 8.5s linear infinite;
}
@keyframes chAiFlow{0%{background-position:150% 0}100%{background-position:-70% 0}}

/* Systems — a restrained diagnostic sweep and sequential board wake-up. */
.capability-hero--systems .ch-scan{
  top:0;bottom:0;left:-18%;width:15%;opacity:.42;
  background:linear-gradient(90deg,transparent,rgba(255,206,0,.06),rgba(255,206,0,.27),rgba(255,206,0,.05),transparent);
  filter:blur(1px);
  animation:chSystemsSweep 7.5s cubic-bezier(.45,0,.2,1) infinite;
}
.capability-hero--systems .ch-fx::before{
  content:"";position:absolute;inset:0;
  background:
    radial-gradient(circle at 57% 26%,rgba(255,206,0,.9) 0 2px,transparent 5px),
    radial-gradient(circle at 72% 52%,rgba(255,206,0,.76) 0 2px,transparent 6px),
    radial-gradient(circle at 87% 31%,rgba(255,206,0,.9) 0 2px,transparent 5px),
    radial-gradient(circle at 80% 77%,rgba(255,206,0,.68) 0 2px,transparent 6px);
  filter:drop-shadow(0 0 7px rgba(255,206,0,.68));
  animation:chSystemsNodes 3.2s steps(4,end) infinite;
}
.capability-hero--systems .ch-packet{background:#FFCE00;box-shadow:0 0 9px 2px rgba(255,206,0,.5);}
.capability-hero--systems .ch-packet-a{left:58%;top:12%;animation:chSystemsDrop 4.8s linear .1s infinite;}
.capability-hero--systems .ch-packet-b{left:76%;top:4%;animation:chSystemsDrop 5.6s linear 1.7s infinite;}
.capability-hero--systems .ch-packet-c{left:91%;top:18%;animation:chSystemsDrop 5.1s linear 3s infinite;}

/* Data — the warm field pulses while small insights rise from the data floor. */
.capability-hero--data .ch-fx::before{
  content:"";position:absolute;left:27%;right:0;bottom:-8%;height:54%;
  background:
    radial-gradient(ellipse at 72% 100%,rgba(255,206,0,.28),transparent 50%),
    linear-gradient(0deg,rgba(255,158,22,.22),transparent 68%);
  filter:blur(8px);
  animation:chDataGlow 4.8s ease-in-out infinite alternate;
}
.capability-hero--data .ch-scan{
  left:36%;right:2%;top:20%;height:1px;opacity:.2;
  background:linear-gradient(90deg,transparent,rgba(var(--cyan-rgb),.9),#fff,transparent);
  filter:drop-shadow(0 0 7px rgba(var(--cyan-rgb),.8));
  animation:chDataScan 6.5s ease-in-out infinite;
}
.capability-hero--data .ch-packet{background:var(--aux-cyan);box-shadow:0 0 9px 3px rgba(var(--cyan-rgb),.58);}
.capability-hero--data .ch-packet-a{left:49%;bottom:4%;animation:chDataRise 5.8s ease-out .4s infinite;}
.capability-hero--data .ch-packet-b{left:67%;bottom:2%;animation:chDataRise 6.4s ease-out 2s infinite;}
.capability-hero--data .ch-packet-c{left:84%;bottom:7%;animation:chDataRise 5.3s ease-out 3.3s infinite;}

/* Infrastructure — diagonal strata separate gently; network nodes breathe. */
.capability-hero--infrastructure .ch-fx::before{
  content:"";position:absolute;inset:-12% -8%;
  background:linear-gradient(112deg,transparent 32%,rgba(var(--cyan-rgb),.15) 41%,transparent 49%,rgba(0,63,152,.15) 64%,transparent 72%);
  animation:chInfraLayers 9s ease-in-out infinite alternate;
}
.capability-hero--infrastructure .ch-fx::after{
  content:"";position:absolute;inset:0;
  background:
    radial-gradient(circle at 76% 23%,rgba(var(--cyan-rgb),.9) 0 2px,transparent 7px),
    radial-gradient(circle at 87% 54%,rgba(var(--cyan-rgb),.75) 0 2px,transparent 7px),
    radial-gradient(circle at 69% 68%,rgba(var(--blue-rgb),.66) 0 2px,transparent 7px),
    radial-gradient(circle at 93% 77%,rgba(var(--cyan-rgb),.75) 0 2px,transparent 7px);
  filter:drop-shadow(0 0 8px rgba(var(--cyan-rgb),.78));
  animation:chInfraNodes 3.8s ease-in-out infinite alternate;
}
.capability-hero--infrastructure .ch-scan{
  left:40%;top:-45%;width:11%;height:180%;rotate:24deg;opacity:.22;
  background:linear-gradient(90deg,transparent,rgba(var(--cyan-rgb),.56),transparent);
  filter:blur(4px);
  animation:chInfraSweep 8.5s ease-in-out infinite;
}

@keyframes chAiNodes{0%{opacity:.38;filter:brightness(.8)}55%{opacity:.9;filter:brightness(1.4)}100%{opacity:.55;filter:brightness(1)}}
@keyframes chAiSignal{0%,12%{translate:-22% 16px;opacity:0}30%{opacity:.55}72%{opacity:.38}100%{translate:16% -10px;opacity:0}}
@keyframes chAiPacketA{0%,14%{translate:-30px 35px;opacity:0}28%{opacity:1}82%{opacity:.85}100%{translate:390px -135px;opacity:0}}
@keyframes chAiPacketB{0%,18%{translate:-60px 45px;opacity:0}34%{opacity:1}100%{translate:330px -105px;opacity:0}}
@keyframes chAiPacketC{0%,16%{translate:-85px 60px;opacity:0}32%{opacity:1}100%{translate:230px -75px;opacity:0}}
@keyframes chSystemsSweep{0%,10%{translate:0;opacity:0}20%{opacity:.46}72%{opacity:.32}100%{translate:780%;opacity:0}}
@keyframes chSystemsNodes{0%{opacity:.2}25%{opacity:.48}50%{opacity:.72}75%{opacity:1}100%{opacity:.32}}
@keyframes chSystemsDrop{0%,15%{translate:0 -80px;opacity:0}28%{opacity:1}82%{opacity:.7}100%{translate:0 520px;opacity:0}}
@keyframes chDataGlow{0%{opacity:.35;scale:.98}100%{opacity:.9;scale:1.045}}
@keyframes chDataScan{0%,10%{translate:0 -100px;opacity:0}28%{opacity:.45}75%{opacity:.24}100%{translate:0 410px;opacity:0}}
@keyframes chDataRise{0%,15%{translate:0 35px;opacity:0}28%{opacity:1}72%{opacity:.75}100%{translate:40px -350px;opacity:0}}
@keyframes chInfraLayers{0%{translate:-1.4% 0}100%{translate:1.8% 0}}
@keyframes chInfraNodes{0%{opacity:.32;filter:brightness(.82)}100%{opacity:.92;filter:brightness(1.35)}}
@keyframes chInfraSweep{0%,15%{translate:-250% 0;opacity:0}30%{opacity:.3}72%{opacity:.22}100%{translate:520% 0;opacity:0}}

@media (max-width:720px){
  .interior-v2 .capability-hero>.container{
    width:100%;
    max-width:100%;
    padding-left:28px;
    padding-right:28px;
    overflow:hidden;
  }
  .interior-v2 .capability-hero .h1{
    width:100%;
    max-width:100%;
    font-size:clamp(38px,10.5vw,54px);
    line-height:1.03;
    white-space:normal;
    text-wrap:wrap;
    overflow-wrap:anywhere;
    word-break:normal;
  }
  .interior-v2 .capability-hero .lead{
    width:100%;
    max-width:100%;
    font-size:18px;
    line-height:1.55;
  }
  .interior-v2 .capability-hero .bg img{object-position:60% center;}
  .interior-v2 .capability-hero .bg::after{
    background:linear-gradient(90deg,rgba(var(--ground-rgb),.96) 0%,rgba(var(--ground-rgb),.81) 62%,rgba(var(--ground-rgb),.47) 100%);
  }
  .capability-hero .ch-art{inset:-1%;animation-duration:18s;}
  .capability-hero .ch-fx{opacity:.58;}
  .capability-hero .ch-packet-b,.capability-hero .ch-packet-c{display:none;}
}

@media (prefers-reduced-motion:reduce){
  .capability-hero .ch-art{
    opacity:1;
    scale:1.025;
    translate:0 0;
    animation:none;
    transition:none;
  }
  .capability-hero .ch-fx{display:none;}
}

/* =====================================================================
   CAPABILITIES SYSTEM V2 — six connected, responsive capability modules
   ===================================================================== */
.c2-system-rail{position:absolute;inset:0;z-index:6;overflow:hidden;pointer-events:none;border-radius:var(--radius-20);}
.c2-system-rail i{position:absolute;left:0;width:20%;height:2px;opacity:0;
  background:linear-gradient(90deg,transparent,var(--blue) 36%,#fff 62%,#C81BC0 82%,transparent);
  filter:drop-shadow(0 0 7px rgba(var(--blue-rgb),.78));}
.c2-system-rail i::after{content:"";position:absolute;right:8%;top:50%;width:8px;height:8px;border-radius:50%;
  background:#fff;box-shadow:0 0 0 4px rgba(var(--blue-rgb),.16),0 0 18px var(--blue);transform:translateY(-50%);}
.c2-system-rail i:first-child{top:0;transform:translateX(-120%);}
.c2-system-rail i:last-child{top:calc(50% + 8px);left:auto;right:0;transform:translateX(120%);}
.ah-caps2-grid.c2-system-live .c2-system-rail i:first-child{animation:c2RailForward 1.35s cubic-bezier(.2,.7,.2,1) .12s both;}
.ah-caps2-grid.c2-system-live .c2-system-rail i:last-child{animation:c2RailReverse 1.35s cubic-bezier(.2,.7,.2,1) .78s both;}
@keyframes c2RailForward{
  0%{opacity:0;transform:translateX(-120%) scaleX(.25)}
  12%{opacity:1}
  78%{opacity:.95}
  100%{opacity:0;transform:translateX(505%) scaleX(1)}
}
@keyframes c2RailReverse{
  0%{opacity:0;transform:translateX(120%) scaleX(.25)}
  12%{opacity:1}
  78%{opacity:.95}
  100%{opacity:0;transform:translateX(-505%) scaleX(1)}
}

.home.motion-v1 .c2-motion-armed .ah-cap2 .ah-cap2-no{
  opacity:0;translate:-14px 0;filter:blur(4px);
  transition:opacity var(--dur-base) var(--ease) .18s,translate var(--dur-base) var(--ease-out) .18s,filter var(--dur-base) var(--ease) .18s;
}
.home.motion-v1 .c2-motion-armed .ah-cap2.c2-motion-in .ah-cap2-no{opacity:1;translate:0 0;filter:blur(0);}
.home.motion-v1 .c2-motion-armed .ah-cap2 .ah-cap2-ic{position:absolute;right:24px;top:20px;}
.ah-cap2-glyphfx,.ah-cap2-glyphfx::before,.ah-cap2-glyphfx::after{position:absolute;pointer-events:none;}
.ah-cap2-glyphfx{inset:8px;z-index:3;border-radius:50%;}
.ah-cap2-glyphfx::before,.ah-cap2-glyphfx::after{content:"";opacity:0;transition:opacity var(--dur-base) var(--ease-out);}

/* Cloud — orbital upload particles. */
.cap2--cloud .ah-cap2-glyphfx::before{inset:3px;border:1px dashed color-mix(in srgb,var(--acc) 48%,transparent);border-radius:50%;}
.cap2--cloud .ah-cap2-glyphfx::after{left:50%;top:3px;width:5px;height:5px;border-radius:50%;background:var(--acc);
  box-shadow:38px 55px 0 -1px color-mix(in srgb,var(--acc) 70%,transparent),-35px 72px 0 -1px color-mix(in srgb,var(--acc) 52%,transparent);}
.cap2--cloud:hover .ah-cap2-glyphfx::before,.cap2--cloud:hover .ah-cap2-glyphfx::after{opacity:1;animation:c2Orbit 4s linear infinite;}
@keyframes c2Orbit{to{rotate:360deg}}

/* AI — neural core ignition. */
.cap2--ai .ah-cap2-glyphfx::before{inset:26px;background:conic-gradient(from 0deg,transparent,var(--aux-purple),var(--blue),transparent);
  clip-path:polygon(50% 0,100% 88%,0 88%);filter:blur(2px);}
.cap2--ai .ah-cap2-glyphfx::after{inset:18px;border:1px solid color-mix(in srgb,var(--acc) 46%,transparent);border-radius:50%;}
.cap2--ai:hover .ah-cap2-glyphfx::before{opacity:.55;animation:c2AiCore 1.45s ease-in-out infinite;}
.cap2--ai:hover .ah-cap2-glyphfx::after{opacity:1;animation:c2AiRing 1.45s ease-out infinite;}
@keyframes c2AiCore{0%,100%{scale:.82;rotate:-8deg;filter:blur(4px)}50%{scale:1.12;rotate:8deg;filter:blur(1px)}}
@keyframes c2AiRing{0%{scale:.45;opacity:.9}100%{scale:1.18;opacity:0}}

/* Data — layered packets move through the stack. */
.cap2--data .ah-cap2-glyphfx::before{left:22px;right:22px;top:38px;height:44px;
  background:repeating-linear-gradient(180deg,transparent 0 8px,color-mix(in srgb,var(--acc) 62%,transparent) 9px 11px,transparent 12px 16px);
  filter:drop-shadow(0 0 5px color-mix(in srgb,var(--acc) 55%,transparent));}
.cap2--data .ah-cap2-glyphfx::after{left:28px;right:28px;top:60px;height:1px;background:linear-gradient(90deg,transparent,#fff,transparent);}
.cap2--data:hover .ah-cap2-glyphfx::before{opacity:.72;animation:c2DataStack 1.25s ease-in-out infinite;}
.cap2--data:hover .ah-cap2-glyphfx::after{opacity:.9;animation:c2DataSweep 1.25s ease-in-out infinite;}
@keyframes c2DataStack{0%,100%{translate:0 -9px}50%{translate:0 10px}}
@keyframes c2DataSweep{0%{translate:0 -24px;opacity:0}40%{opacity:1}100%{translate:0 34px;opacity:0}}

/* Security — an active scanner crosses the shield. */
.cap2--security .ah-cap2-glyphfx::before{top:18px;bottom:18px;left:24px;width:2px;
  background:linear-gradient(180deg,transparent,#fff 44%,var(--acc) 58%,transparent);
  box-shadow:0 0 14px color-mix(in srgb,var(--acc) 75%,transparent);}
.cap2--security .ah-cap2-glyphfx::after{inset:20px;border:1px solid color-mix(in srgb,var(--acc) 44%,transparent);border-radius:24% 24% 42% 42%;}
.cap2--security:hover .ah-cap2-glyphfx::before{opacity:1;animation:c2SecurityScan 1.35s ease-in-out infinite;}
.cap2--security:hover .ah-cap2-glyphfx::after{opacity:.75;animation:c2SecurityPulse 1.35s ease-in-out infinite;}
@keyframes c2SecurityScan{0%{translate:0 0;opacity:0}18%{opacity:1}82%{opacity:1}100%{translate:78px 0;opacity:0}}
@keyframes c2SecurityPulse{0%,100%{scale:.92}50%{scale:1.05}}

/* Experience — interaction ripples respond around the symbol. */
.cap2--experience .ah-cap2-glyphfx::before,.cap2--experience .ah-cap2-glyphfx::after{
  left:50%;top:50%;width:52px;height:52px;margin:-26px;border:1.5px solid color-mix(in srgb,var(--acc) 66%,transparent);border-radius:50%;}
.cap2--experience:hover .ah-cap2-glyphfx::before{opacity:1;animation:c2Ripple 1.6s ease-out infinite;}
.cap2--experience:hover .ah-cap2-glyphfx::after{opacity:1;animation:c2Ripple 1.6s ease-out .58s infinite;}
@keyframes c2Ripple{0%{scale:.45;opacity:.9}100%{scale:2.05;opacity:0}}

/* Product — engineering frame assembles around the cube. */
.cap2--product .ah-cap2-glyphfx::before{inset:18px;border:1.5px solid color-mix(in srgb,var(--acc) 58%,transparent);
  clip-path:polygon(50% 0,93% 24%,93% 75%,50% 100%,7% 75%,7% 24%);}
.cap2--product .ah-cap2-glyphfx::after{inset:29px;border:1px dashed color-mix(in srgb,var(--acc) 70%,transparent);
  clip-path:polygon(50% 0,93% 24%,93% 75%,50% 100%,7% 75%,7% 24%);}
.cap2--product:hover .ah-cap2-glyphfx::before{opacity:.8;animation:c2ProductFrame 2.2s ease-in-out infinite;}
.cap2--product:hover .ah-cap2-glyphfx::after{opacity:1;animation:c2ProductFrame 2.2s ease-in-out -.8s infinite reverse;}
@keyframes c2ProductFrame{0%,100%{scale:.86;rotate:-8deg}50%{scale:1.08;rotate:8deg}}

/* Six distinct idle/hover personalities. */
.home.motion-v1 .c2-motion-armed .ah-cap2.cap2--cloud.c2-motion-in .ah-cap2-ic img{animation:c2CloudIdle 5.8s ease-in-out var(--c2-phase,0s) infinite;}
.home.motion-v1 .c2-motion-armed .ah-cap2.cap2--ai.c2-motion-in .ah-cap2-ic img{animation:c2AiIdle 4.6s ease-in-out var(--c2-phase,0s) infinite;}
.home.motion-v1 .c2-motion-armed .ah-cap2.cap2--data.c2-motion-in .ah-cap2-ic img{animation:c2DataIdle 5.2s ease-in-out var(--c2-phase,0s) infinite;}
.home.motion-v1 .c2-motion-armed .ah-cap2.cap2--security.c2-motion-in .ah-cap2-ic img{animation:c2SecurityIdle 4.9s ease-in-out var(--c2-phase,0s) infinite;}
.home.motion-v1 .c2-motion-armed .ah-cap2.cap2--experience.c2-motion-in .ah-cap2-ic img{animation:c2ExperienceIdle 6.2s ease-in-out var(--c2-phase,0s) infinite;}
.home.motion-v1 .c2-motion-armed .ah-cap2.cap2--product.c2-motion-in .ah-cap2-ic img{animation:c2ProductIdle 6.4s ease-in-out var(--c2-phase,0s) infinite;}
@keyframes c2CloudIdle{0%,100%{translate:0 0;rotate:-1deg}50%{translate:0 -7px;rotate:1deg}}
@keyframes c2AiIdle{0%,100%{scale:.98;filter:brightness(1)}50%{scale:1.035;filter:brightness(1.12)}}
@keyframes c2DataIdle{0%,100%{translate:0 -2px}50%{translate:0 6px}}
@keyframes c2SecurityIdle{0%,100%{scale:.985}50%{scale:1.025}}
@keyframes c2ExperienceIdle{0%,100%{translate:0 0;rotate:-2deg}50%{translate:0 -5px;rotate:2deg}}
@keyframes c2ProductIdle{0%,100%{transform:perspective(260px) rotateY(-5deg) translateY(0)}50%{transform:perspective(260px) rotateY(6deg) translateY(-5px)}}

@media (hover:hover) and (pointer:fine){
  .home.motion-v1 .ah-caps2-grid.c2-motion-armed.cap-focus .ah-cap2.c2-motion-in:not(.cap-active){
    opacity:.68;filter:saturate(.72) brightness(.985);
    transform:perspective(1000px);
  }
  .home.motion-v1 .ah-caps2-grid.c2-motion-armed .ah-cap2.c2-motion-in.cap-active{
    opacity:1;filter:none;
    transform:perspective(1000px) rotateX(var(--cap-rx)) rotateY(var(--cap-ry)) translateY(-9px) scale(1.018);
    border-color:color-mix(in srgb,var(--acc) 58%,#E7ECF4);
    box-shadow:0 42px 82px -38px color-mix(in srgb,var(--acc) 52%,rgba(3,60,120,.55));
    transition:transform var(--dur-fast) var(--ease),border-color var(--dur-base),box-shadow var(--dur-base),filter var(--dur-base),opacity var(--dur-base);
  }
  .home.motion-v1 .ah-caps2-grid.c2-motion-armed .ah-cap2.c2-motion-in.cap-active::before{opacity:1;}
}

@media (prefers-reduced-motion:reduce){
  .c2-system-rail{display:none!important;}
  .ah-cap2-glyphfx,.ah-cap2-glyphfx::before,.ah-cap2-glyphfx::after,.ah-cap2-ic img{
    animation:none!important;transition:none!important;
  }
  .ah-cap2{--cap-rx:0deg!important;--cap-ry:0deg!important;}
}
@media (max-width:600px){
  .home.motion-v1 .c2-motion-armed .ah-cap2 .ah-cap2-ic{right:12px;top:14px;}
}

/* =====================================================================
   GLASS DEVICE ICONS V2
   A coordinated material system with six capability-specific structures.
   The image supplies the crystal object; CSS supplies live energy signals.
   ===================================================================== */
.ah-cap2-ic{
  right:18px;top:14px;width:128px;height:128px;border-radius:50%;overflow:visible;
  perspective:460px;
  background:
    radial-gradient(circle at 50% 46%,#ffffff 0 45%,rgba(237,246,251,.92) 61%,rgba(230,241,249,0) 73%),
    radial-gradient(circle at 50% 52%,color-mix(in srgb,var(--acc) 11%,transparent),transparent 70%);
  box-shadow:inset 0 0 0 1.4px color-mix(in srgb,var(--acc) 20%,rgba(var(--white-rgb),.5)),0 20px 42px -32px color-mix(in srgb,var(--acc) 45%,transparent);
  transition:background var(--dur-base) var(--ease-out),box-shadow var(--dur-base) var(--ease-out),transform var(--dur-base) var(--ease-out);
}
.ah-cap2-ic img{
  width:108px;height:108px;border-radius:50%;mix-blend-mode:multiply;
  filter:contrast(1.035) saturate(1.04);
  transform-origin:50% 62%;
}
.ah-cap2:hover .ah-cap2-ic{
  background:
    radial-gradient(circle at 42% 34%,rgba(var(--white-rgb),1) 0 18%,rgba(var(--white-rgb),.35) 40%,transparent 63%),
    radial-gradient(circle at 50% 52%,color-mix(in srgb,var(--acc) 21%,transparent),transparent 72%);
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--acc) 18%,white),0 24px 46px -27px color-mix(in srgb,var(--acc) 62%,transparent);
}
.ah-cap2:hover .ah-cap2-ic img{filter:contrast(1.06) saturate(1.12) brightness(1.02);}
.ah-cap2-glyphfx{inset:10px;border-radius:50%;mix-blend-mode:multiply;}

/* Robotics — three joint halos engage, then a precision signal travels to the gripper. */
.cap2--robotics .ah-cap2-glyphfx::before{
  inset:0;opacity:.2;
  background:
    radial-gradient(circle at 33% 71%,transparent 0 5px,color-mix(in srgb,var(--acc) 72%,transparent) 5.5px 7px,transparent 7.5px),
    radial-gradient(circle at 45% 24%,transparent 0 5px,color-mix(in srgb,var(--acc) 66%,transparent) 5.5px 7px,transparent 7.5px),
    radial-gradient(circle at 72% 42%,transparent 0 4px,color-mix(in srgb,var(--acc) 58%,transparent) 4.5px 6px,transparent 6.5px);
  animation:c2RobotJointIdle 3.8s ease-in-out infinite;
}
.cap2--robotics .ah-cap2-glyphfx::after{
  left:43%;top:27%;width:48%;height:2px;opacity:0;transform-origin:left center;rotate:20deg;
  background:linear-gradient(90deg,transparent,var(--acc),#fff,transparent);
  box-shadow:0 0 10px color-mix(in srgb,var(--acc) 72%,transparent);
}
.cap2--robotics:hover .ah-cap2-glyphfx::before{opacity:.9;animation:c2RobotJointWork 1.15s ease-in-out infinite;}
.cap2--robotics:hover .ah-cap2-glyphfx::after{animation:c2RobotSignal 1.15s ease-out infinite;}
.cap2--robotics:hover .ah-cap2-ic img{animation:c2RobotWork 1.45s cubic-bezier(.45,0,.55,1) infinite;}
@keyframes c2RobotJointIdle{0%,100%{filter:brightness(.9)}50%{filter:brightness(1.25)}}
@keyframes c2RobotJointWork{0%,100%{scale:.96;filter:brightness(1)}50%{scale:1.07;filter:brightness(1.45)}}
@keyframes c2RobotSignal{0%{opacity:0;scale:.1 1}25%{opacity:1}100%{opacity:0;scale:1.1 1}}
@keyframes c2RobotWork{0%,100%{transform:translateY(0) rotate(-1deg)}45%{transform:translateY(-4px) rotate(2.2deg)}70%{transform:translateY(-2px) rotate(.5deg)}}

/* AI — a quiet neural core breathes by default and ignites on hover. */
.cap2--ai .ah-cap2-glyphfx::before{
  inset:39px;border-radius:50%;opacity:.24;
  background:conic-gradient(from 20deg,transparent,var(--acc),var(--aux-cyan),var(--acc),transparent);
  filter:blur(3px);animation:c2AiGlassIdle 3.4s ease-in-out infinite;
}
.cap2--ai .ah-cap2-glyphfx::after{
  inset:24px;border:1px solid color-mix(in srgb,var(--acc) 52%,transparent);border-radius:50%;opacity:.18;
  box-shadow:0 0 14px color-mix(in srgb,var(--acc) 26%,transparent);
}
.cap2--ai:hover .ah-cap2-glyphfx::before{opacity:.72;animation:c2AiGlassCore 1.15s ease-in-out infinite;}
.cap2--ai:hover .ah-cap2-glyphfx::after{opacity:1;animation:c2AiGlassPulse 1.35s ease-out infinite;}
.cap2--ai:hover .ah-cap2-ic img{animation:c2AiGlassObject 1.5s ease-in-out infinite;}
@keyframes c2AiGlassIdle{0%,100%{scale:.88;rotate:-5deg}50%{scale:1.05;rotate:5deg}}
@keyframes c2AiGlassCore{0%,100%{scale:.74;rotate:-10deg;filter:blur(5px)}50%{scale:1.16;rotate:10deg;filter:blur(1px)}}
@keyframes c2AiGlassPulse{0%{scale:.5;opacity:.95}100%{scale:1.38;opacity:0}}
@keyframes c2AiGlassObject{0%,100%{transform:scale(.99)}50%{transform:scale(1.045)}}

/* Data — packets rise through the three transparent processing planes. */
.cap2--data .ah-cap2-glyphfx::before{
  left:47%;top:18%;bottom:21%;width:4px;opacity:.2;
  background:repeating-linear-gradient(180deg,transparent 0 8px,var(--acc) 9px 14px,transparent 15px 20px);
  box-shadow:0 0 11px color-mix(in srgb,var(--acc) 55%,transparent);
  animation:c2DataGlassIdle 2.8s linear infinite;
}
.cap2--data .ah-cap2-glyphfx::after{
  left:20%;right:18%;top:57%;height:2px;opacity:.2;
  background:linear-gradient(90deg,transparent,#fff,var(--acc),#fff,transparent);
}
.cap2--data:hover .ah-cap2-glyphfx::before{opacity:.95;animation:c2DataGlassPackets .82s linear infinite;}
.cap2--data:hover .ah-cap2-glyphfx::after{opacity:.9;animation:c2DataGlassScan 1.18s ease-in-out infinite;}
.cap2--data:hover .ah-cap2-ic img{animation:c2DataGlassObject 1.55s ease-in-out infinite;}
@keyframes c2DataGlassIdle{to{background-position:0 -20px}}
@keyframes c2DataGlassPackets{to{background-position:0 -40px}}
@keyframes c2DataGlassScan{0%,100%{translate:0 -25px;opacity:0}45%{opacity:1}70%{opacity:.8}100%{translate:0 34px;opacity:0}}
@keyframes c2DataGlassObject{0%,100%{transform:translateY(1px)}50%{transform:translateY(-5px)}}

/* Infrastructure — module status lights wake in sequence and connect to the cloud. */
.cap2--infrastructure .ah-cap2-glyphfx::before{
  left:22%;right:27%;top:42%;height:33%;opacity:.2;
  background:
    radial-gradient(circle at 14% 18%,var(--acc) 0 2px,transparent 3px),
    radial-gradient(circle at 51% 44%,var(--acc) 0 2px,transparent 3px),
    radial-gradient(circle at 86% 72%,#8D9900 0 2px,transparent 3px);
  filter:drop-shadow(0 0 5px var(--acc));
  animation:c2InfraStatus 2.4s steps(3,end) infinite;
}
.cap2--infrastructure .ah-cap2-glyphfx::after{
  left:51%;top:22%;width:32%;height:42%;opacity:.18;
  border-top:1.5px solid var(--acc);border-right:1.5px solid var(--acc);border-radius:0 70% 0 0;
  filter:drop-shadow(0 0 6px color-mix(in srgb,var(--acc) 70%,transparent));
}
.cap2--infrastructure:hover .ah-cap2-glyphfx::before{opacity:1;animation:c2InfraStatus .72s steps(3,end) infinite;}
.cap2--infrastructure:hover .ah-cap2-glyphfx::after{opacity:1;animation:c2InfraLink 1.1s ease-in-out infinite;}
.cap2--infrastructure:hover .ah-cap2-ic img{animation:c2InfraObject 1.7s ease-in-out infinite;}
@keyframes c2InfraStatus{0%{filter:brightness(.75)}50%{filter:brightness(1.65)}100%{filter:brightness(.95)}}
@keyframes c2InfraLink{0%,100%{clip-path:inset(0 100% 100% 0)}55%{clip-path:inset(0 0 0 0)}}
@keyframes c2InfraObject{0%,100%{transform:perspective(280px) rotateY(-1deg)}50%{transform:perspective(280px) rotateY(3deg) translateY(-2px)}}

/* Systems — one continuous signal completes the orchestration loop. */
.cap2--systems .ah-cap2-glyphfx::before{
  inset:25px;border:1.5px solid color-mix(in srgb,var(--acc) 48%,transparent);border-radius:50%;opacity:.22;
  background:conic-gradient(from 0deg,transparent 0 70%,color-mix(in srgb,var(--acc) 36%,transparent) 82%,transparent 94%);
  animation:c2SystemsLoop 7s linear infinite;
}
.cap2--systems .ah-cap2-glyphfx::after{
  left:50%;top:24px;width:7px;height:7px;margin-left:-3px;border-radius:50%;opacity:.42;background:var(--acc);
  box-shadow:0 0 11px 2px color-mix(in srgb,var(--acc) 72%,transparent);
  transform-origin:3px 52px;animation:c2SystemsOrbit 4.6s linear infinite;
}
.cap2--systems:hover .ah-cap2-glyphfx::before{opacity:.92;animation-duration:2.2s;}
.cap2--systems:hover .ah-cap2-glyphfx::after{opacity:1;animation-duration:1.15s;}
.cap2--systems:hover .ah-cap2-ic img{animation:c2SystemsObject 1.8s ease-in-out infinite;}
@keyframes c2SystemsLoop{to{rotate:360deg}}
@keyframes c2SystemsOrbit{to{rotate:360deg}}
@keyframes c2SystemsObject{0%,100%{transform:scale(1)}50%{transform:scale(1.035) translateY(-3px)}}

/* Digital engineering — two guide frames converge as the product layers assemble. */
.cap2--engineering .ah-cap2-glyphfx::before,
.cap2--engineering .ah-cap2-glyphfx::after{
  left:27%;top:27%;width:46%;height:46%;border:1.5px solid color-mix(in srgb,var(--acc) 60%,transparent);
  clip-path:polygon(50% 0,100% 27%,100% 73%,50% 100%,0 73%,0 27%);opacity:.2;
}
.cap2--engineering .ah-cap2-glyphfx::after{inset:auto;left:35%;top:35%;width:30%;height:30%;border-style:dashed;}
.cap2--engineering:hover .ah-cap2-glyphfx::before{opacity:.9;animation:c2EngineeringFrame 1.5s ease-in-out infinite;}
.cap2--engineering:hover .ah-cap2-glyphfx::after{opacity:1;animation:c2EngineeringFrame 1.5s ease-in-out -.5s infinite reverse;}
.cap2--engineering:hover .ah-cap2-ic img{animation:c2EngineeringBuild 1.55s cubic-bezier(.45,0,.55,1) infinite;}
@keyframes c2EngineeringFrame{0%,100%{scale:.8;rotate:-7deg}50%{scale:1.1;rotate:7deg}}
@keyframes c2EngineeringBuild{0%,100%{transform:perspective(300px) rotateY(-3deg) translateY(1px)}50%{transform:perspective(300px) rotateY(4deg) translateY(-5px)}}

/* Distinct low-amplitude idle motion keeps the showcase alive without competing with copy. */
.home.motion-v1 .c2-motion-armed .ah-cap2.cap2--robotics.c2-motion-in:not(:hover) .ah-cap2-ic img{animation:c2RobotIdle 5.6s ease-in-out var(--c2-phase,0s) infinite;}
.home.motion-v1 .c2-motion-armed .ah-cap2.cap2--ai.c2-motion-in:not(:hover) .ah-cap2-ic img{animation:c2AiIdle 4.8s ease-in-out var(--c2-phase,0s) infinite;}
.home.motion-v1 .c2-motion-armed .ah-cap2.cap2--data.c2-motion-in:not(:hover) .ah-cap2-ic img{animation:c2DataIdle 5.2s ease-in-out var(--c2-phase,0s) infinite;}
.home.motion-v1 .c2-motion-armed .ah-cap2.cap2--infrastructure.c2-motion-in:not(:hover) .ah-cap2-ic img{animation:c2InfraIdle 5.8s ease-in-out var(--c2-phase,0s) infinite;}
.home.motion-v1 .c2-motion-armed .ah-cap2.cap2--systems.c2-motion-in:not(:hover) .ah-cap2-ic img{animation:c2SystemsIdle 6.2s ease-in-out var(--c2-phase,0s) infinite;}
.home.motion-v1 .c2-motion-armed .ah-cap2.cap2--engineering.c2-motion-in:not(:hover) .ah-cap2-ic img{animation:c2EngineeringIdle 6.4s ease-in-out var(--c2-phase,0s) infinite;}
.home.motion-v1 .c2-motion-armed .ah-cap2.cap2--robotics.c2-motion-in:hover .ah-cap2-ic img{animation:c2RobotWork 1.45s cubic-bezier(.45,0,.55,1) infinite;}
.home.motion-v1 .c2-motion-armed .ah-cap2.cap2--ai.c2-motion-in:hover .ah-cap2-ic img{animation:c2AiGlassObject 1.5s ease-in-out infinite;}
.home.motion-v1 .c2-motion-armed .ah-cap2.cap2--data.c2-motion-in:hover .ah-cap2-ic img{animation:c2DataGlassObject 1.55s ease-in-out infinite;}
.home.motion-v1 .c2-motion-armed .ah-cap2.cap2--infrastructure.c2-motion-in:hover .ah-cap2-ic img{animation:c2InfraObject 1.7s ease-in-out infinite;}
.home.motion-v1 .c2-motion-armed .ah-cap2.cap2--systems.c2-motion-in:hover .ah-cap2-ic img{animation:c2SystemsObject 1.8s ease-in-out infinite;}
.home.motion-v1 .c2-motion-armed .ah-cap2.cap2--engineering.c2-motion-in:hover .ah-cap2-ic img{animation:c2EngineeringBuild 1.55s cubic-bezier(.45,0,.55,1) infinite;}
@keyframes c2RobotIdle{0%,100%{transform:translateY(0) rotate(-.8deg)}50%{transform:translateY(-5px) rotate(.8deg)}}
@keyframes c2InfraIdle{0%,100%{transform:perspective(280px) rotateY(-1.5deg)}50%{transform:perspective(280px) rotateY(2deg) translateY(-3px)}}
@keyframes c2SystemsIdle{0%,100%{transform:translateY(0) rotate(-.6deg)}50%{transform:translateY(-4px) rotate(.6deg)}}
@keyframes c2EngineeringIdle{0%,100%{transform:perspective(300px) rotateY(-2deg)}50%{transform:perspective(300px) rotateY(3deg) translateY(-3px)}}

@media (max-width:600px){
  .home.motion-v1 .c2-motion-armed .ah-cap2 .ah-cap2-ic,
  .ah-cap2-ic{right:8px;top:8px;width:136px;height:136px;}
  .ah-cap2-ic img{width:112px;height:112px;}
}

/* =====================================================================
   CHINESE TYPOGRAPHY V1
   Language-specific rhythm for CJK copy. Content, section order, particle
   field dimensions and the approved English composition remain unchanged.
   ===================================================================== */
html[lang="zh"]{
  /* Helvetica leads here too, so any Latin inside Chinese copy matches the rest of
     the site; the CJK faces behind it still supply the 中文 glyphs. */
  --f-body:Helvetica,'Helvetica Neue',Arial,"PingFang SC","Source Han Sans SC","Hiragino Sans GB","Microsoft YaHei",sans-serif;
  --f-display:Helvetica,'Helvetica Neue',Arial,"PingFang SC","Source Han Sans SC","Hiragino Sans GB","Microsoft YaHei",sans-serif;
}
html[lang="zh"] body{
  font-family:var(--f-body);
  text-rendering:optimizeLegibility;
}

/* CJK weight escalation.
   Accenture pairs EVERY text style with a CJK bump — 451 rules in their stylesheet follow the
   shape `.rad-button{font-weight:500}` + `.rad-button:lang(ja-JP),.rad-button:lang(zh-CN)
   {font-weight:700}`. This theme ships 中文 and 日本語 and had none of it: 35 rules for zh, 2
   for ja, and not one touching weight.

   It is not a stylistic flourish, it is a correction. The Latin face here is Helvetica; the
   CJK glyphs come from the fallbacks behind it — PingFang SC, Hiragino Sans, Microsoft YaHei.
   Those faces are drawn lighter at the same nominal weight than Helvetica is, so a heading set
   at 700 in English arrives visibly thinner in Chinese, and a 600 UI label thinner still. The
   hierarchy the English page has is quietly flattened in the other two languages.

   One step up, not two: 600 -> 700 and 700 -> 800. Body copy is left alone — the fallbacks are
   correctly weighted at 400 and bumping running text would make it heavy rather than even.
   app.js:2304 sets documentElement.lang, so these are live the moment the switcher is used. */
html:is([lang="zh"],[lang="ja"]) :is(
  .h1,.h2,.h3,h1,h2,h3,
  .ah-h1,.pa-index-h1,.cr-hero-title,
  .rc-body h3,.ah-tile h3,.card h3,.ah-cap2 h3,
  .btn,.tab,.nav-item,.mega-head .mt
){font-weight:800;}
html:is([lang="zh"],[lang="ja"]) :is(
  .eyebrow,.rc-tag,.mono,.lab-eyebrow,.ah-cap2-no,
  .lead,.pa-index-lead,.capability-copy
){font-weight:600;}
/* The mono/eyebrow sizes are small and letter-spaced; at those sizes a CJK face needs the
   weight more than the tracking, so the tracking comes off with the bump. */
html:is([lang="zh"],[lang="ja"]) :is(.eyebrow,.rc-tag,.mono,.lab-eyebrow){letter-spacing:.04em;}

/* Header: slightly smaller characters, with more deliberate breathing room. */
html[lang="zh"] .nav-links{
  gap:var(--sp-28);
  font-family:var(--f-body);
  font-size:16.5px;
  font-weight:600;
  letter-spacing:.018em;
}
html[lang="zh"] .nav-item .chev{margin-left:4px;}
html[lang="zh"] :is(.mega-head .mt,.mega-col a,.mega-feature h5,.mobile-menu a,.mobile-menu button.m-link){
  font-family:var(--f-body);
}

/* Hero: "交付" is the lead-in; "超越期待" remains the visual statement. */
html[lang="zh"] .ah-hero-in{
  padding-top:88px;
  padding-bottom:120px;
}
html[lang="zh"] .ah-h1{
  font-family:var(--f-display);
  font-size:clamp(64px,5.7vw,86px);
  font-weight:800;
  line-height:1;
  letter-spacing:.035em;
  text-transform:none;
}
html[lang="zh"] .ah-h1 .ah-hline:first-child{
  font-size:.84em;
  line-height:1;
  letter-spacing:.065em;
}
html[lang="zh"] .ah-h1 .ah-hline:nth-child(2){
  font-size:1.18em;
  line-height:.96;
  letter-spacing:.04em;
  margin-top:.14em;
}
html[lang="zh"] .ah-h1>.ah-accent{
  display:inline-block;
  font-size:1.18em;
  line-height:.96;
  letter-spacing:.04em;
  margin-top:.14em;
}
html[lang="zh"] .ah-h1 .ah-hline .ah-accent{
  font-size:1em;
  margin-top:0;
}
html[lang="zh"] .ah-lead{
  max-width:760px;
  margin-top:31px;
  font-family:var(--f-body);
  font-size:clamp(18px,1.45vw,20px);
  font-weight:500;
  line-height:1.68;
  letter-spacing:.025em;
  color:#46586b;
}
html[lang="zh"] .ah-cta-row{
  gap:var(--sp-16);
  margin-top:34px;
}
html[lang="zh"] .ah-cta-row .ah-btn{
  min-width:168px;
  min-height:62px;
  justify-content:center;
  padding:16px 28px;
  font-family:var(--f-body);
  font-size:17px;
  font-weight:650;
  letter-spacing:.055em;
}
html[lang="zh"] .ah-cta-row .ah-btn-ghost{min-width:156px;}

/* Interior Chinese headings keep phrases intact and avoid dense Latin spacing. */
html[lang="zh"] .interior-v2 :is(.h1,.h2,.ct-title,.cr-hero-title){
  font-family:var(--f-display);
  font-weight:750;
  letter-spacing:.015em;
  word-break:keep-all;
  overflow-wrap:normal;
  text-wrap:balance;
}
html[lang="zh"] .interior-v2 :is(.lead,p,li){
  letter-spacing:.012em;
}

@media (max-width:720px){
  html[lang="zh"] .ah-hero-in{
    padding-top:70px;
    padding-bottom:82px;
  }
  html[lang="zh"] .ah-h1{
    font-size:clamp(42px,11.4vw,56px);
    letter-spacing:.025em;
  }
  html[lang="zh"] .ah-h1 .ah-hline:first-child{font-size:.86em;}
  html[lang="zh"] .ah-h1 .ah-hline:nth-child(2),
  html[lang="zh"] .ah-h1>.ah-accent{font-size:1.14em;}
  html[lang="zh"] .ah-h1 .ah-hline .ah-accent{font-size:1em;}
  html[lang="zh"] .ah-lead{
    max-width:22em;
    margin-top:25px;
    font-size:17px;
    line-height:1.65;
  }
  html[lang="zh"] .ah-cta-row{
    margin-top:29px;
    gap:var(--sp-12);
  }
  html[lang="zh"] .ah-cta-row .ah-btn{
    min-width:0;
    min-height:56px;
    padding:14px 23px;
    font-size:16px;
  }
}

/* =====================================================================
   SUBPAGE HERO ART DIRECTION V4
   Client-supplied hero language: dark technology field, left-aligned copy,
   restrained motion and official Beyondsoft colour accents.
   ===================================================================== */
/* Article variant of the AI family. The AI Solutioning page's own artwork is an
   8.4MB, 7973px PNG — right for one signed-off page, wrong to put on 27 article
   pages, so those get a 3840px WebP cut of it at the theme's normal hero size.
   The page itself keeps the original untouched. */
.interior-v2.bs-hero-ai-article{
  --bs-hero-art:url("img/hero-ai-article.webp");
  --bs-hero-accent:var(--aux-red);
  --bs-hero-accent-rgb:244,37,52;
}
.interior-v2.bs-hero-ai{
  /* hero-ai.webp, not hero-ai-exact.png. The PNG is 7973x2717 and 8.64 MB, and this token is
     live: /solution-generative-ai/ carries .bs-hero-ai and renders class="page-hero", which is
     the one selector that consumes var(--bs-hero-art) — so every visit to that page downloaded
     8.6 MB for a background. The server confirms Content-Length: 8644742.

     The webp is the same artwork at 3840x1309 and 0.50 MB — 17x lighter. Compared pixel by
     pixel after scaling both to a common width, the mean difference is 3.6/765, i.e. 0.5%.
     page-service-ai-solutioning.php had already reached this conclusion and says so in a
     comment at line 8; the token was simply never brought along. */
  --bs-hero-art:url("img/hero-ai.webp");
  --bs-hero-accent:var(--aux-red);
  --bs-hero-accent-rgb:244,37,52;
}
.interior-v2.bs-hero-insights{
  --bs-hero-art:url("img/hero-insights-v2.webp");
  --bs-hero-accent:var(--aux-purple);
  --bs-hero-accent-rgb:144,71,153;
}
.interior-v2.bs-hero-media{
  --bs-hero-art:url("img/hero-media.webp");
  --bs-hero-accent:var(--blue);
  --bs-hero-accent-rgb:0,138,171;
}
.interior-v2.bs-hero-data{
  --bs-hero-art:url("img/hero-data.webp");
  --bs-hero-accent:#FF9E16;
  --bs-hero-accent-rgb:255,158,22;
}
.interior-v2.bs-hero-robotics{
  --bs-hero-art:url("img/hero-infrastructure.webp");
  --bs-hero-accent:var(--aux-cyan);
  --bs-hero-accent-rgb:59,176,201;
}
.interior-v2.bs-hero-systems{
  --bs-hero-art:url("img/hero-systems.webp");
  --bs-hero-accent:#FFCE00;
  --bs-hero-accent-rgb:255,206,0;
}
.interior-v2.bs-hero-infrastructure{
  --bs-hero-art:url("img/hero-infrastructure.webp");
  --bs-hero-accent:var(--aux-cyan);
  --bs-hero-accent-rgb:59,176,201;
}

.interior-v2 .page-hero{
  /* min-height removed: the shell rule further down owns it now. */
  padding:clamp(96px,11vw,150px) 0 clamp(76px,9vw,118px);
  isolation:isolate;
  color:#fff;
  background-color:#0b213a;
  background-image:
    linear-gradient(90deg,rgba(var(--ground-rgb),.97) 0%,rgba(var(--ground-rgb),.88) 37%,rgba(5,23,42,.54) 66%,rgba(5,23,42,.14) 100%),
    var(--bs-hero-art);
  background-repeat:no-repeat;
  background-position:center,center;
  background-size:cover,cover;
  animation:bsSubpageHeroDrift 16s ease-in-out infinite alternate;
}
.interior-v2 .page-hero::before{
  z-index:0;
  opacity:.48;
  background:
    radial-gradient(circle at 73% 34%,rgba(var(--white-rgb),.92) 0 1px,transparent 5px),
    radial-gradient(circle at 86% 62%,rgba(var(--bs-hero-accent-rgb),.86) 0 2px,transparent 7px),
    radial-gradient(circle at 62% 78%,rgba(var(--cyan-rgb),.84) 0 1px,transparent 6px);
  background-size:100% 100%,100% 100%,100% 100%;
  -webkit-mask-image:none;
          mask-image:none;
  animation:bsSubpageSignal 5.8s ease-in-out infinite alternate;
}
/* (.page-hero::after removed with the watermark cleanup — this override is retired.) */
.interior-v2 .page-hero>.container{
  position:relative;
  z-index:2;
  width:100%;
  padding-top:0;
  padding-bottom:0;
}
.interior-v2 .page-hero .glow{display:none;}
.interior-v2 .page-hero .h1{
  width:min(100%,940px);
  max-width:940px!important;
  color:var(--hero-ink,#fff);
  font-size:clamp(44px,5.4vw,76px);
  line-height:1.01;
  letter-spacing:-.042em;
  overflow:visible;
  overflow-wrap:anywhere;
  word-break:normal;
  text-wrap:balance;
}
.interior-v2 .page-hero .lead{
  max-width:690px!important;
  color:var(--hero-lead-ink,rgba(var(--white-rgb),.94));
}
.interior-v2 .page-hero .mono{color:rgba(var(--white-rgb),.66)!important;}
.interior-v2 .page-hero .grad-text{
  background:var(--bs-hero-accent);
  -webkit-background-clip:text;
          background-clip:text;
  color:transparent;
}
.interior-v2 .page-hero .btn-primary{
  background:var(--bs-hero-accent);
  color:#fff;
  box-shadow:0 18px 36px -20px rgba(var(--bs-hero-accent-rgb),.72);
}
.interior-v2.bs-hero-data .page-hero .btn-primary,
.interior-v2.bs-hero-systems .page-hero .btn-primary{color:#26292C;}
.interior-v2 .page-hero .btn-ghost{
  color:#fff;
  border-color:rgba(var(--white-rgb),.42);
  background:rgba(var(--ground-rgb),.18);
}
.interior-v2 .page-hero .btn-ghost:hover{
  color:#fff;
  border-color:rgba(var(--white-rgb),.72);
  background:rgba(var(--ground-rgb),.36);
}

/* Contact uses the same full-width hero field while keeping its editable form. */
.interior-v2.pg-contact .ct-wrap{
  position:relative;
  isolation:isolate;
  width:100%;
  max-width:1240px;
  box-sizing:border-box;
}
.interior-v2.pg-contact .ct-wrap::before{
  background:
    linear-gradient(90deg,rgba(var(--ground-rgb),.97),rgba(var(--ground-rgb),.86) 42%,rgba(3,20,62,.40)),
    var(--bs-hero-art) center/cover no-repeat;
}
.interior-v2.pg-contact .ct-head{position:relative;z-index:1;}
.interior-v2.pg-contact .ct-title{color:#fff;max-width:900px;overflow-wrap:anywhere;}
.interior-v2.pg-contact .ct-blurb{color:rgba(var(--white-rgb),.82);}
.interior-v2.pg-contact .ct-grid{position:relative;z-index:1;}

/* Long English and Chinese headings must always remain inside the viewport. */
.interior-v2 :is(.page-hero,.hero-image,.cr-hero) .h1,
.interior-v2>section.hero .h1,
.interior-v2 .ct-title{
  max-width:100%;
  overflow-wrap:anywhere;
  word-break:normal;
}
html[lang="zh"] .interior-v2 :is(.page-hero,.hero-image,.cr-hero) .h1,
html[lang="zh"] .interior-v2>section.hero .h1,
html[lang="zh"] .interior-v2 .ct-title{
  letter-spacing:0;
  line-height:1.12;
  /* NOT break-all. That was here to let a long Chinese headline wrap, but Chinese wraps
     between characters under `normal` anyway — break-all adds nothing for CJK and instead
     licenses breaks INSIDE Latin words, which is a real problem on this site: the case
     studies and press pieces carry English headlines with no Chinese translation, so on
     the Chinese site they were being split mid-word ("Beyondsoft's FDE Mode|l Unlocks
     Scalable Fina|ncial AI Across Borders"). overflow-wrap:anywhere keeps the safety net
     for a single unbreakable string longer than the column. */
  word-break:normal;
  overflow-wrap:anywhere;
}

@keyframes bsSubpageHeroDrift{
  0%{background-position:center,50% 50%;}
  100%{background-position:center,52% 47%;}
}
@keyframes bsSubpageSignal{
  0%{background-position:center,center,center,center;opacity:.24;filter:brightness(.86);}
  100%{background-position:center,center,center,center;opacity:.58;filter:brightness(1.28);}
}

/* Responsive safeguards found during the complete subpage audit. */
@media (max-width:720px){
  .interior-v2 .page-hero{
    min-height:500px;
    padding:82px 0 72px;
    background-position:center,62% center;
    animation-duration:20s;
  }
  .interior-v2 .page-hero>.container,
  .interior-v2 .hero-image>.container,
  .interior-v2 .cr-hero>.container{
    width:100%;
    max-width:100%;
    box-sizing:border-box;
    overflow:hidden;
  }
  .interior-v2 .page-hero .h1,
  .interior-v2 .hero-image .h1,
  .interior-v2 .cr-hero .h1{
    width:100%;
    max-width:100%!important;
    font-size:clamp(37px,10.4vw,52px);
    line-height:1.04;
  }
  html[lang="zh"] .interior-v2 .page-hero .h1,
  html[lang="zh"] .interior-v2 .hero-image .h1,
  html[lang="zh"] .interior-v2 .cr-hero .h1{
    font-size:clamp(36px,10vw,48px);
    line-height:1.14;
  }
  .interior-v2.pg-contact .ct-wrap{
    width:100%;
    max-width:100%;
    padding-left:var(--pad);
    padding-right:var(--pad);
    overflow:hidden;
  }
  .interior-v2.pg-contact .ct-head,
  .interior-v2.pg-contact .ct-grid,
  .interior-v2.pg-contact .ct-card,
  .interior-v2.pg-contact .ct-panel{
    width:100%;
    max-width:100%;
    min-width:0;
    box-sizing:border-box;
  }
  .interior-v2.pg-contact .ct-title{
    width:100%;
    font-size:clamp(38px,11vw,52px);
  }
  .interior-v2 .ah-ai-in{width:100%;max-width:100%;padding-inline:var(--pad);box-sizing:border-box;}
  .interior-v2 .ah-ai-in h2{max-width:100%;overflow-wrap:anywhere;}
  .ah-ai{min-height:520px;padding:88px 0 96px;}
  .ptable{min-width:0;width:100%;font-size:12px;table-layout:fixed;}
  .ptable th,.ptable td{padding:10px 8px;overflow-wrap:anywhere;}
}

@media (prefers-reduced-motion:reduce){
  .interior-v2 .page-hero,
  .interior-v2 .page-hero::before{animation:none;}
}

/* =====================================================================
   SUBPAGE HERO MOTION V2 — stronger art movement, signal sweep and
   one-time content staging. Applied to the actual first hero on every
   interior page without replacing editable content or imagery.
   ===================================================================== */
.interior-v2 .sp-motion{
  --sp-x:0px;
  --sp-y:0px;
  isolation:isolate;
}

/* page-hero artwork is promoted to a real layer so pointer and idle depth
   can move independently of the copy. */
.interior-v2 .page-hero.sp-motion{
  background-image:linear-gradient(90deg,rgba(var(--ground-rgb),.97) 0%,rgba(var(--ground-rgb),.88) 37%,rgba(5,23,42,.54) 66%,rgba(5,23,42,.14) 100%);
  animation:none;
}
.interior-v2 .page-hero.sp-motion::before{z-index:1;}
.sp-motion-art{
  position:absolute;
  inset:-5%;
  z-index:0;
  pointer-events:none;
  background:var(--bs-hero-art) center/cover no-repeat;
  translate:var(--sp-x) var(--sp-y);
  scale:1.07;
  transition:translate var(--dur-fast) linear;
  will-change:translate,scale;
}
.sp-motion-art::after{
  content:"";
  position:absolute;
  inset:0;
  background:
    linear-gradient(90deg,rgba(var(--ground-rgb),.97) 2%,rgba(var(--ground-rgb),.86) 39%,rgba(5,23,42,.48) 68%,rgba(5,23,42,.10) 100%),
    radial-gradient(60% 88% at 82% 28%,rgba(var(--bs-hero-accent-rgb),.20),transparent 72%);
}

/* Photographic heroes retain their real <img>; the whole background plane
   receives pointer depth while the existing scroll parallax keeps working. */
.interior-v2 .hero-image.sp-motion:not(.capability-hero) .bg{
  inset:-3%;
  translate:var(--sp-x) var(--sp-y);
  scale:1.035;
  transition:translate var(--dur-fast) linear;
  will-change:translate,scale;
}

.sp-motion-field{
  position:absolute;
  inset:0;
  z-index:1;
  overflow:hidden;
  pointer-events:none;
  opacity:0;
  translate:var(--sp-fx-x,0) var(--sp-fx-y,0);
  transition:opacity var(--dur-slow) var(--ease) .18s,translate var(--dur-fast) linear;
}
.sp-motion-in .sp-motion-field{opacity:1;}
.sp-motion-field i{position:absolute;display:block;pointer-events:none;}
/* No sweep light: two slow orbital planes create continuous spatial motion
   without sending a bright band across the copy. */
.sp-motion-orbit{
  right:clamp(0%,5vw,7%);
  top:50%;
  width:clamp(260px,35vw,540px);
  height:clamp(150px,20vw,300px);
  border:1px solid rgba(var(--bs-hero-accent-rgb),.24);
  border-left-color:rgba(var(--white-rgb),.36);
  border-right-color:rgba(var(--bs-hero-accent-rgb),.08);
  border-radius:50%;
  transform:translateY(-50%) rotateX(62deg) rotateZ(-12deg);
  transform-style:preserve-3d;
  animation:spHeroOrbit 16s linear infinite;
}
.sp-motion-orbit::before,
.sp-motion-orbit::after{
  content:"";
  position:absolute;
  width:9px;
  height:9px;
  border-radius:50%;
  background:var(--bs-hero-accent);
  box-shadow:0 0 0 5px rgba(var(--bs-hero-accent-rgb),.12),0 0 20px rgba(var(--bs-hero-accent-rgb),.66);
}
.sp-motion-orbit::before{left:8%;top:21%;}
.sp-motion-orbit::after{right:10%;bottom:20%;background:#fff;}
.sp-motion-orbit-b{
  width:clamp(210px,28vw,430px);
  height:clamp(125px,17vw,250px);
  right:clamp(8%,12vw,15%);
  border-color:rgba(var(--white-rgb),.14);
  border-top-color:rgba(var(--bs-hero-accent-rgb),.36);
  transform:translateY(-50%) rotateX(68deg) rotateZ(28deg);
  animation-duration:22s;
  animation-direction:reverse;
}
.sp-motion-ring{
  right:clamp(4%,8vw,10%);
  top:50%;
  width:clamp(210px,28vw,430px);
  aspect-ratio:1;
  border:1px solid rgba(var(--bs-hero-accent-rgb),.34);
  border-radius:50%;
  translate:0 -50%;
  box-shadow:
    0 0 0 1px rgba(var(--white-rgb),.06) inset,
    0 0 40px rgba(var(--bs-hero-accent-rgb),.09);
  animation:spHeroRing 4.4s ease-out infinite;
}
.sp-motion-ring-b{
  animation-delay:2.2s;
}
.sp-motion-node{
  width:8px;
  height:8px;
  border-radius:50%;
  background:#fff;
  box-shadow:
    0 0 0 5px rgba(var(--bs-hero-accent-rgb),.15),
    0 0 22px 7px rgba(var(--bs-hero-accent-rgb),.55);
  animation:spHeroNode 2.4s ease-in-out infinite alternate,spHeroFloat 7s ease-in-out infinite;
}
.sp-motion-node-a{right:17%;top:24%;}
.sp-motion-node-b{right:8%;top:61%;animation-delay:.7s;}
.sp-motion-node-c{right:31%;top:78%;animation-delay:1.35s;}
.sp-motion-node-d{right:42%;top:37%;width:5px;height:5px;animation-delay:1.8s,-2.2s;}
.sp-motion-node-e{right:25%;top:52%;width:6px;height:6px;animation-delay:.35s,-4.1s;}

/* Remove every legacy scan line from the capability-specific treatments.
   The image breathing, packets, nodes and new orbital field stay active. */
.capability-hero .ch-scan{display:none!important;}

/* Stronger first-view choreography: art arrives first, then title, copy,
   actions. Longhand translate/scale avoids fighting the existing reveal
   transform and remains safe when clients edit the text. */
.interior-v2 .sp-motion .h1{
  opacity:0;
  translate:-58px 0;
  scale:.975;
  filter:blur(10px);
  transition:opacity var(--dur-slow) var(--ease-out) .12s,
    translate var(--dur-slow) var(--ease-out) .12s,
    scale var(--dur-slow) var(--ease-out) .12s,
    filter var(--dur-slow) var(--ease-out) .12s;
}
.interior-v2 .sp-motion .lead{
  opacity:0;
  translate:-34px 0;
  filter:blur(7px);
  transition:opacity var(--dur-base) var(--ease-out) .34s,
    translate var(--dur-slow) var(--ease-out) .34s,
    filter var(--dur-base) var(--ease-out) .34s;
}
.interior-v2 .sp-motion .h1 + .lead + *,
.interior-v2 .sp-motion .lead + form{
  opacity:0;
  translate:0 24px;
  transition:opacity var(--dur-base) var(--ease-out) .56s,translate var(--dur-slow) var(--ease-out) .56s;
}
.interior-v2 .sp-motion-in .h1,
.interior-v2 .sp-motion-in .lead,
.interior-v2 .sp-motion-in .h1 + .lead + *,
.interior-v2 .sp-motion-in .lead + form{
  opacity:1;
  translate:0 0;
  scale:1;
  filter:blur(0);
}

@keyframes spHeroOrbit{
  from{rotate:0deg;}
  to{rotate:360deg;}
}
@keyframes spHeroRing{
  0%{scale:.58;opacity:0;}
  18%{opacity:.66;}
  100%{scale:1.24;opacity:0;}
}
@keyframes spHeroNode{
  0%{opacity:.32;scale:.68;}
  100%{opacity:1;scale:1.24;}
}
@keyframes spHeroFloat{
  0%,100%{translate:0 0;}
  35%{translate:-10px 13px;}
  68%{translate:9px -11px;}
}

@media (max-width:720px){
  .sp-motion-ring{right:-18%;width:280px;}
  .sp-motion-orbit{right:-24%;width:330px;height:190px;}
  .sp-motion-orbit-b{right:-7%;width:250px;height:145px;}
  .sp-motion-node-a{right:12%;}
  .sp-motion-node-c{display:none!important;}
  .sp-motion-node-d{display:none!important;}
  .interior-v2 .sp-motion .h1{translate:-28px 0;filter:blur(6px);}
  .interior-v2 .sp-motion .lead{translate:-18px 0;filter:blur(4px);}
  .sp-motion-art{scale:1.04;animation-duration:15s;}
}

@media (prefers-reduced-motion:reduce){
  .sp-motion-art,
  .interior-v2 .hero-image.sp-motion:not(.capability-hero) .bg{
    translate:0 0!important;
    scale:1.03;
    animation:none!important;
  }
  .sp-motion-field{display:none!important;}
  .interior-v2 .sp-motion .h1,
  .interior-v2 .sp-motion .lead,
  .interior-v2 .sp-motion .h1 + .lead + *,
  .interior-v2 .sp-motion .lead + form{
    opacity:1!important;
    translate:0 0!important;
    scale:1!important;
    filter:none!important;
    transition:none!important;
  }
}

/* =====================================================================
   REFERENCE-MATCHED SUBPAGE HERO
   Matches the supplied 1913 × 652 layouts: full artwork, broad left copy
   column, large Helvetica typography and pill CTAs. No invented orbit,
   sweep or decorative field is layered over the designer artwork.
   ===================================================================== */
/* THE hero shell. Everything below in this block is the one in force — the four earlier
   attempts at this (V3, its exemption, V4, and this) each left their losing rules in the file,
   which is how the same set of heroes came to carry eighteen min-height declarations between
   380px and 660px. The seven superseded top-level ones are now deleted rather than out-ranked;
   the six inside @media are responsive and stay.

   Heights are NOT touched. An earlier pass folded .independent-hero and .cr-hero in here too,
   which shortened the five independent-page heroes by 140px and the careers hero by 130px at
   1440 — a visible change nobody asked for. Both keep their own heights below; what this
   block does is own the height for .page-hero and .hero-image, which it already did, and let
   the eleven superseded declarations be deleted instead of merely out-ranked. */
/* Fixed, not a floor. min-height was only ever a floor, so what actually set each hero's
   height was its own copy: 30 pages all declaring min-height:520px rendered anywhere from
   520px to 697px at 1440, a 177px spread, and the spread was there at every width measured
   (122px at 1024, 167px at 1280, 116px at 1920). Two heroes side by side in a deck looked
   like two different templates, which is what the client kept seeing.

   The curve is /service-cloud/'s own, measured: 520 / 552 / 577 / 685 at 1024 / 1280 / 1440
   / 1920. 286px + 20.8vw runs through it (+8px at 1440, exact at the other three), so the
   page the client pointed at as correct keeps its height and every other page comes to it.

   Paired with the container rule below: the container is bottom-aligned with its 40px pad
   instead of stretched under a fixed top pad, so /service-cloud/'s copy lands on the same
   pixel it does today, and a page with more copy grows UPWARD into the space that used to
   be top padding rather than growing the box. That is the whole mechanism — the tallest
   content column on the site is 547px, comfortably inside the box; it was the 109px of
   top padding underneath it that pushed the total past the floor. */
.interior-v2 :is(.page-hero,.hero-image){
  height:clamp(520px,286px + 20.8vw,720px);
  min-height:0;
}
/* Restored to what they were before the unification pass. */
.independent-hero{min-height:clamp(500px,57vw,660px);}
.interior-v2 .cr-hero{min-height:clamp(500px,57vw,650px);}
.interior-v2 .page-hero{padding:0;}
.interior-v2 :is(.page-hero,.hero-image)>.container{
  --maxw:1920px;
  --pad:clamp(38px,6.2vw,119px);
  width:100%;
  max-width:1920px;
  padding-left:var(--pad);
  padding-right:var(--pad);
  /* was: padding-top:clamp(80px,7.6vw,146px) + align-self:stretch. The stretch made the
     container as tall as the hero and the top pad then pushed the copy down; together they
     meant a long headline had nowhere to go but downward, taking the hero with it. Bottom
     alignment reproduces the same resting position from the other end. */
  padding-top:0;
  padding-bottom:40px;
  align-self:flex-end;
  translate:none;
}
.interior-v2 :is(.page-hero,.hero-image) .h1{
  width:min(100%,980px);
  max-width:980px!important;
  font-size:clamp(52px,4.3vw,82px);
  line-height:1.01;
  letter-spacing:-.044em;
  text-wrap:balance;
}
.interior-v2 :is(.page-hero,.hero-image) .lead{
  width:min(100%,860px);
  max-width:860px!important;
  margin:18px 0 34px!important;
  font-size:clamp(20px,1.46vw,28px);
  line-height:1.2;
  color:rgba(var(--white-rgb),.94);
}
.interior-v2 :is(.page-hero,.hero-image) .btn{
  min-width:0;
  height:46px;
  padding:0 36px;
  border-radius:999px;
  font-size:clamp(16px,1vw,19px);
  line-height:1;
}
.interior-v2 :is(.page-hero,.hero-image) .lead + *{
  gap:var(--sp-32)!important;
}
.interior-v2 :is(.page-hero,.hero-image) .btn-ghost{
  border-width:1.5px;
  background:rgba(var(--ground-rgb),.06);
}

/* The supplied backgrounds already include their intended dark/light field.
   Keep only a nearly invisible legibility veil instead of recolouring them. */
.interior-v2 .capability-hero .bg::after{
  background:linear-gradient(90deg,rgba(var(--ground-rgb),.08),rgba(var(--ground-rgb),.025) 48%,transparent 72%)!important;
}
.sp-motion-art::after{
  background:linear-gradient(90deg,rgba(var(--ground-rgb),.10),rgba(var(--ground-rgb),.025) 48%,transparent 72%);
}

/* Cloud and Systems take new artwork, and it breaks the assumption the veil above rests on.

   That rule drops every per-page hero scrim to an 8% veil, with !important, because the
   client's original banners each carried their own dark field on the left where the
   headline sits. The two new images do not: measured white-on-ground under the h1, Cloud
   came out at 2.35:1 against a bright teal (2,187,201) and Systems at 2.04:1 against a
   cyan (73,195,234) — both under the 3:1 a display headline needs.

   So the field those two lost is put back, and only for them. Every other capability hero
   still carries the veil and its own built-in field, untouched. Keyed off the body class
   and not off .capability-hero--infrastructure, which /service-app-engineering/ also
   carries — that page kept its original artwork and must keep the veil with it. If either
   page is ever given artwork with its own dark left field again, delete its selector here
   rather than weakening the gradient. */
body.pg-service-cloud.interior-v2 .capability-hero .bg::after,
body.pg-systems.interior-v2 .capability-hero .bg::after{
  background:linear-gradient(90deg,
    rgba(4,18,36,.90) 0%,
    rgba(4,18,36,.68) 44%,
    rgba(4,18,36,.26) 72%,
    rgba(4,18,36,0) 100%)!important;
}

/* The previously explored orbital layer is intentionally absent in the
   reference-matched treatment. */
.sp-motion-field{display:none!important;}

/* Exact accent sampled from the supplied Untitled-3-01 reference. */
.interior-v2 .capability-hero--systems .grad-text{
  background:#5080C0;
  -webkit-background-clip:text;
          background-clip:text;
}
.interior-v2 .capability-hero--systems .btn-primary,
.interior-v2.bs-hero-systems .page-hero .btn-primary{
  background:#5080C0;
  color:#fff;
  box-shadow:0 14px 30px -18px rgba(80,128,192,.82);
}
.interior-v2 .capability-hero--systems .btn-primary:hover,
.interior-v2.bs-hero-systems .page-hero .btn-primary:hover{
  background:#3F70B2;
}

/* Exact client AI artwork. No crop, recolour, idle zoom or pointer drift is
   applied on desktop. Only the luminous cyan/pink points are extracted into
   six registered layers and switched fully off/on. */
.capability-hero--ai .ch-art{
  inset:0;
  opacity:1;
  scale:1;
  translate:0 0!important;
  animation:none;
  transition:none;
}
.capability-hero--ai .ch-art>img,
.interior-v2 .capability-hero--ai .ch-art .ch-ai-light-map{
  top:0;
  left:0;
  width:100%;
  height:100%;
  object-fit:cover;
  object-position:center;
  transform:none!important;
}
.capability-hero--ai .ch-art>img:not(.ch-ai-light-map){
  filter:saturate(1.16) contrast(1.045);
}
.capability-hero--ai .ch-fx{display:none!important;}
.interior-v2 .capability-hero--ai .ch-art .ch-ai-light-map{
  position:absolute;
  z-index:2;
  pointer-events:none;
  opacity:0;
  mix-blend-mode:screen;
  will-change:opacity,filter;
  filter:
    brightness(2.35)
    contrast(1.18)
    saturate(1.38)
    drop-shadow(0 0 10px rgba(255,63,154,.95))
    drop-shadow(0 0 22px rgba(74,181,255,.90));
  animation:chAiLightSwitch 6s steps(1,end) infinite;
}
.interior-v2 .capability-hero--ai .ch-ai-light-map:nth-of-type(2){animation-delay:0s;}
.interior-v2 .capability-hero--ai .ch-ai-light-map:nth-of-type(3){animation-delay:-5s;}
.interior-v2 .capability-hero--ai .ch-ai-light-map:nth-of-type(4){animation-delay:-4s;}
.interior-v2 .capability-hero--ai .ch-ai-light-map:nth-of-type(5){animation-delay:-3s;}
.interior-v2 .capability-hero--ai .ch-ai-light-map:nth-of-type(6){animation-delay:-2s;}
.interior-v2 .capability-hero--ai .ch-ai-light-map:nth-of-type(7){animation-delay:-1s;}
@keyframes chAiLightSwitch{
  0%,1.9%{opacity:0;}
  2%,12.8%{opacity:1;}
  12.9%,100%{opacity:0;}
}

@media (max-width:720px){
  .interior-v2 :is(.page-hero,.hero-image){
    min-height:520px;
  }
  .interior-v2 :is(.page-hero,.hero-image)>.container{
    --pad:28px;
    padding-top:78px;
    padding-bottom:48px;
    translate:none;
  }
  .interior-v2 :is(.page-hero,.hero-image) .h1{
    font-size:clamp(40px,11vw,54px);
    line-height:1.03;
  }
  .interior-v2 :is(.page-hero,.hero-image) .lead{
    font-size:18px;
    line-height:1.42;
    margin:18px 0 28px!important;
  }
  .interior-v2 :is(.page-hero,.hero-image) .lead + *{
    gap:var(--sp-12)!important;
  }
  .interior-v2 :is(.page-hero,.hero-image) .btn{
    height:46px;
    padding:0 20px;
    font-size:15px;
  }
  .interior-v2 .capability-hero--ai .ch-art .ch-ai-light-map{
    animation-duration:6s;
  }
}

@media (prefers-reduced-motion:reduce){
  .interior-v2 .capability-hero--ai .ch-art .ch-ai-light-map{
    opacity:.42;
    animation:none!important;
    filter:brightness(1.3) saturate(1.1) drop-shadow(0 0 7px rgba(112,196,255,.66));
  }
}

/* =====================================================================
   ROBOTICS — standalone capability hero
   Deep connected-systems field + the approved blue-glass robot arm.
   Joint signals switch on/off; orbital lines provide mechanical depth
   without a sweeping-light effect.
   ===================================================================== */
.interior-v2 .capability-hero--robotics{
  background:#071a33;
}
.interior-v2 .capability-hero--robotics>.container{
  z-index:5;
  width:100%;
}
.interior-v2 .capability-hero--robotics .h1{
  max-width:690px!important;
}
.interior-v2 .capability-hero--robotics .lead{
  max-width:640px!important;
}
/* Gold, the banner's own hue, replacing a cyan that matched nothing in the picture.
   The artwork's gold measures #A97036, but as type on this purple that is 2.58:1 —
   fine as a button fill under white text, far too dark to be the text itself. These
   three stops are the same hue lifted until the word clears its background: 6.64,
   5.83 and 4.76:1 against the rgb(93,42,95) the headline sits on. */
/* The gold headline gradient and gold button went with the gold banner — the artwork here is
   now brand blue, so both fall back to the site's own .grad-text and .btn-primary. The dark
   scrim below stays: it is what keeps the headline legible over the artwork, and it is a
   neutral navy that suits this banner as well as it suited the last one. */
/* Gold, taken from the banner rather than from the site palette. The button used to
   be the theme's teal on a purple-and-gold picture, which belonged to no part of it.
   #A97036 is the median of the artwork's bright saturated pixels; #9E6932 is that
   colour walked down until white type clears 4.5:1 on it (4.65:1), and the darker
   stop continues the same hue rather than turning to another one. */

/* Hover goes darker, not lighter. Brightening a gold this saturated drops white type
   under 4.5:1 — #B07B3C measured 3.66:1 — so the hover deepens instead. */

/* No scrim on this hero, at the client's call: the plate shows as supplied.

   It used to carry a left-to-right wash — .88 of --ground at the left edge falling to .08
   at the right — which is what made the artwork's blue read as dark navy under the copy.
   Removed, so this hero falls back to the shared .interior-v2 .capability-hero .bg::after
   veil (8%), the same one every capability page whose artwork carries its own dark field
   already uses.

   Recorded for whoever reads this next: white type over the bare plate measures 3.10:1 on
   the h1 and 3.21:1 on the lead at 1440. The h1 clears the 3:1 large-text floor; the lead
   is normal-size text and does not clear 4.5:1. The fix, if it is ever wanted, is a plate
   with a darker left third rather than a heavier wash here. */
.capability-hero--robotics .ch-fx{display:none!important;}
.robotics-hero-visual{
  position:absolute;
  z-index:4;
  top:50%;
  right:clamp(42px,7vw,132px);
  width:clamp(290px,27vw,430px);
  aspect-ratio:1;
  translate:0 -50%;
  pointer-events:none;
  filter:drop-shadow(0 34px 40px rgba(0,16,58,.42));
  animation:roboticsHeroFloat 5.2s ease-in-out infinite;
}
.robotics-hero-visual::before,
.robotics-hero-visual::after{
  content:"";
  position:absolute;
  border-radius:50%;
  pointer-events:none;
}
.robotics-hero-visual::before{
  inset:9%;
  background:radial-gradient(circle,rgba(var(--cyan-rgb),.18),rgba(var(--blue-rgb),.05) 48%,transparent 71%);
  filter:blur(4px);
  animation:roboticsCorePulse 2.4s steps(2,end) infinite;
}
.robotics-hero-visual::after{
  inset:18%;
  border:1px dashed rgba(85,194,221,.34);
  box-shadow:0 0 26px rgba(var(--cyan-rgb),.12),inset 0 0 22px rgba(var(--cyan-rgb),.08);
  animation:roboticsOrbitSpin 15s linear infinite reverse;
}
.robotics-hero-visual>img{
  position:absolute;
  z-index:3;
  inset:8%;
  width:84%;
  height:84%;
  object-fit:contain;
  border:1px solid rgba(155,221,240,.58);
  border-radius:28px;
  background:rgba(244,251,255,.94);
  box-shadow:0 30px 62px -24px rgba(0,23,80,.72),inset 0 0 26px rgba(var(--cyan-rgb),.10);
  mix-blend-mode:normal;
  filter:contrast(1.06) saturate(1.20) brightness(1.02) drop-shadow(0 20px 22px rgba(0,70,160,.26));
  animation:roboticsArmPulse 3.6s steps(2,end) infinite;
}
.robotics-hero-orbit{
  position:absolute;
  z-index:2;
  inset:2%;
  border:1px solid rgba(85,194,221,.30);
  border-radius:50%;
  transform:rotateX(68deg) rotateZ(-12deg);
  box-shadow:0 0 24px rgba(var(--cyan-rgb),.10);
  animation:roboticsOrbitSpin 11s linear infinite;
}
.robotics-hero-orbit::before,
.robotics-hero-orbit::after{
  content:"";
  position:absolute;
  width:9px;
  height:9px;
  border-radius:50%;
  background:#55C2DD;
  box-shadow:0 0 8px 3px rgba(85,194,221,.76);
}
.robotics-hero-orbit::before{left:12%;top:16%;}
.robotics-hero-orbit::after{right:8%;bottom:22%;animation-delay:-1.2s;}
.robotics-hero-orbit--inner{
  inset:16%;
  border-style:dashed;
  opacity:.72;
  transform:rotateX(72deg) rotateZ(24deg);
  animation-duration:8.5s;
  animation-direction:reverse;
}
.robotics-hero-node{
  position:absolute;
  z-index:5;
  width:12px;
  height:12px;
  border:2px solid rgba(var(--white-rgb),.88);
  border-radius:50%;
  background:var(--aux-cyan);
  box-shadow:0 0 8px 3px rgba(var(--cyan-rgb),.72),0 0 26px 8px rgba(var(--blue-rgb),.28);
  animation:roboticsNodeSwitch 2.8s steps(1,end) infinite;
}
.robotics-hero-node--a{left:33%;top:34%;}
.robotics-hero-node--b{left:46%;top:57%;animation-delay:-1.9s;}
.robotics-hero-node--c{right:27%;top:35%;animation-delay:-.95s;}
@keyframes roboticsHeroFloat{
  0%,100%{translate:0 -50%;rotate:-1deg;}
  50%{translate:0 calc(-50% - 12px);rotate:1.2deg;}
}
@keyframes roboticsCorePulse{
  0%,49%{opacity:.32;scale:.96;}
  50%,100%{opacity:.88;scale:1.04;}
}
@keyframes roboticsOrbitSpin{to{rotate:360deg;}}
@keyframes roboticsArmPulse{
  0%,49%{filter:contrast(1.03) saturate(1.08) brightness(.98) drop-shadow(0 20px 22px rgba(0,70,160,.25));}
  50%,100%{filter:contrast(1.09) saturate(1.28) brightness(1.06) drop-shadow(0 20px 28px rgba(var(--blue-rgb),.40));}
}
@keyframes roboticsNodeSwitch{
  0%,32%{opacity:.16;scale:.72;}
  33%,66%{opacity:1;scale:1.16;}
  67%,100%{opacity:.42;scale:.88;}
}

/* DATA — preserve the supplied 7973 × 2717 artwork, but reveal it only across
   the right side so the left copy column stays calm and readable. */
.interior-v2 .capability-hero--data{
  background:#07131f;
}
.interior-v2 .capability-hero--data .ch-art{
  inset:0;
  opacity:1;
  scale:1.018;
}
.interior-v2 .capability-hero--data :is(.bg>img,.ch-art>img){
  inset:0;
  top:0;
  left:0;
  width:100%;
  height:100%;
  max-width:none;
  object-fit:cover;
  object-position:center;
  opacity:1;
  -webkit-mask-image:linear-gradient(90deg,transparent 0 40%,rgba(0,0,0,.16) 46%,#000 60%);
          mask-image:linear-gradient(90deg,transparent 0 40%,rgba(0,0,0,.16) 46%,#000 60%);
}
.interior-v2 .capability-hero--data .bg::after{
  background:
    linear-gradient(90deg,#07131f 0%,#07131f 39%,rgba(7,19,31,.90) 48%,rgba(7,19,31,.24) 68%,rgba(7,19,31,.06) 100%),
    linear-gradient(180deg,rgba(7,19,31,.08),rgba(7,19,31,.17));
}
.interior-v2 .capability-hero--data :is(.h1,.lead){
  width:min(52%,690px);
  max-width:690px;
}
.capability-hero--data .ch-fx::before{
  left:30%;
  background:
    radial-gradient(ellipse at 78% 100%,rgba(255,206,0,.20),transparent 54%),
    linear-gradient(0deg,rgba(255,158,22,.12),transparent 70%);
  filter:blur(8px);
}

@media (max-width:960px){
  .interior-v2 .capability-hero--data :is(.h1,.lead){
    width:min(60%,620px);
  }
  .robotics-hero-visual{
    right:-72px;
    width:clamp(300px,46vw,420px);
    opacity:.68;
  }
  .interior-v2 .capability-hero--robotics .h1,
  .interior-v2 .capability-hero--robotics .lead{max-width:68%!important;}
}
@media (max-width:720px){
  .interior-v2 .capability-hero--data :is(.h1,.lead){
    width:100%;
    max-width:100%;
  }
  .interior-v2 .capability-hero--data :is(.bg>img,.ch-art>img){
    object-position:62% center;
    opacity:.56;
    -webkit-mask-image:linear-gradient(90deg,transparent 0 18%,rgba(0,0,0,.14) 36%,#000 72%);
            mask-image:linear-gradient(90deg,transparent 0 18%,rgba(0,0,0,.14) 36%,#000 72%);
  }
  .interior-v2 .capability-hero--data .bg::after{
    background:linear-gradient(90deg,rgba(7,19,31,.98) 0%,rgba(7,19,31,.92) 54%,rgba(7,19,31,.54) 100%);
  }
  .robotics-hero-visual{
    top:46%;
    right:-112px;
    width:360px;
    opacity:.28;
    filter:drop-shadow(0 24px 30px rgba(0,16,58,.35));
  }
  .interior-v2 .capability-hero--robotics .h1,
  .interior-v2 .capability-hero--robotics .lead{max-width:100%!important;}
}
@media (prefers-reduced-motion:reduce){
  .robotics-hero-visual,
  .robotics-hero-visual::before,
  .robotics-hero-visual::after,
  .robotics-hero-visual>img,
  .robotics-hero-orbit,
  .robotics-hero-node{animation:none!important;}
}

/* =====================================================================
   INDEPENDENT MENU PAGES
   Shared structure, separately owned colour systems and motion languages.
   ===================================================================== */
.independent-hero{
  --ih-accent:var(--aux-cyan);
  --ih-accent-2:#5080C0;
  --ih-ink:#fff;
  --ih-lead:rgba(var(--white-rgb),.84);
  position:relative;
  isolation:isolate;
  /* min-height removed: superseded by the shell rule further down. The rest of this
     block is still in force — it carries the flex centring, the clip and the padding. */
  display:flex;
  align-items:center;
  overflow:hidden;
  color:var(--ih-ink);
  border-bottom:1px solid rgba(var(--white-rgb),.16);
}
.independent-hero::before,
.independent-hero::after{
  content:"";
  position:absolute;
  inset:0;
  z-index:-2;
  pointer-events:none;
}
.independent-hero::before{
  opacity:.62;
  animation:independentFieldDrift 16s ease-in-out infinite alternate;
}
.independent-hero::after{
  z-index:-1;
  background:linear-gradient(90deg,rgba(6,16,31,.86),rgba(6,16,31,.56) 48%,rgba(6,16,31,.10) 78%);
}
.independent-hero>.container{
  position:relative;
  z-index:3;
  width:100%;
  padding-top:clamp(96px,11vw,150px);
  padding-bottom:clamp(76px,9vw,118px);
}
.independent-hero .h1{
  width:min(100%,860px);
  max-width:860px;
  color:var(--ih-ink);
  font-size:clamp(44px,5.4vw,76px);
  line-height:1.01;
  letter-spacing:-.04em;
  text-wrap:balance;
}
.independent-hero .lead{
  max-width:690px;
  margin:24px 0 34px;
  color:var(--ih-lead);
}
.independent-hero .grad-text{
  background:linear-gradient(100deg,var(--ih-accent),var(--ih-accent-2));
  -webkit-background-clip:text;
          background-clip:text;
  color:transparent;
}
/* The label colour is a token per state, because a single one cannot work here.
   --ih-accent is the client's own auxiliary palette and none of it is touched; what changed
   is the ink laid on it. Hardcoded #fff was failing on all four variants that actually
   render (--innovation is declared but no reachable page uses it; /innovation-network/
   serves .lab-hero, not .independent-hero) —
   white 15.5px/600 needs 4.5:1 and measured 2.05:1 on energy's #B6BD00, 2.07:1 on consumer's
   #FF9E16, 3.32:1 on agriculture's #8B9400 and 4.02:1 on built's var(--blue).

   The hover was worse than the rest state on two of them, which is backwards for a hover:
   built went 4.02 -> 2.58 and innovation 4.87 -> 2.07, because :hover swapped the fill and
   never restated the ink. Hence two tokens, not one.

   #111 rather than --ink #26292C: the three hardest fills (var(--blue) 3.64, var(--aux-red) 3.59,
   #8B9400 4.41) all miss 4.5:1 with #26292C and clear it with #111 (4.70 / 4.64 / 5.70).
   Innovation's #9D55AA is the one rest fill dark enough for white, at 4.87:1 — kept as a
   correct default in case that variant is ever wired to a page.

   Measured, every state, rest and hover:
     innovation  #9D55AA/#fff 4.87  ->  #55C2DD/#111 9.12   (not currently rendered)
     built       var(--blue)/#111 4.70  ->  #30B3A9/#111 7.33
     consumer    #FF9E16/#111 9.13  ->  var(--aux-red)/#111 4.64
     energy      #B6BD00/#111 9.23  ->  #30B3A9/#111 7.33
     agriculture #8B9400/#111 5.70  ->  var(--blue)/#111 4.70

   The alternative the file uses elsewhere — darkening the fill, as .sai-hero does with
   var(--aux-red) -> #D81B2A — was not taken here: that moves the client's swatch, and choosing the
   ink does not. */
.independent-hero{--ih-btn-ink:#111;--ih-btn-ink-2:#111;}
.independent-hero--innovation{--ih-btn-ink:#fff;}
.independent-hero .btn-primary{
  color:var(--ih-btn-ink);
  background:var(--ih-accent);
  box-shadow:0 18px 36px -22px color-mix(in srgb,var(--ih-accent) 80%,transparent);
}
.independent-hero .btn-primary:hover{background:var(--ih-accent-2);color:var(--ih-btn-ink-2);}
.independent-hero .btn-ghost{
  color:var(--ih-ink);
  border-color:color-mix(in srgb,var(--ih-ink) 38%,transparent);
  background:color-mix(in srgb,var(--ih-ink) 7%,transparent);
}
.independent-hero-field{
  position:absolute;
  z-index:0;
  inset:0;
  overflow:hidden;
  pointer-events:none;
}
.independent-hero-field span{
  position:absolute;
  display:block;
  width:13px;
  height:13px;
  border:2px solid color-mix(in srgb,var(--ih-accent) 82%,#fff);
  border-radius:50%;
  background:color-mix(in srgb,var(--ih-accent) 58%,transparent);
  box-shadow:0 0 10px 3px color-mix(in srgb,var(--ih-accent) 54%,transparent);
  animation:independentNodeFloat 6s ease-in-out infinite;
}
.independent-hero-field span::after{
  content:"";
  position:absolute;
  left:50%;
  top:50%;
  width:clamp(110px,13vw,220px);
  height:1px;
  transform-origin:left center;
  rotate:var(--node-r,18deg);
  background:linear-gradient(90deg,color-mix(in srgb,var(--ih-accent) 58%,transparent),transparent);
}
.independent-hero-field span:nth-child(1){left:62%;top:20%;--node-r:24deg;}
.independent-hero-field span:nth-child(2){left:78%;top:35%;--node-r:-36deg;animation-delay:-1.2s;}
.independent-hero-field span:nth-child(3){left:69%;top:70%;--node-r:11deg;animation-delay:-2.4s;}
.independent-hero-field span:nth-child(4){left:90%;top:17%;--node-r:56deg;animation-delay:-3.6s;}
.independent-hero-field span:nth-child(5){left:88%;top:74%;--node-r:-18deg;animation-delay:-4.8s;}

/* Innovation Network — violet/cyan laboratory constellation. */
.independent-hero--innovation{
  --ih-accent:#9D55AA;
  --ih-accent-2:#55C2DD;
  background:
    radial-gradient(48% 92% at 92% 16%,rgba(144,71,153,.54),transparent 74%),
    radial-gradient(42% 70% at 58% 100%,rgba(var(--cyan-rgb),.30),transparent 76%),
    linear-gradient(125deg,#160f31 0%,#30204f 48%,#0b3a50 100%);
}
.independent-hero--innovation::before{
  background:
    radial-gradient(circle at 72% 28%,rgba(var(--white-rgb),.52) 0 1px,transparent 3px),
    radial-gradient(circle at 88% 63%,rgba(85,194,221,.68) 0 2px,transparent 6px),
    linear-gradient(rgba(var(--white-rgb),.035) 1px,transparent 1px),
    linear-gradient(90deg,rgba(var(--white-rgb),.035) 1px,transparent 1px);
  background-size:auto,auto,72px 72px,72px 72px;
}

/* Built Environment — pale architectural grid, deliberately not dark blue. */
.independent-hero--built{
  --ih-accent:var(--blue);
  --ih-accent-2:#30B3A9;
  --ih-ink:#173148;
  --ih-lead:#466276;
  background:
    radial-gradient(65% 120% at 96% 14%,rgba(48,179,169,.25),transparent 72%),
    linear-gradient(135deg,#edf7f7 0%,#dcecef 52%,#c7e1e4 100%);
  border-bottom-color:rgba(23,49,72,.12);
}
.independent-hero--built::before{
  background:
    linear-gradient(30deg,rgba(var(--blue-rgb),.11) 12%,transparent 12.5%,transparent 87%,rgba(var(--blue-rgb),.11) 87.5%),
    linear-gradient(150deg,rgba(var(--blue-rgb),.08) 12%,transparent 12.5%,transparent 87%,rgba(var(--blue-rgb),.08) 87.5%),
    linear-gradient(30deg,rgba(var(--blue-rgb),.08) 12%,transparent 12.5%,transparent 87%,rgba(var(--blue-rgb),.08) 87.5%);
  background-size:94px 164px;
  background-position:0 0,0 0,47px 82px;
}
.independent-hero--built::after{
  background:linear-gradient(90deg,rgba(244,251,251,.94),rgba(236,247,248,.74) 48%,rgba(226,242,243,.22) 78%);
}
.independent-hero--built .btn-ghost{background:rgba(var(--white-rgb),.32);}

/* Consumer — warm coral/orange experience field. */
.independent-hero--consumer{
  --ih-accent:#FF9E16;
  --ih-accent-2:var(--aux-red);
  background:
    radial-gradient(56% 96% at 94% 30%,rgba(255,158,22,.46),transparent 70%),
    radial-gradient(42% 70% at 67% 100%,rgba(244,37,52,.34),transparent 76%),
    linear-gradient(125deg,#2b1728 0%,#582331 52%,#7b3224 100%);
}
.independent-hero--consumer::before{
  background:
    radial-gradient(circle at 78% 22%,rgba(var(--white-rgb),.52) 0 2px,transparent 7px),
    radial-gradient(circle at 91% 57%,rgba(255,206,0,.72) 0 2px,transparent 8px),
    repeating-linear-gradient(120deg,transparent 0 58px,rgba(var(--white-rgb),.045) 59px 60px);
}

/* Energy & Sustainability — graphite, teal and a single lime accent. */
.independent-hero--energy{
  --ih-accent:#B6BD00;
  --ih-accent-2:#30B3A9;
  background:
    radial-gradient(52% 92% at 91% 18%,rgba(182,189,0,.32),transparent 70%),
    radial-gradient(45% 80% at 68% 100%,rgba(48,179,169,.30),transparent 75%),
    linear-gradient(125deg,#112421 0%,#1d3930 54%,#365438 100%);
}
.independent-hero--energy::before{
  background:
    repeating-radial-gradient(ellipse at 90% 100%,transparent 0 34px,rgba(182,189,0,.08) 35px 36px),
    linear-gradient(112deg,transparent 54%,rgba(var(--white-rgb),.06) 54.2%,transparent 54.5%);
}

/* Agriculture — light earth/field system with darker text. */
.independent-hero--agriculture{
  --ih-accent:#8B9400;
  --ih-accent-2:var(--blue);
  --ih-ink:#26351f;
  --ih-lead:#526148;
  background:
    radial-gradient(54% 98% at 92% 12%,rgba(48,179,169,.24),transparent 72%),
    linear-gradient(132deg,#f4f3df 0%,#e8ebca 54%,#d5dfb6 100%);
  border-bottom-color:rgba(38,53,31,.12);
}
.independent-hero--agriculture::before{
  background:
    repeating-linear-gradient(116deg,transparent 0 49px,rgba(139,148,0,.12) 50px 51px),
    repeating-linear-gradient(64deg,transparent 0 79px,rgba(var(--blue-rgb),.075) 80px 81px);
}
.independent-hero--agriculture::after{
  background:linear-gradient(90deg,rgba(248,248,232,.96),rgba(241,243,218,.75) 49%,rgba(226,233,194,.18) 80%);
}
.independent-hero--agriculture .btn-ghost{background:rgba(var(--white-rgb),.28);}

.independent-intro .h2{max-width:560px;}
.independent-feature-grid{
  display:grid;
  grid-template-columns:repeat(3,minmax(0,1fr));
  gap:var(--sp-16);
  margin-top:48px;
}
.independent-feature{
  position:relative;
  min-height:230px;
  padding:30px 28px 26px;
  overflow:hidden;
  border:1px solid var(--df-line);
  border-radius:var(--radius-20);
  background:rgba(var(--white-rgb),.86);
  box-shadow:var(--sh-raised);
  transition:translate var(--dur-base) var(--ease-out),border-color var(--dur-base) var(--ease-out),box-shadow var(--dur-base) var(--ease-out);
}
.independent-feature::after{
  content:"";
  position:absolute;
  right:-42px;
  bottom:-50px;
  width:150px;
  height:150px;
  border:1px solid color-mix(in srgb,var(--teal) 20%,transparent);
  border-radius:50%;
  transition:scale var(--dur-base) var(--ease-out),opacity var(--dur-base) var(--ease-out);
  opacity:.55;
}
.independent-feature:hover{
  translate:0 -7px;
  border-color:rgba(var(--blue-rgb),.28);
  box-shadow:0 34px 66px -46px rgba(0,93,120,.52);
}
.independent-feature:hover::after{opacity:.9;}
.independent-feature-no{
  display:block;
  margin-bottom:52px;
  font:700 12px/1 var(--f-mono);
  letter-spacing:.17em;
  color:var(--teal);
}
.independent-feature h3{font-size:21px;margin-bottom:10px;color:var(--ink);}
.independent-feature p{font-size:15px;line-height:1.62;color:var(--text);margin:0;}
.independent-related-title{margin-bottom:24px;}
.independent-cta .h2{margin-bottom:12px;}

@keyframes independentFieldDrift{
  from{background-position:0 0,0 0,0 0,0 0;}
  to{background-position:28px -18px,-22px 16px,38px 18px,-34px -16px;}
}
@keyframes independentNodeFloat{
  0%,100%{translate:0 0;opacity:.38;scale:.82;}
  48%{translate:16px -18px;opacity:1;scale:1.14;}
  72%{translate:-5px -7px;opacity:.64;scale:.94;}
}

@media (max-width:900px){
  .independent-feature-grid{grid-template-columns:1fr;}
  .independent-feature{min-height:190px;}
  .independent-feature-no{margin-bottom:34px;}
}
@media (max-width:720px){
  .independent-hero{min-height:540px;}
  .independent-hero>.container{padding-top:82px;padding-bottom:64px;}
  .independent-hero .h1{font-size:clamp(40px,11vw,54px);overflow-wrap:anywhere;}
  .independent-hero .lead{font-size:18px;line-height:1.5;}
  .independent-hero-field span:nth-child(1),
  .independent-hero-field span:nth-child(3){display:none;}
}
@media (prefers-reduced-motion:reduce){
  .independent-hero::before,
  .independent-hero-field span{animation:none!important;}
}

/* =====================================================================
   CAPABILITY PAGES — accreditation block + partner wall
   Added for the "BYS Website" copy deck (Microsoft Frontier Partner
   section and the [Insert logos] partner row on AI / Data).
   ===================================================================== */
/* Three layers: decoration, badge card, copy. The decoration drifts and the card floats
   against it on a slower cycle, which is what reads as depth — matching speeds would just
   look like the whole block sliding. Nothing here is baked: the copy is live text and the
   badge is its own file, so either can change without re-cutting an image. */
/* Capped so the badge inside lands at the same size the rest of the site gives this
   exact PNG. .accred-card is width:34%, so 1000 x 0.34 = 340px — the same cap .pr-badge
   carries at base.css ~6208 for the identical file. Uncapped, this block rendered
   1342px wide / 899px tall, making it the tallest section on the page and 2.97x the
   partner wall directly below it. */
.accred{position:relative;max-width:1000px;margin-left:auto;margin-right:auto;}
.accred-art{position:relative;}
.accred-decor{
  display:block;width:100%;height:auto;
  animation:acDrift 19s ease-in-out infinite alternate;
  will-change:transform;
}
/* Slot measured on the artwork frame: the erased card sits at x 830-1526 of 1706 and is
   centred on y 449 of 922. Width-matched, midline-centred — see the template note. */
.accred-card{
  /* Down from 41.50% at the client's call. left/top move with it: the badge is absolutely
     positioned, so shrinking it alone would slide it off the centre of the slot the
     backdrop has cut for it. Centre held at 69.06% / 48.53%. */
  position:absolute;z-index:3;left:52.06%;top:27.26%;width:34%;height:auto;
  animation:acFloat 7.5s ease-in-out infinite alternate;
  will-change:transform;
}
/* Amplitudes raised after review: the first pass moved the decoration 9px over 26s and
   the card 7px over 9s, which measured as motion but did not read as any. */
@keyframes acDrift{from{transform:translate3d(0,0,0) scale(1);}
                   to{transform:translate3d(-18px,10px,0) scale(1.025);}}
@keyframes acFloat{from{transform:translate3d(0,0,0);}
                   to{transform:translate3d(9px,-13px,0);}}

/* Circuit ring — the track, and the pulse that runs it. Colours are the artwork's own
   node navy, so the pulse reads as part of the drawing rather than something laid over it.
   The path is deliberately INVISIBLE — an earlier pass stroked it faintly as a guide track
   and it read as a stray rectangle drawn around the badge, which is not in the client's
   artwork. Only the moving dash is painted. Path length is 3060; the dash is 58 with the
   remainder as gap, so exactly one pulse is in flight at a time. */
.accred-net{position:absolute;inset:0;width:100%;height:100%;pointer-events:none;z-index:1;}
.accred-run{
  stroke:#314975;stroke-width:2.6;stroke-linecap:round;
  stroke-dasharray:58 3002;
  animation:acRun 12s linear infinite;
  filter:drop-shadow(0 0 5px rgba(49,73,117,.5));
}
@keyframes acRun{from{stroke-dashoffset:3060;}to{stroke-dashoffset:0;}}

/* The four brand squares, lifted out of the raster so they can actually move. Geometry
   and colour measured off BACKDROP DESIGN.png against the same 1706x922 frame.
   Two animations, deliberately on different properties so they compose instead of
   fighting: a slow idle drift on transform, and a flash on box-shadow/filter whose delay
   is the moment the pulse above arrives at that square. */
.accred-sq{
  position:absolute;pointer-events:none;z-index:2;
  animation:acSqIdle var(--dur) ease-in-out infinite alternate var(--dly,0s),
            acSqHit 12s linear infinite var(--hit,0s);
  will-change:transform;
}
@keyframes acSqIdle{
  from{transform:translate(0,0) scale(1) rotate(0deg);}
  to  {transform:translate(var(--tx),var(--ty)) scale(1.06) rotate(var(--rot));}
}
@keyframes acSqHit{
  0%      {box-shadow:0 0 0 0 rgba(0,0,0,0);filter:brightness(1);}
  3%      {box-shadow:0 0 26px 7px var(--glow);filter:brightness(1.28) saturate(1.15);}
  11%     {box-shadow:0 0 0 0 rgba(0,0,0,0);filter:brightness(1);}
  100%    {box-shadow:0 0 0 0 rgba(0,0,0,0);filter:brightness(1);}
}
.accred-sq--r{left:47.362%;top:22.017%;width:3.751%;height:6.725%;background:#FD655F;
  --tx:-5%;--ty:6%;--rot:-2deg;--dur:7.2s;--dly:0s;  --hit:0s;    --glow:rgba(253,101,95,.85);}
.accred-sq--g{left:86.694%;top:17.028%;width:3.048%;height:5.640%;background:#8FC773;
  --tx:6%;--ty:-5%;--rot:3deg;--dur:9.1s;--dly:.9s;  --hit:3.07s; --glow:rgba(143,199,115,.85);}
.accred-sq--b{left:44.197%;top:72.017%;width:3.165%;height:5.640%;background:#2DA8EC;
  --tx:6%;--ty:5%;--rot:2deg;--dur:6.4s;--dly:1.8s;  --hit:9.35s; --glow:rgba(45,168,236,.85);}
.accred-sq--y{left:88.394%;top:74.078%;width:3.107%;height:5.965%;background:#FEBF34;
  --tx:-6%;--ty:-6%;--rot:-3deg;--dur:8.3s;--dly:2.6s;--hit:5.76s;--glow:rgba(254,191,52,.85);}

.accred-copy{
  position:absolute;z-index:2;left:4.5%;top:50%;transform:translateY(-50%);
  /* The artwork's clean left runs to 35.8% of its width before the first dot column and
     vertical rule appear. 4.5% + 30% clears that; the previous 34% did not, once the frame
     was capped above. */
  width:min(30%,300px);
}
.accred-copy h2{margin:0 0 10px;font-size:clamp(22px,2.4vw,30px);}
/* The .interior-v2 prefix is load-bearing: without it the generic interior h2 rule
   earlier in this file wins and this heading renders at 54px, wrapping to three lines
   inside a 300px column. */
.interior-v2 .accred-copy h2{font-size:clamp(24px,2.2vw,32px);line-height:1.12;letter-spacing:-.02em;}
.accred-copy p{margin:0;font:400 16.5px/1.6 var(--f-body);color:var(--text);max-width:52ch;}

@media (prefers-reduced-motion:reduce){
  .accred-decor,.accred-card,.accred-sq,.accred-run{animation:none;}
  .accred-run{opacity:0;}
}

/* Dark band so the deck's white partner marks read correctly, and so the row
   sits as one confident block rather than ten pale boxes. Grid (not flex) keeps
   a trailing odd logo the same width as the rest instead of stretching it. */
/* Wide layout: the client's own composed strip. Narrow layout: the individual files,
   reflowed. Exactly one is ever displayed — see template-parts/partner-wall.php. */
.pwall-strip{
  border-radius:var(--radius-14);overflow:hidden;background:#0A0A0A;
  border:1px solid rgba(var(--white-rgb),.08);
}
.pwall-strip img{display:block;width:100%;height:auto;}

/* One black field, five across, logos floating in it — no tile grid. The 1px-gap
   navy tiles this replaced fenced every logo in its own box, which fought artwork that
   is already a set of self-contained marks. Ten logos on five columns give two clean
   rows; a partner list that is not a multiple of five still fills left-to-right. */
.pwall{
  display:none;grid-template-columns:repeat(5,1fr);gap:var(--sp-28) var(--sp-12);
  border-radius:var(--radius-14);overflow:hidden;background:#0A0A0A;
  border:1px solid rgba(var(--white-rgb),.08);padding:40px 22px;
}
.pwall-item{
  min-height:74px;display:inline-flex;align-items:center;justify-content:center;padding:0 14px;
  background:transparent;
}
.pwall-item img{max-width:100%;max-height:38px;width:auto;object-fit:contain;opacity:.9;transition:opacity var(--dur-base);}
.pwall-item:hover img{opacity:1;}
/* the three we hold as vector are brand-coloured — force them white to match */
.pwall-item--vector img{filter:brightness(0) invert(1);}

@media (max-width:820px){
  /* The artwork's empty left is a desktop composition — at this width there is no room
     to sit copy inside it, and overlaid text would land on the decoration. Unstack it:
     copy above, artwork below, both in normal flow. */
  .accred{display:flex;flex-direction:column;gap:var(--sp-20);text-align:center;}
  .accred-copy{position:static;transform:none;width:auto;left:auto;top:auto;}
  /* Without this the new .interior-v2 rule above also wins here and drops the stacked
     mobile heading from ~35px to 24px. */
  .interior-v2 .accred-copy h2{font-size:clamp(26px,6vw,34px);}
  .accred-copy p{margin:0 auto;}
  /* Hand over from the strip to the individual files: at this width the 5.53:1 strip
     scales each mark down to roughly 12px and the wordmarks stop being readable. */
  .pwall-strip{display:none;}
  .pwall{display:grid;grid-template-columns:repeat(2,1fr);gap:var(--sp-24) var(--sp-8);padding:30px 16px;}
  .pwall-item{min-height:60px;padding:0 10px;}
  .pwall-item img{max-height:30px;}
}

/* =====================================================================
   CAPABILITY REACTOR  (.acx + .acc.acc--motion)
   The AI page's capability list as a dark instrument panel: a live canvas
   node-field that re-forms behind the cards each time the active capability
   changes, a cursor spotlight, and glass cards over the top.
   Opt-in — the other seven .acc pages are untouched.
   ===================================================================== */
.acx{
  position:relative;isolation:isolate;overflow:hidden;border-radius:var(--radius-20);
  padding:14px;
  background:
    radial-gradient(120% 90% at 82% 8%,rgba(var(--blue-rgb),.38),transparent 58%),
    linear-gradient(158deg,#0B2547 0%,#0A3369 52%,#124490 100%);
  box-shadow:0 30px 70px -40px rgba(0,31,77,.9),inset 0 1px 0 rgba(var(--white-rgb),.07);
}
/* AI hero family — panel follows the artwork above it.
   Sampled from the AI hero artwork (then hero-ai-exact.png, now hero-ai.webp — same image,
   the 8.6MB PNG was retired): base #001830 (48% of the image), second
   layer #003048/#003060, indigo highlights #184878, warm accent #783048. The default
   panel is a cyan-and-blue scheme that reads as a different page against that red mesh,
   so this family gets the hero's own hues — lifted a step so the panel still sits above
   the page rather than punching a hole in it. Scoped to .bs-hero-ai (the artwork-family
   class from functions.php:113, not the page slug) so the cloud / robotics / data panels
   keep the neutral scheme that suits their own heroes. */
/* The panel followed the hero, and the hero has changed — so the panel follows it again.

   Every red below was lifted off the previous AI banner. With that banner gone, a red mesh,
   red edge bars and a red glow sat under a blue-and-violet plate and answered to nothing.
   The whole scheme moves into the new plate's family: cyan for the live parts, the deep
   indigo #003090 the artwork is actually built from for the ground.

   The split the old comment describes still holds and is why these are not one colour: text
   carries no accent at all (the open row goes white with a glow), the +/x affordance takes a
   colour that clears the 3:1 in WCAG 1.4.11, and the purely decorative parts — mesh, edge
   bar, progress, glow — are unconstrained. var(--aux-cyan) measures 5.74:1 on this panel's
   ground, well past the 3:1 the affordance needs. */
.bs-hero-ai .acx{
  --acx-net-rgb:86,168,200;      /* canvas mesh — the plate's cyan network */
  --acx-hot-rgb:150,220,240;     /* pulse highlight */
  background:
    radial-gradient(120% 90% at 82% 8%,rgba(0,48,144,.44),transparent 58%),
    linear-gradient(158deg,#0A2340 0%,#123356 52%,#1D4478 100%);
}
.bs-hero-ai .acx-spot{background:radial-gradient(220px 220px at var(--mx,50%) var(--my,50%),rgba(86,168,200,.22),transparent 70%);}
.bs-hero-ai .acc--motion .acc-item::before{background:linear-gradient(180deg,#5FC8E4,#2A6E9B);}
.bs-hero-ai .acc--motion.is-auto .acc-item.open::after,
.bs-hero-ai .acc--motion .acc-item::after{background:linear-gradient(90deg,#2A6E9B,#5FC8E4);}
.bs-hero-ai .acc--motion .pm{color:#6FD3EC;}
.bs-hero-ai .acc--motion .acc-item.open .pm,
.bs-hero-ai .acc--motion .acc-item.open .acc-n{color:#fff;text-shadow:0 0 14px rgba(95,200,228,.75);}
.bs-hero-ai .acc--motion .acc-item:not(.open):hover{border-color:rgba(95,200,228,.36);}
.bs-hero-ai .acc--motion .acc-item.open{
  border-color:rgba(95,200,228,.50);
  box-shadow:0 16px 40px -22px rgba(20,70,110,.9),inset 0 0 0 1px rgba(95,200,228,.12);
}

.acx-net{position:absolute;inset:0;width:100%;height:100%;z-index:0;pointer-events:none;opacity:.9;}
/* cursor spotlight — follows the pointer, driven by --mx/--my from fx.js */
.acx-spot{
  position:absolute;inset:0;z-index:1;pointer-events:none;opacity:0;
  transition:opacity var(--dur-base) var(--ease);
  background:radial-gradient(220px 220px at var(--mx,50%) var(--my,50%),rgba(var(--blue-soft-rgb),.20),transparent 70%);
}
.acx:hover .acx-spot{opacity:1;}

.acc--motion,
/* The interior-v2 surface rule paints .acc with var(--df-surface) — a 92% white —
   through `.interior-v2 :is(.acc, .metrics, .trust, …)`. That selector scores (0,2,0)
   and this one only scored (0,1,0), so the plain `.acc--motion` declaration below
   lost the cascade and the panel rendered as a white slab with white text on it.
   The .interior-v2 prefix here matches that specificity so transparent actually
   wins. Do not drop it back to a bare class selector. */
.interior-v2 .acc--motion{
  position:relative;z-index:2;
  border:none;background:transparent;overflow:visible;box-shadow:none;display:grid;gap:var(--sp-8);
}
.acc--motion .acc-item{
  position:relative;overflow:hidden;border-radius:var(--radius-14);
  border:1px solid rgba(var(--white-rgb),.10);
  /* Deliberately a flat translucent white over the navy rather than
     backdrop-filter: the blur is expensive, and where it degrades it renders as
     a white haze that bleaches the whole panel. */
  background:rgba(var(--white-rgb),.075);
  transition:border-color var(--dur-base) var(--ease),background var(--dur-base) var(--ease),
             box-shadow var(--dur-base) var(--ease),transform var(--dur-base) var(--ease);
}
.acc--motion .acc-item+.acc-item{border-top:1px solid rgba(var(--white-rgb),.10);}

/* leading edge — grows from the top when the card becomes active */
.acc--motion .acc-item::before{
  content:"";position:absolute;left:0;top:0;bottom:0;width:2px;z-index:2;
  background:linear-gradient(180deg,var(--blue-soft),var(--blue));
  transform:scaleY(0);transform-origin:top;transition:transform var(--dur-base) var(--ease);
}
.acc--motion .acc-item.open::before{transform:scaleY(1);}

/* dwell progress along the bottom edge */
.acc--motion .acc-item::after{
  content:"";position:absolute;left:0;bottom:0;height:1.5px;width:100%;z-index:2;
  background:linear-gradient(90deg,var(--blue),var(--blue-soft));
  transform:scaleX(0);transform-origin:left;
}
.acc--motion.is-auto .acc-item.open::after{animation:acxProg var(--acc-dwell,5.5s) linear forwards;}
@keyframes acxProg{from{transform:scaleX(0);}to{transform:scaleX(1);}}

.acc--motion .acc-h{padding:17px 20px 17px 24px;gap:var(--sp-12);}
.acc--motion .acc-h:hover{background:transparent;}
.acc--motion .acc-n{
  flex:0 0 auto;min-width:22px;font:700 11px/1 var(--f-mono);letter-spacing:.16em;
  /* was .34, which measured 2.56:1 against the card — below AA for 11px text.
     .62 lands at 4.95:1; the number still reads as subordinate to the .82 title
     through its size and weight rather than through being too faint to read. */
  color:rgba(var(--white-rgb),.62);transition:color var(--dur-base) var(--ease),text-shadow var(--dur-base) var(--ease);
}
.acc--motion .acc-item.open .acc-n{color:#7FD4E4;text-shadow:0 0 14px rgba(127,212,228,.65);}
.acc--motion .acc-h .t{
  flex:1 1 auto;color:rgba(var(--white-rgb),.82);
  transition:color var(--dur-base) var(--ease),transform var(--dur-base) var(--ease);
}
.acc--motion .acc-item.open .acc-h .t{color:#fff;transform:translateX(3px);}
.acc--motion .pm{color:var(--blue-soft);transition:transform var(--dur-base) var(--ease),color var(--dur-base);}
.acc--motion .acc-item.open .pm{transform:rotate(135deg);color:#7FD4E4;}

.acc--motion .acc-item:not(.open):hover{
  border-color:rgba(var(--blue-soft-rgb),.34);background:rgba(var(--white-rgb),.075);transform:translateY(-1px);
}
.acc--motion .acc-item.open{
  border-color:rgba(127,212,228,.46);background:rgba(var(--white-rgb),.085);
  box-shadow:0 16px 40px -22px rgba(var(--blue-rgb),.85),inset 0 0 0 1px rgba(127,212,228,.10);
}

/* true auto-height; !important defeats the inline max-height the shared
   accordion script writes for the classic .acc variant */
/* Open at 1fr, not 0fr — same reason as .acc-b above. This variant was single-open and
   hover-driven, so only one row of N was ever readable and the other rows' copy was
   unreachable entirely under a coarse pointer. The .open class survives and still drives
   the row highlight and the node-field pulse, so hovering still responds; it just no
   longer decides what is legible. */
.acc--motion .acc-b{
  max-height:none!important;display:grid;grid-template-rows:1fr;
}
.acc--motion .acc-b>.inner{
  overflow:hidden;min-height:0;padding:0 22px 18px 24px;
  color:rgba(var(--white-rgb),.62);font-size:14.5px;line-height:1.65;
}
/* The highlighted row's copy lifts slightly out of the others, which is what the
   hover now buys instead of legibility. */
.acc--motion .acc-item.open .acc-b>.inner{color:rgba(var(--white-rgb),.82);}

@media (max-width:820px){ .acx{padding:10px;border-radius:var(--radius-14);} }

@media (prefers-reduced-motion:reduce){
  .acc--motion .acc-item,
  .acc--motion .acc-item::before,
  .acc--motion .acc-b,
  .acc--motion .acc-b>.inner,
  .acc--motion .acc-h .t,
  .acc--motion .acc-n,
  .acc--motion .pm{transition:none;}
  .acc--motion .acc-item::after{animation:none;display:none;}
  .acc--motion .acc-item:not(.open):hover{transform:none;}
  .acx-spot{display:none;}
}

/* Managed Services' right-hand panel.
   The client's deck asks every capability page for the same "<Drop-down list on right>",
   and on this one page it supplies the five items as titles with no body copy behind
   them. A .acc--motion accordion here would be five cards whose +/x opens onto nothing,
   so the panel keeps the instrument plate and the card, and drops the disclosure.

   Everything below is lifted from .acc--motion .acc-item / .acc-h so the two panels are
   the same object: same 14px radius, same 10% white hairline, same 7.5% translucent
   white fill, same 17/20/17/24 padding, same 600 17px display face. The one addition is
   that the leading edge is drawn at rest rather than growing on .open, because there is
   no .open state to grow it — it is what tells the eye these are rows of one list.

   z-index:2 puts it over .acx-net (0) and .acx-spot (1), exactly as .acc--motion does. */
.acx-list{
  position:relative;z-index:2;display:grid;gap:var(--sp-8);
  margin:0;padding:0;list-style:none;
}
.acx-list li{
  position:relative;overflow:hidden;border-radius:var(--radius-14);
  border:1px solid rgba(var(--white-rgb),.10);
  background:rgba(var(--white-rgb),.075);
  padding:17px 20px 17px 24px;
  font:600 17px/1.3 var(--f-display);
  color:rgba(var(--white-rgb),.90);
}
.acx-list li::before{
  content:"";position:absolute;left:0;top:0;bottom:0;width:2px;
  background:linear-gradient(180deg,var(--blue-soft),var(--blue));
}
@media (max-width:820px){ .acx-list li{padding:15px 16px 15px 20px;font-size:16px;} }

/* Managed Services joins the capability-hero family: the highlighted word and the
   primary button take the same cyan-to-blue the Data, Systems and Infrastructure heroes
   use, rather than the site-wide anniversary gradient. */
.interior-v2 .capability-hero--managed .grad-text{
  background:linear-gradient(100deg,var(--aux-cyan),var(--blue));
  -webkit-background-clip:text;
          background-clip:text;
}
.interior-v2 .capability-hero--managed .btn-primary{background:var(--blue);}

/* =====================================================================
   AI SOLUTIONING HERO — "cold start"
   The approved artwork runs at full luminance and is SHAPED BY A MASK
   rather than dimmed by a scrim. The band is painted #0E2036 — sampled
   from the artwork's own flat left field — so the mask edge is invisible
   and the picture reads as the band rather than as a photo inside one.
   Every moving element is the artwork, a line of type, or a rule of the
   grid. Nothing decorative is added: that is what the two rejected
   reactor attempts were, and this design has no place to put one.
   ===================================================================== */

.interior-v2 .capability-hero--ai.sai-hero{
  background:#0E2036;
  /* Was clamp(560px,44vw,680px), which put this hero 132px taller than every sibling at
     1440. The shared subpage scale is at base.css ~4487; matching it literally here keeps
     the value visible next to the rest of this page's geometry. */
  min-height:clamp(520px,34.1vw,652px);
  border-bottom:0;
  overflow:visible;                 /* the underprint has to cross the floor */
  position:relative;
}
.interior-v2 .capability-hero--ai.sai-hero .bg{overflow:hidden;}

/* ---- the field ---------------------------------------------------- */
.interior-v2 .capability-hero--ai.sai-hero .ch-art{
  opacity:1;
  clip-path:inset(0 0 0 100%);
  transition:clip-path var(--dur-slow) var(--ease-out) 80ms;
  -webkit-mask-image:
    linear-gradient(100deg,transparent 0 24%,#000 60%,#000 100%),
    linear-gradient(180deg,#000 0 calc(100% - 64px),transparent 100%);
          mask-image:
    linear-gradient(100deg,transparent 0 24%,#000 60%,#000 100%),
    linear-gradient(180deg,#000 0 calc(100% - 64px),transparent 100%);
  -webkit-mask-composite:source-in;
          mask-composite:intersect;
}
.interior-v2 .capability-hero--ai.sai-hero.sai-in .ch-art{clip-path:inset(0 0 0 0);}

.interior-v2 .capability-hero--ai.sai-hero .ch-art>img{
  object-position:78% 50%;
  filter:saturate(1.16) contrast(1.045);
  scale:1.18;
  translate:var(--ch-x,0) var(--ch-y,0);   /* the field moves; the mask does not */
  transition:scale 2.1s var(--ease) var(--dur-fast),translate var(--dur-fast) linear;
}
.interior-v2 .capability-hero--ai.sai-hero.sai-in .ch-art>img{scale:1.02;}

/* ---- the grid ------------------------------------------------------ */
.interior-v2 .capability-hero--ai.sai-hero>.container{
  display:grid;
  grid-template-columns:64px minmax(0,1fr);
  grid-template-rows:1fr auto;   /* kicker row removed */
  column-gap:clamp(20px,2.4vw,36px);
  /* Bottom-aligned like every other hero container. This selector is (0,4,0) and was
     out-ranking the shared rule, so when the hero became a fixed box this page was the one
     still pushing its copy down from a fixed top pad — and it clipped. */
  padding-top:0;
  padding-bottom:40px;   /* matches the sibling container rhythm */
  align-self:flex-end;
}

/* ---- the spine ----------------------------------------------------- */
.sai-hero .sai-rail{
  position:relative;grid-column:1;grid-row:1;width:64px;
  clip-path:inset(0 0 100% 0);
  transition:clip-path var(--dur-slow) var(--ease-out) 140ms;
}
.sai-in .sai-rail{clip-path:inset(0 0 0 0);}
.sai-hero .sai-rail::before{
  content:"";position:absolute;left:0;top:0;bottom:0;width:1px;
  background:linear-gradient(180deg,transparent,rgba(var(--blue-soft-rgb),.40) 10%,rgba(var(--blue-soft-rgb),.40) 90%,transparent);
}
.sai-hero .sai-rail i{
  position:absolute;left:0;width:14px;height:1px;background:rgba(var(--blue-soft-rgb),.55);
  transform:scaleX(0);transform-origin:left;
  transition:transform var(--dur-base) var(--ease);
}
.sai-hero .sai-rail i:nth-child(1){top:0;}
.sai-hero .sai-rail i:nth-child(2){top:50%;}
.sai-hero .sai-rail i:nth-child(3){top:calc(100% - 1px);}
.sai-in .sai-rail i:nth-child(1){transform:scaleX(1);transition-delay:.72s;}
.sai-in .sai-rail i:nth-child(2){transform:scaleX(1);transition-delay:.86s;}
.sai-in .sai-rail i:nth-child(3){transform:scaleX(1);transition-delay:1.00s;}
.sai-hero .sai-rail b{
  position:absolute;left:0;top:0;width:1px;height:56px;
  background:linear-gradient(180deg,transparent,#5FD0E4,transparent);
  opacity:0;transition:opacity var(--dur-base) var(--ease-out);
  translate:0 calc(var(--sai-rail-y,0px) - 28px);
}
.sai-hero:hover .sai-rail b{opacity:.85;}

/* ---- copy stack ---------------------------------------------------- */
.sai-hero .sai-copy{grid-column:2;grid-row:1;align-self:center;}

.interior-v2 .capability-hero--ai.sai-hero .h1{
  width:auto;
  max-width:min(100%,1180px)!important;
  font-size:clamp(52px,7.6vw,124px);
  line-height:.92;
  letter-spacing:-.042em;
  text-wrap:wrap;
  color:#fff;
  scale:1;filter:none;
  opacity:0;translate:0 14px;
  /* Uncovered by a slanted edge sweeping across it. Done with clip-path on the h1
     ITSELF, not by splitting it into per-character spans: applyI18n() rewrites this
     element's innerHTML on every language switch, and any child spans an entrance
     depended on would be destroyed the first time someone picks 中文. */
  clip-path:polygon(-30% -10%,-30% -10%,-56% 110%,-56% 110%);
  transition:opacity var(--dur-base) linear .46s,
    translate var(--dur-slow) var(--ease-out) .46s,
    clip-path var(--dur-slow) var(--ease) var(--dur-base);
}
.interior-v2 .capability-hero--ai.sai-hero.sai-in .h1{
  opacity:1;translate:0 0;
  clip-path:polygon(-30% -10%,150% -10%,124% 110%,-56% 110%);
}

/* Back to the artwork's red, at the client's call. Kept as a gradient rather than the
   flat var(--aux-red) it used to be, so the word has some modelling at 124px.
   var(--aux-red) measures 4.04:1 on #0E2036 and #FF6B5E 5.88:1 — both clear the 3:1 large-text
   floor, and the ramp runs light-to-dark left-to-right so the brightest stop leads. */
/* Off the red: the artwork it was sampled from is no longer on the page. The banner is
   hero-ai-network.webp now and its accents run 220-280deg — #003090, #303090, #604890,
   #784890 — blue to indigo to violet, no red anywhere. It was not only a mismatch: against
   the ground actually behind the highlighted word, rgb(80,73,149), #FF5A4E measures 2.50:1
   and var(--aux-red) 1.81:1, both under the 3:1 a display headline needs. The ramp below is
   the plate's own family and every stop clears it — #A8E4F7 5.54:1, #7FC4FF 4.12:1,
   #8FA8FF 3.38:1 — still running brightest-first, as the red one did. */
.interior-v2 .capability-hero--ai.sai-hero .grad-text{
  background:linear-gradient(96deg,#A8E4F7,#7FC4FF 45%,#8FA8FF);
  -webkit-background-clip:text;background-clip:text;color:transparent;
  animation:none;                                  /* retires the infinite shimmer */
}

.interior-v2 .capability-hero--ai.sai-hero .lead{
  width:auto;
  max-width:46ch!important;
  margin:26px 0 32px!important;
  font-size:18px;
  line-height:1.58;
  color:rgba(var(--white-rgb),.82);                     /* 11.4:1 on #0E2036 */
  scale:1;filter:none;
  opacity:0;translate:0 22px;
  transition:opacity var(--dur-base) var(--ease-out) .92s,translate var(--dur-base) var(--ease-out) .92s;
}
.interior-v2 .capability-hero--ai.sai-hero.sai-in .lead{opacity:1;translate:0 0;}

.interior-v2 .capability-hero--ai.sai-hero .sai-actions{
  display:flex;flex-wrap:wrap;gap:var(--sp-16)!important;
}
.interior-v2 .capability-hero--ai.sai-hero .sai-actions>.btn{
  opacity:0;translate:0 30px;
  transition:opacity var(--dur-base) var(--ease-out),translate var(--dur-base) var(--ease),
             background var(--dur-fast),border-color var(--dur-fast),color var(--dur-fast),box-shadow var(--dur-fast);
}
.interior-v2 .capability-hero--ai.sai-hero .sai-actions>.btn:nth-child(1){transition-delay:1.18s;}
.interior-v2 .capability-hero--ai.sai-hero .sai-actions>.btn:nth-child(2){transition-delay:1.28s;}
.interior-v2 .capability-hero--ai.sai-hero.sai-in .sai-actions>.btn{opacity:1;translate:0 0;}

/* ---- controls ------------------------------------------------------ */
.interior-v2 .capability-hero--ai.sai-hero .btn{
  height:52px;padding:0 30px;border-radius:var(--radius-4);font-size:15.5px;line-height:1;
}
/* A LIGHT fill, and the ground is the reason rather than taste. Where this button sits the
   plate is rgb(48,66,144), a mid blue, and every dark blue fails WCAG 1.4.11's 3:1 between
   a control and its surroundings: var(--blue) 2.26:1, #0A5FA8 1.39:1, the artwork's own
   #003090 1.26:1. (The red it replaces failed the same test at 1.78:1 — that criterion was
   never being met here.) Clearing it on this plate means going lighter than the ground.
   var(--aux-cyan) does, is already a site token, and is already the colour of the nodes in
   the plate: 3.57:1 against the ground, with dark ink on it at 5.74:1 — clear of the 4.5:1
   body floor that ruled out var(--blue) with white at 4.02:1. */
.interior-v2 .capability-hero--ai.sai-hero .btn-primary{
  background:var(--aux-cyan);color:#0B1B33;
  box-shadow:0 16px 30px -18px rgba(59,176,201,.62);
}
.interior-v2 .capability-hero--ai.sai-hero .btn-primary:hover{
  background:#57C3D9;transform:none;box-shadow:0 18px 34px -18px rgba(59,176,201,.75);
}
.interior-v2 .capability-hero--ai.sai-hero .btn-primary .arrow{color:#0B1B33;}
.interior-v2 .capability-hero--ai.sai-hero .btn-primary::after{display:none;}
.interior-v2 .capability-hero--ai.sai-hero .btn-ghost{
  border-color:rgba(var(--white-rgb),.42);color:#fff;background:transparent;
}
.interior-v2 .capability-hero--ai.sai-hero .btn-ghost:hover{
  border-color:#fff;color:#fff;background:rgba(var(--white-rgb),.06);
}
.sai-hero a:focus-visible{outline:2px solid #5FD0E4;outline-offset:3px;}

/* ---- the overview beside the capability list ------------------------
   Back to a left/right split, at the client's call.

   It had been stacked — the overview as a full-width lede with the six items two-up
   underneath — to close a measured hole: at 1440 the copy column ran 344px against an
   815px panel, so 481px of the left column stood empty. Stacking did close it, but the
   client wants the two columns, so the columns are what it has.

   The hole is handled inside that constraint instead of by abandoning it. The split is
   5fr/7fr rather than 1fr/1fr, which narrows the copy to a better measure and widens the
   panel so its items wrap less and it stands shorter; and the copy is sticky, so instead
   of stranding at the top while the reader moves down the list, it travels with it. The
   panel remains one column: two-up only made sense when it had the full width. */
.sai-after .grid{
  display:grid;
  grid-template-columns:minmax(0,5fr) minmax(0,7fr);
  align-items:start;
}
.sai-after .grid>.reveal:first-child{position:sticky;top:clamp(96px,9vw,124px);}
@media (max-width:900px){
  .sai-after .grid{grid-template-columns:minmax(0,1fr);}
  .sai-after .grid>.reveal:first-child{position:static;}
}

/* ---- the floor ----------------------------------------------------- */
.sai-hero .sai-meta{
  grid-column:1/-1;grid-row:2;
  /* Sits low, on the floor of the hero: align-self:end does that on its own. There used
     to be a clamp(104px,10.5vw,168px) top margin here as well, on the theory that row 1
     takes the slack — but the row is auto-height, so the margin was ADDED to the hero's
     height rather than absorbed by it, and it was the single largest reason this hero ran
     132px taller than its siblings. The 18px padding stays: it carries the hairline rule
     drawn by .sai-meta::before. */
  align-self:end;margin:0;padding:18px 0 0;
  display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
  gap:clamp(20px,2.6vw,44px);align-items:start;
  position:relative;
  /* Measured: the buttons' bottom edge and this row's top edge were both at y=402 — a 0px
     gap, so the hairline rule read as an underline on the CTA rather than as the top of its
     own row. The offset is `top` and not a margin: the container is exactly as tall as its
     content and is bottom-aligned inside a hero whose height is fixed by the shared
     clamp(520px, 286px + 20.8vw, 720px), so a margin here would grow the container upward
     and slide the h1 under the header, which clears it by 6px. A relative offset moves the
     row without touching layout, and there is 148px of hero below it to move into. */
  top:clamp(22px,2.6vw,38px);
}
.sai-hero .sai-meta::before{
  content:"";position:absolute;left:0;right:0;top:0;height:1px;
  background:rgba(var(--white-rgb),.14);
  transform:scaleX(0);transform-origin:left;
  transition:transform var(--dur-base) var(--ease-out) 1.42s;
}
.sai-in .sai-meta::before{transform:scaleX(1);}
/* The 7.0:1 noted above was measured against the hero's flat base colour, but this
   row actually sits over the densest part of the artwork, where the mesh is at its
   brightest. A scrim puts the stated background back underneath the text. It bleeds
   past the container so the band reaches the viewport edge rather than stopping
   short of the last item. */
.sai-hero .sai-meta::after{
  content:"";position:absolute;z-index:-1;pointer-events:none;
  left:calc(50% - 50vw);right:calc(50% - 50vw);
  /* Reaches all the way to the floor of the hero and fades out well above the
     text, so it reads as the hero settling into its base rather than as a bar
     laid across the artwork — which is what a top-and-bottom scrim looked like.

     --sai-floor is the distance from this row down to the hero's floor. fx.js
     measures it (this container's bottom padding, plus the hero's own) instead of
     assuming it, because it is not a constant and not even constant per width: the
     hero's bottom padding is 0 normally, but line 350 parks var(--cookie-h) there
     while the cookie banner is up. So the floor is 111px below this row with the
     banner showing and 18-26px below it once it is dismissed.

     The fallback below is for the no-JS case only, and is deliberately SHORTER than
     the smallest real distance (18px). Overshooting is the expensive direction: the
     hero is overflow:visible, so anything below the floor paints onto the white section
     underneath as a grey band. (That overflow used to be deliberate — it let the
     .sai-underprint strip live past the floor. That strip is gone, but the scrim still
     has to stop at the floor, so this stays as it is.) Undershooting only stops the fade
     a few pixels early. */
  top:-150px;bottom:calc(-1 * var(--sai-floor,16px));
  background:linear-gradient(180deg,
    rgba(9,20,36,0) 0%, rgba(9,20,36,.30) 34%,
    rgba(9,20,36,.66) 58%, rgba(9,20,36,.84) 78%, rgba(9,20,36,.90) 100%);
}
.sai-hero .sai-meta li{
  display:flex;gap:var(--sp-8);align-items:baseline;
  font:600 12px/1.42 var(--f-display);letter-spacing:.10em;text-transform:uppercase;
  color:rgba(var(--white-rgb),.76);                     /* over the scrim above */
  opacity:0;translate:0 16px;
  transition:opacity var(--dur-base) var(--ease-out),translate var(--dur-base) var(--ease-out);
}
.sai-hero .sai-meta li b{color:#5FD0E4;font-weight:600;letter-spacing:.06em;flex:0 0 auto;}
.sai-in .sai-meta li:nth-child(1){transition-delay:1.54s;}
.sai-in .sai-meta li:nth-child(2){transition-delay:1.64s;}
.sai-in .sai-meta li:nth-child(3){transition-delay:1.74s;}
.sai-in .sai-meta li{opacity:1;translate:0 0;}

.sai-hero::after{
  content:"";position:absolute;left:0;right:0;bottom:0;height:1px;z-index:6;
  background:linear-gradient(90deg,transparent,rgba(95,208,228,.55) 22%,rgba(192,155,208,.42) 68%,transparent);
}

/* ---- the artwork crosses the floor --------------------------------- */
/* Answers the "hard horizontal bottom edge" structurally: the same picture continues
   below the band as an inverted line-print that dissolves into the white page. */
/* The underprint band is gone, at the client's call.

   It was a 110-190px strip below the hero repeating the hero artwork greyscaled, inverted
   and multiplied at 12% — the picture "continuing" past the floor. It was hard-wired to
   hero-ai.webp, and this page's hero is hero-ai-network.webp now, so it had stopped being
   an echo of anything: it printed a different photograph, at 12%, as a grey band between
   the hero's teal edge and the white page. Removed rather than repointed — the new banner
   has no line-print to continue. */
.sai-after{position:relative;z-index:1;}

/* ---- CJK ----------------------------------------------------------- */
html[lang="zh"] .sai-hero .h1,
html[lang="ja"] .sai-hero .h1{letter-spacing:-.01em;line-height:1.06;}
html[lang="zh"] .sai-hero .sai-meta li,
html[lang="ja"] .sai-hero .sai-meta li{letter-spacing:.04em;text-transform:none;}

/* ---- scroll: two rates, so the type separates from the field -------- */
@supports (animation-timeline:view()){
  .sai-hero .ch-art{
    animation:saiSink linear both;
    animation-timeline:view();animation-range:exit 0% exit 100%;
  }
  .sai-hero .sai-copy{
    animation:saiLift linear both;
    animation-timeline:view();animation-range:exit 0% exit 70%;
  }
}
@keyframes saiSink{from{scale:1;translate:0 0;}to{scale:1.06;translate:0 -5%;}}
@keyframes saiLift{from{translate:0 0;opacity:1;}to{translate:0 -42px;opacity:.10;}}

/* ---- breakpoints ---------------------------------------------------- */
@media (max-width:1100px){
  .interior-v2 .capability-hero--ai.sai-hero>.container{grid-template-columns:40px minmax(0,1fr);}
  .sai-hero .sai-rail{width:40px;}
  .sai-hero .sai-meta{grid-template-columns:repeat(2,minmax(0,1fr));row-gap:var(--sp-16);}
  .sai-hero .sai-meta li:nth-child(3){grid-column:1/-1;}
}
@media (max-width:720px){
  .interior-v2 .capability-hero--ai.sai-hero{min-height:520px;}
  .interior-v2 .capability-hero--ai.sai-hero>.container{
    grid-template-columns:minmax(0,1fr);
    padding-top:96px;padding-bottom:40px;
  }
  .sai-hero .sai-rail{display:none;}
  .sai-hero .sai-copy{grid-column:1;}
  .interior-v2 .capability-hero--ai.sai-hero .h1{font-size:clamp(40px,12vw,58px);line-height:.98;}
  .interior-v2 .capability-hero--ai.sai-hero .lead{font-size:17px;margin:20px 0 26px!important;}
  .interior-v2 .capability-hero--ai.sai-hero .sai-actions>.btn{flex:1 1 100%;}
  .sai-hero .sai-meta{grid-template-columns:minmax(0,1fr);row-gap:var(--sp-12);}
  .interior-v2 .capability-hero--ai.sai-hero .ch-art{
    -webkit-mask-image:linear-gradient(180deg,#000 0 calc(100% - 40px),transparent 100%);
            mask-image:linear-gradient(180deg,#000 0 calc(100% - 40px),transparent 100%);
    -webkit-mask-composite:source-over;mask-composite:add;
  }
  .interior-v2 .capability-hero--ai.sai-hero .ch-art>img{object-position:64% 50%;}
}

/* ---- reduced motion ------------------------------------------------- */
@media (prefers-reduced-motion:reduce){
  .interior-v2 .capability-hero--ai.sai-hero .ch-art{clip-path:none!important;}
  .interior-v2 .capability-hero--ai.sai-hero .ch-art>img{scale:1.02!important;translate:0 0!important;}
  .interior-v2 .capability-hero--ai.sai-hero .h1{clip-path:none!important;}
  .sai-hero .sai-rail{clip-path:none!important;}
  .sai-hero .sai-rail i,.sai-hero .sai-meta::before{transform:none!important;}
  .sai-hero .sai-rail b{display:none;}
  .interior-v2 .capability-hero--ai.sai-hero :is(.h1,.lead,.sai-meta li,.sai-actions>.btn){
    opacity:1!important;translate:0 0!important;
  }
  .sai-hero .ch-art,.sai-hero .sai-copy{animation:none!important;}
}

/* ── Per-item entrances ───────────────────────────────────────────────
   Some .reveal blocks are not one thing but a set of things: ten partner logos, six
   accordion rows. Animating the box around them makes the whole set arrive as a single
   slab, which is the flattest possible reading of a grid. Each member gets its own slice
   of the same scroll timeline instead, so the set assembles.

   The parent keeps its own animation — it carries the block, the children carry the
   detail, and because the children start later the two read as one cascade rather than
   two competing moves. */
@supports (animation-timeline: view()){
  /* Logos: a diagonal sweep across the wall. Five columns, so +1 column and +1 row both
     shift the start — nth-child(5n+k) buckets do that without a class per cell. */
  .pwall-item{
    animation:rvItem linear both;
    animation-timeline:view();
    animation-range:entry 26% entry 94%;
  }
  .pwall-item:nth-child(5n+2){animation-range:entry 29% entry 97%;}
  .pwall-item:nth-child(5n+3){animation-range:entry 32% entry 100%;}
  .pwall-item:nth-child(5n+4){animation-range:entry 35% entry 100%;}
  .pwall-item:nth-child(5n+5){animation-range:entry 38% entry 100%;}
  .pwall-item:nth-child(n+6){animation-range:entry 34% entry 100%;}

  /* Accordion rows. Deliberately on `translate`, NOT `transform`: the rows already use
     transform for their hover lift, and an entrance written in transform would overwrite
     it the moment the pointer arrived. The two properties compose instead of fighting. */
  .acc--motion .acc-item{
    animation:rvRow linear both;
    animation-timeline:view();
    /* Was `entry 24% cover 50%`, staggered out to `cover 65%` on the sixth row. Measured on
       /robotics/ with the whole list sitting inside the viewport, rows four and five were
       still at 0.64 and 0.26 opacity — fully on screen, half arrived, and staying that way
       for as long as the reader sat there. Every range now ends inside the entry phase,
       which finishes the moment the row is completely in view. */
    animation-range:entry 6% entry 82%;
  }
  .acc--motion .acc-item:nth-child(2){animation-range:entry 12% entry 86%;}
  .acc--motion .acc-item:nth-child(3){animation-range:entry 18% entry 90%;}
  .acc--motion .acc-item:nth-child(4){animation-range:entry 24% entry 94%;}
  .acc--motion .acc-item:nth-child(5){animation-range:entry 30% entry 98%;}
  .acc--motion .acc-item:nth-child(6){animation-range:entry 36% entry 100%;}

  /* Metric numerals and the tiles, where they sit as a row of peers. */
  .metrics .metric{
    animation:rvItem linear both;
    animation-timeline:view();
    animation-range:entry 26% entry 94%;
  }
  .metrics .metric:nth-child(2){animation-range:entry 30% entry 98%;}
  .metrics .metric:nth-child(3){animation-range:entry 34% entry 100%;}
  .metrics .metric:nth-child(4){animation-range:entry 38% entry 100%;}
}

@keyframes rvItem{
  0%  {opacity:0;transform:translateY(26px) scale(.965);}
  74% {opacity:1;transform:translateY(-4px) scale(1.004);}
  100%{opacity:1;transform:translateY(0) scale(1);}
}
@keyframes rvRow{
  0%  {opacity:0;translate:0 20px;}
  76% {opacity:1;translate:0 -3px;}
  100%{opacity:1;translate:0 0;}
}

@media (prefers-reduced-motion:reduce){
  .pwall-item,.acc--motion .acc-item,.metrics .metric{
    animation:none!important;opacity:1!important;translate:0 0!important;transform:none!important;
  }
}

/* ── Motion system: entrances by element type ─────────────────────────
   One entrance for everything is what makes a page read as templated — the heading, the
   photo card and the row of tiles all arriving the same way tells the eye they are the
   same kind of thing. These give each type its own character, drawn from what the element
   IS: type lifts out from behind an edge the way it would be set, cards turn into place,
   an image is wiped in rather than faded.

   All of it hangs off the same view() timeline as the base .reveal, so nothing here has
   its own clock and the whole page stays scrubbing with the scroll. Browsers without
   scroll-driven animations keep the plain rise from :522 — a graceful base, not a bug. */
@supports (animation-timeline: view()){

  /* A section wrapper holding a heading is not itself a thing that should move: moving it
     AND its children compounds two transforms into mush. Hand the motion to the children
     and let the box stay put. */
  .reveal:has(> .h2){animation:none;opacity:1;transform:none;}

  /* Every range in this block used to END in the cover phase — entry 10% cover 46% for the
     heading, cover 52%/57%/62% for the paragraphs under it, and the same shape on .pwall-item,
     .metrics .metric and the tiles below. The cover phase spans the whole time an element is
     anywhere in the viewport, so 52% of it is roughly the moment the element reaches the middle
     of the screen: text was still translucent while it was perfectly readable in position, and
     the paragraphs were behind their own heading by design, which read as "the body copy is a
     lighter grey" rather than as an animation still running. Measured on the live page at a
     normal reading position: h2 at opacity .075, both paragraphs at 0.

     This file already fixed exactly this once — the note on .reveal's own ranges says "Every
     range now ENDS inside the entry phase... The old ones ran to cover 52% and beyond, so a
     card could sit whole and centred in the viewport and still be at 61% opacity." These
     eighteen declarations were the ones that pass missed. They now end in the entry phase too,
     which finishes the moment the element is fully on screen. The staggered starts are kept, so
     the cascade is unchanged; only the finish moved earlier.

  /* HEADINGS — set, not slid. The line rises out from behind a clipping edge, the way
     type is pulled into place, instead of drifting up as a whole block.
     The end inset is negative on every side so descenders, the italic overhang and the
     accent rule underneath are never shaved off by the mask that revealed them. */
  .h2.reveal,
  .reveal:has(> .h2) > .h2{
    animation:rvHead linear backwards;
    animation-timeline:view();
    animation-range:entry 10% entry 78%;
  }
  @keyframes rvHead{
    0%  {opacity:0;clip-path:inset(0 0 100% 0);translate:0 26px;}
    62% {opacity:1;clip-path:inset(-12% -12% -30% -12%);translate:0 -3px;}
    100%{opacity:1;clip-path:inset(-12% -12% -30% -12%);translate:0 0;}
  }

  /* BODY COPY — deliberately plainer than the heading above it, and a beat behind, so the
     pair reads as one cascade rather than two elements that happen to be adjacent. */
  .reveal:has(> .h2) > p{
    animation:rvBody linear backwards;
    animation-timeline:view();
    animation-range:entry 18% entry 86%;
  }
  .reveal:has(> .h2) > p:nth-of-type(2){animation-range:entry 23% entry 91%;}
  .reveal:has(> .h2) > p:nth-of-type(3){animation-range:entry 28% entry 96%;}
  @keyframes rvBody{
    from{opacity:0;translate:0 18px;}
    to  {opacity:1;translate:0 0;}
  }

  /* TILES — turned into place. A shallow rotateY alternating by column reads as cards
     being laid down rather than a row sliding up in lockstep; the perspective is what
     stops it looking like a flat skew. */
  .tile.reveal{
    animation:rvTileA linear backwards;
    animation-timeline:view();
    animation-range:entry 14% entry 82%;
    transform-origin:50% 60%;
  }
  .tile.reveal:nth-child(even){animation-name:rvTileB;}
  @keyframes rvTileA{
    0%  {opacity:0;transform:perspective(1100px) rotateY(-9deg) translate3d(-14px,26px,-40px);}
    70% {opacity:1;transform:perspective(1100px) rotateY(1.2deg) translate3d(2px,-4px,0);}
    100%{opacity:1;transform:perspective(1100px) rotateY(0) translate3d(0,0,0);}
  }
  @keyframes rvTileB{
    0%  {opacity:0;transform:perspective(1100px) rotateY(9deg) translate3d(14px,26px,-40px);}
    70% {opacity:1;transform:perspective(1100px) rotateY(-1.2deg) translate3d(-2px,-4px,0);}
    100%{opacity:1;transform:perspective(1100px) rotateY(0) translate3d(0,0,0);}
  }

  /* IMAGE CARD — wiped, not faded. A photograph arriving by opacity looks like a slow
     connection; arriving behind a moving edge looks intentional. The picture inside eases
     out of a small overscale at the same time, so the wipe uncovers something already in
     motion rather than a still. */
  .rcard.reveal{
    animation:rvCard linear backwards;
    animation-timeline:view();
    animation-range:entry 12% entry 80%;
  }
  @keyframes rvCard{
    0%  {opacity:0;clip-path:inset(0 100% 0 0);translate:0 18px;}
    100%{opacity:1;clip-path:inset(0 0 0 0);translate:0 0;}
  }
  .rcard.reveal img{
    animation:rvCardArt linear backwards;
    animation-timeline:view();
    animation-range:entry 12% entry 80%;
  }
  @keyframes rvCardArt{from{scale:1.14;}to{scale:1;}}

  /* THE DARK PANEL — hinged from its top edge, so a block that heavy is set down rather
     than floated up. Origin at the top is the whole trick: the same rotation about the
     centre reads as a wobble. */
  .acx.reveal{
    animation:rvPanel linear backwards;
    animation-timeline:view();
    animation-range:entry 10% entry 78%;
    transform-origin:50% 0%;
  }
  @keyframes rvPanel{
    0%  {opacity:0;transform:perspective(1400px) rotateX(-7deg) translate3d(0,30px,-70px);}
    74% {opacity:1;transform:perspective(1400px) rotateX(.8deg) translate3d(0,-5px,0);}
    100%{opacity:1;transform:perspective(1400px) rotateX(0) translate3d(0,0,0);}
  }

}

/* Buttons do not animate in. They are the one thing on the page a visitor may be
   reaching for the moment it loads, and anything that delays or fades a control makes the
   page feel slower than it is — the home hero's CTA row was held at 69% opacity by an
   entrance that could not finish, which read as the buttons being washed out rather than
   as an animation still running. Whatever else moves, these are simply there.
   Covers both shapes: a button carrying .reveal itself, and the rows that hold nothing
   but buttons. */
:is(.btn,.ah-btn).reveal,
:is(.ah-cta-row,.capability-hero-actions,.sai-actions).reveal,
.reveal :is(.ah-cta-row,.capability-hero-actions,.sai-actions){
  animation:none!important;
  opacity:1!important;
  transform:none!important;
  translate:0 0!important;
  scale:1!important;
  transition-property:background,border-color,color,box-shadow!important;
}

@media (prefers-reduced-motion:reduce){
  .h2.reveal,.reveal:has(> .h2) > .h2,.reveal:has(> .h2) > p,
  .tile.reveal,.rcard.reveal,.rcard.reveal img,.acx.reveal{
    animation:none!important;opacity:1!important;
    transform:none!important;translate:0 0!important;scale:1!important;clip-path:none!important;
  }
}

/* ── Hero artwork on the banner pages ─────────────────────────────────
   One rule set for two different hosts: .independent-hero (the shared industry template)
   and .page-hero (the text bands on About, Press, Certifications and friends). Both opt
   in with .hero-art, so the artwork behaves the same wherever it lands.

   The tone modifier is not decoration — this set of banners is genuinely mixed. Measured
   on the left third of each image, the band the headline sits on: About 9/255, Press
   11/255 and Managed Services 17/255 are almost black, while Global Locations is 254/255
   and Built Environment 242/255 are almost white. One text colour cannot serve both, so
   each page declares which it got. */
.hero-art{position:relative;isolation:isolate;overflow:hidden;}
.hero-art .bg{position:absolute;inset:0;z-index:0;overflow:hidden;}
.hero-art .bg img{width:100%;height:100%;object-fit:cover;object-position:72% 50%;display:block;}
.hero-art > .container{position:relative;z-index:2;}
/* The CSS glows were standing in for artwork. With a picture behind, they read as haze. */
.hero-art .glow{display:none;}

/* A scrim on the text side only, in the artwork's own direction — it guarantees the
   headline's contrast without flattening the picture, which a full overlay would. */
.hero-art::before{
  content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
}
.hero-art--dark::before{
  background:linear-gradient(96deg,rgba(4,16,32,.92) 0%,rgba(4,16,32,.74) 34%,rgba(4,16,32,.18) 66%,transparent 100%);
}
/* No scrim on light artwork. There was one — white at .94 falling to .24 — and it was a
   white haze laid over the picture for no benefit: measured against #26292C, the text
   band of these banners already gives 14.5:1 (global locations), 13.1:1 (built
   environment) and 6.4:1 (certifications). All three clear AA untouched, so the scrim was
   buying nothing and costing the artwork its contrast. */
.hero-art--light::before{background:none;}

/* The one exception. Agriculture's text band measures 126/255 — a mid blue, not a light
   one — and dark text on it is 3.60:1, under the floor. This is the lightest veil that
   lifts it over 4.5:1, and it stops well short of the artwork's subject. */
.hero-art--veil::before{
  background:linear-gradient(96deg,rgba(var(--white-rgb),.72) 0%,rgba(var(--white-rgb),.46) 30%,rgba(var(--white-rgb),.10) 58%,transparent 78%);
}
.hero-art--veil :is(.h1,h1){color:var(--ink);}
.hero-art--veil :is(.lead,p){color:var(--text);}

/* Text colour follows the tone, not the page's usual skin. */
.hero-art--dark :is(.h1,h1){color:#fff;}
.hero-art--dark :is(.lead,p){color:rgba(var(--white-rgb),.86);}
/* The tone classes set a TOKEN rather than trying to out-specify the hero's own colour rule.
   They were (0,2,0) against .interior-v2 .page-hero .h1 at (0,3,0) and lost, which is why
   /certifications/ shipped a white headline on a gold banner — the artwork's left third was
   measured at luminance 171 and the measurement was right; only the cascade was wrong. */
.hero-art--light{--hero-ink:var(--ink);--hero-lead-ink:var(--text);}
/* The highlight word too. The site ramp is tuned for a dark ground and vanishes on a light
   one — on /certifications/ the word "excellence" was invisible against the gold. On a light
   hero it becomes solid --blue, so the word is still marked out, by colour and weight rather
   than by a gradient nobody can see.

   Written past .interior-v2 .page-hero .grad-text, which is (0,3,0): a bare
   .hero-art--light .grad-text is (0,2,0) and lost, which is how the word stayed invisible
   after the ink beside it was fixed.

   The colour is --logo-blue and not --blue, because --blue measures 2.00:1 against this
   artwork's text band and 2.70:1 against its brightest tenth — it fails the 3:1 large-text
   floor, so falling back to it would have swapped an invisible word for an illegible one.
   --logo-blue measures 4.82:1 and 6.51:1, clearing even the 4.5:1 body threshold. It is also
   a token that until now had zero references anywhere in the theme. */
.interior-v2 :is(.page-hero,.hero-image,.independent-hero) .hero-art--light .grad-text,
.interior-v2 .hero-art--light .grad-text,
.hero-art--light .grad-text{
  background:none;
  -webkit-background-clip:border-box;background-clip:border-box;
  -webkit-text-fill-color:var(--logo-blue);color:var(--logo-blue);
}
.hero-art--dark{--hero-ink:#fff;--hero-lead-ink:rgba(var(--white-rgb),.86);}
.hero-art--light :is(.h1,h1){color:var(--ink);}
.hero-art--light :is(.lead,p){color:var(--text);}

/* .page-hero--art's sizing block was here and is deleted, not out-ranked.

   Every declaration in it was already inert: the selector is (0,1,0) and both pages that
   carry the class (certifications, solution-managed-services) are interior pages, so
   .interior-v2 :is(.page-hero,…) at (0,2,0) was setting their min-height, padding and
   display already. It was one of the losing layers — the kind that makes the file read as
   though the geometry is set in five places when it is set in one. */

/* The shared industry hero already has its height; it only needs the field decoration
   suppressed, which the template does, plus the artwork sitting under its own content. */
.independent-hero.hero-art{background:#04152E;}
.independent-hero.hero-art--light{background:#F4F7FB;}

@media (max-width:820px){
  /* Portrait crops lose the right side of the composition anyway, so pull the focus back
     toward the middle and let the scrim run top-to-bottom instead of across. */
  .hero-art .bg img{object-position:62% 50%;}
  .hero-art--dark::before{background:linear-gradient(180deg,rgba(4,16,32,.62),rgba(4,16,32,.90));}
  .hero-art--light::before{background:linear-gradient(180deg,rgba(var(--white-rgb),.72),rgba(var(--white-rgb),.94));}
  .page-hero--art{padding:clamp(96px,18vw,124px) 0 clamp(56px,10vw,76px);min-height:0;}
}

/* ── Hero motion, drawn from the artwork itself ───────────────────────
   Nothing here adds a shape. Earlier passes laid rings, dots, beams and light bars over
   the banners; that is decoration parked on top of a picture, and it looked it.

   The technique instead is a second copy of the SAME image, brightened, revealed through
   a moving mask. What lights up is whatever the artwork already draws at that spot — the
   circuit traces on the engineering banner, the pylons on the energy one, the dial rings
   on manufacturing. The motion is the banner's own content, so it cannot look bolted on,
   and if the client swaps the file the effect follows the new picture with no edits.

   Everything animates mask-position, opacity or transform only. */
.hx-art{position:absolute;inset:0;z-index:1;pointer-events:none;overflow:hidden;}
.hx-art img{
  position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;object-position:inherit;
  filter:brightness(var(--hx-b,1.75)) saturate(var(--hx-s,1.35)) contrast(1.05);
}

/* SWEEP — the glow travels across. The mask is a soft band, so the artwork lights up
   progressively rather than a hard edge crossing it. */
@keyframes hxSweep{0%{mask-position:130% 0;-webkit-mask-position:130% 0}
                   100%{mask-position:-30% 0;-webkit-mask-position:-30% 0}}

/* RIPPLE — the glow expands from a point. For the banners built around one object: a
   globe, a sphere, a dial. The point is set per page so it starts where the object is. */

/* TIDE — the whole picture breathes in brightness. The quietest option, for artwork that
   is one strong subject and would be spoiled by anything crossing it. */
@keyframes hxTide{from{opacity:0}to{opacity:.55}}

/* ROTATE — a dial cut out of the banner as its own asset, turning in place.
   Two earlier attempts failed for reasons worth recording. The first laid a rotating copy
   of the whole banner over the untouched original, so both dials showed at once. The
   second cut a hole and dropped the same full-size copy behind it — but a rectangle
   rotating about a point 81% across and 46% down swings its own edges through that hole,
   which is where the empty wedges came from, and the centre was measured from the gold
   pixels' CENTROID, which the asymmetric gears around the dial pull well off the true
   axis.

   Now the dial is its own file, cropped square on the real centre with a feathered edge,
   so it has no corners to swing in and rotates about itself. The centre was found by
   scoring candidate points on how evenly gold pixels distribute around each radius — a
   concentric ring scores high, an off-axis point does not: 81.224% / 46.448%, not the
   68.5% / 28% the centroid gave.

   Geometry is set in JS because the banner is object-fit:cover — the mapping from a point
   in the image to a point on screen depends on the viewport, and a CSS percentage cannot
   express it. */
.hx-holed{
  -webkit-mask-image:radial-gradient(circle at var(--dial-x,50%) var(--dial-y,50%),transparent 0 var(--dial-in,15%),#000 var(--dial-out,20%))!important;
          mask-image:radial-gradient(circle at var(--dial-x,50%) var(--dial-y,50%),transparent 0 var(--dial-in,15%),#000 var(--dial-out,20%))!important;
}
/* One motion per hero. chArtBreath scales .ch-art 1.045 → 1.095 on a 9.5s loop; against a
   dial that is already turning it reads as the whole picture pumping. */
.hx-rotate .ch-art{animation:none;}
.hx-dial{
  position:absolute;z-index:1;pointer-events:none;
  left:var(--dial-l,0px);top:var(--dial-t,0px);
  width:var(--dial-s,0px);height:var(--dial-s,0px);
  animation:hxTurn var(--hx-d,52s) linear infinite;
  will-change:transform;
}
.hx-dial img{width:100%;height:100%;display:block;}
@keyframes hxTurn{to{rotate:360deg}}

/* DRIFT — the banner itself, panned slowly. No second copy involved. */
.hx-drift .bg img{animation:hxDrift var(--hx-d,26s) ease-in-out infinite alternate;}
@keyframes hxDrift{from{scale:1;translate:0 0}to{scale:1.05;translate:-1.6% 0}}

@media (prefers-reduced-motion:reduce){
  .hx-art,.hx-art img,.hx-dial{animation:none!important;}
  .hx-art{opacity:0!important;}
  /* the hole must close again, or the dial is simply missing */
  .hx-holed{-webkit-mask-image:none!important;mask-image:none!important;}
  .hx-dial{display:none!important;}
  .hx-drift .bg img{animation:none!important;}
}

/* ── Case study pages ─────────────────────────────────────────────────
   One layout for six cases whose content genuinely differs in shape — some carry
   Specifications, one has Client Use Cases and no Client Profile. The renderer prints the
   sections a case has, so this styles a sequence of headed blocks rather than a fixed
   template with named slots that would sit empty. */
/* The hero is deliberately NOT pulled into the body's centred column. It is the site's
   standard interior banner — full-bleed, title on the left — and every other page wears
   it that way; narrowing it here would centre twelve case studies and this press page
   against the rest of the site. Same split as the ported articles, where .pa-body is
   centred and .pa-hero stays left. */

.cs-tags{list-style:none;display:flex;flex-wrap:wrap;gap:var(--sp-8);margin:22px 0 0;padding:0;}
.cs-tags li{
  font:600 11.5px/1 var(--f-display);letter-spacing:.08em;text-transform:uppercase;
  color:var(--blue);background:color-mix(in srgb,var(--blue) 9%,transparent);
  border:1px solid color-mix(in srgb,var(--blue) 26%,transparent);
  padding:7px 11px;border-radius:999px;
}

/* A measure, not the full container. These are long technical passages — case 1's
   solution runs 336 words — and at the container's full width they would set well past a
   readable line. */
/* Cap the measure on the blocks, never on the section. .container is
   width:var(--maxw);max-width:100%, so setting max-width here rather than on the
   section keeps the 100% clamp that stops the column overflowing the viewport.

   The auto side margins are what actually centre it. An earlier version of this
   comment claimed the max-width alone "re-centres" the column; it does not — a
   block with a max-width and no auto margins stays pinned to its container's left
   edge, which on a 1560px container left the whole right half of the page empty.
   Same fix, same reason, as .pa-body. */
.cs-block,.cs-back{max-width:74ch;margin-left:auto;margin-right:auto;}
.cs-block + .cs-block{margin-top:clamp(34px,3.6vw,52px);}
.cs-block h2{margin:0 0 14px;font-size:clamp(20px,2.1vw,26px);}
.cs-block p{margin:0 0 14px;font:400 16.5px/1.72 var(--f-body);color:var(--text);}
.cs-block p:last-child{margin-bottom:0;}
.cs-back{display:flex;flex-wrap:wrap;gap:var(--sp-12);margin:clamp(44px,4.8vw,68px) auto 0;}

/* The FDE case study and the press releases need three shapes the six deck cases
   never had: a standfirst and dateline under the H1, subsection headings, and
   bullet lists. All optional — the deck cases render unchanged without them. */
.cs-date{margin:16px 0 0;font-size:13px;letter-spacing:.04em;color:var(--muted);}
.cs-block p.cs-lede{font-size:18.5px;line-height:1.7;color:var(--text-2);}
.cs-sub{margin-top:clamp(24px,2.4vw,34px);}
.cs-sub h3{margin:0 0 12px;font:600 clamp(17px,1.5vw,19.5px)/1.36 var(--f-display);color:var(--ink);}
.cs-list{margin:0 0 14px;padding:0;list-style:none;}
.cs-list li{position:relative;margin:0 0 12px;padding-left:24px;font:400 16.5px/1.72 var(--f-body);color:var(--text);}
.cs-list li:last-child{margin-bottom:0;}
.cs-list li::before{content:"";position:absolute;left:3px;top:.6em;width:7px;height:7px;border-radius:var(--radius-4);background:var(--blue);}
/* Credential badge on a press release — sized as a credential, not a hero image. */
.pr-badge{margin:0 0 26px;max-width:340px;}
.pr-badge img{display:block;width:100%;height:auto;border-radius:var(--radius-14);border:1px solid var(--card-line);}

/* ── Ported articles ─────────────────────────────────────────────────────
   Blog / whitepapers / press releases / customer stories brought over from
   beyondsoft.com/sg.

   These were briefly set in the SOURCE site's own type and colour — Roboto, black
   body, cyan un-underlined links — as a deliberate pixel-copy of the old reading
   page. The client's 25/08 review reversed that ("Insights - ported over content not
   adhering to new design"), so the ported pages now wear this theme's design like
   every other page: --f-body / --f-display, --text / --ink, --blue links, and the
   same 74ch measure .cs-block uses, so an article and a case study read alike.
   Only the STRUCTURE stays from the source — a section label over a back link, the
   title as the first line of the body, a share row at the foot — because that is
   page furniture, not styling.

   The .pa-* masthead below is now shared: the four Insights listing pages, the twelve
   case studies and the Microsoft Frontier press release all use it, so every page in
   this family opens the same way. .cs-hero, .cs-kicker and .cs-standfirst were the old
   photographic-hero treatment those pages carried and have been deleted; .cs-tags,
   .cs-date and .cs-block survive because they style content below the masthead. */
.pa-cover{margin:0 auto;padding-bottom:0;}
.pa-cover img{display:block;width:100%;max-width:1180px;height:auto;margin:0 auto;
  border-radius:var(--radius-14);border:1px solid var(--card-line);}
.pa-sep{opacity:.45;margin:0 8px;}

.pa-hero{padding:clamp(26px,3.2vw,48px) 0 clamp(28px,3.4vw,46px);}
.pa-hero-in{display:flex;align-items:flex-end;justify-content:space-between;gap:var(--sp-24);flex-wrap:wrap;}

/* ---- the Insights family's index masthead ----------------------------------
   /insights/, /press/, /whitepapers/ and /articles/ used to open on a hero — a
   3840x1287 photograph on /press/, CSS hero art on the other three — under a
   headline. The client asked for the picture to go and the type to be rebuilt.

   What replaces it reuses the ghost wordmark from the reading pages, so a listing
   and the article you reach from it are visibly the same section rather than two
   designs that happen to share a nav. The order is: wordmark, then the headline,
   then the standfirst, then a rule that the filter row sits under — an editorial
   masthead rather than a banner.

   No .page-hero here, so none of the hero art, glow layers or subpage-hero
   min-height applies; this section is only as tall as its own type. */
/* padding-top only, never the `padding` shorthand: these sections also carry .container,
   whose padding-left/right is what holds the page off the viewport edge. Writing
   `padding: X 0 0` here reset those to zero and put the masthead flush against both
   sides. */
.pa-index{padding-top:clamp(30px,4vw,64px);}
.pa-index .pa-label{margin-bottom:clamp(18px,2vw,26px);}
.pa-index-h1{
  margin:0;max-width:20ch;
  font:700 clamp(34px,4.4vw,60px)/1.06 var(--f-display);
  letter-spacing:-.03em;color:var(--ink);
}
.pa-index-lead{
  margin:clamp(16px,1.6vw,22px) 0 0;max-width:56ch;
  font:400 clamp(16px,1.35vw,18.5px)/1.62 var(--f-body);color:var(--text);
}
/* The rule is the masthead's floor and the filter row's ceiling — one line doing
   both jobs, rather than each section carrying its own margin and the gap between
   them being whatever the two happen to add up to. */
.pa-index-rule{
  margin:clamp(30px,3.6vw,52px) 0 0;
  border:0;border-top:1px solid var(--card-line);
}
/* The newsletter form on /insights/ — the one piece of furniture that came off the
   old hero and still belongs here. */
.pa-index-form{display:flex;gap:var(--sp-8);flex-wrap:wrap;max-width:460px;margin:clamp(20px,2.2vw,30px) 0 0;}
.pa-index-form input{
  flex:1;min-width:240px;
  font-family:var(--f-body);font-size:14.5px;color:var(--ink);
  background:#fff;border:1px solid var(--card-line);border-radius:var(--radius-8);padding:14px 15px;
}
@media (max-width:720px){
  .pa-index-h1{max-width:none;}
}
/* The section label.

   It used to carry an oversized outlined ghost twin of the same word behind it, echoed
   through attr(data-title) by a ::before. That is gone: it was the old site's device, and
   reproducing it here made these mastheads read as the old design rather than this one.
   The data-title attributes are left on the markup — they are inert, and they cost one
   attribute against having to re-thread nine templates if it is ever wanted back.

   What stands in its place is the setting-out drawing — see the block below .pa-share. */
.pa-label{
  position:relative;margin:0;
  /* Bigger at the client's call. Was clamp(26px,3.3vw,46px); every figure here is that
     ramp scaled by 1.26, so the shape of the response is unchanged — the word still
     reaches its ceiling at ~1415px, it is just a quarter larger through the range that
     matters. At 1440 it now sets 58px against the 60px .pa-index-h1 beneath it, which is
     the most it can take without the nameplate out-shouting the headline it introduces.

     THE FLOOR IS 29px AND IT IS MEASURED, NOT ROUNDED. The longest label in the set is
     "Customer stories" (single-bs_story.php; the other three are Insights, Whitepapers and
     Press & News), and at this weight and tracking it measures 10.19px of width for every
     1px of font-size. A 360px phone gives the container 304px between its 28px gutters, so
     anything over 29.8px wraps that one label to two lines and the nameplate doubles in
     height on the narrowest screens still worth designing for. 29px sets it at 296px, one
     line with 8px to spare. The scale factor stops applying at the bottom of the ramp for
     that reason alone.
     The extrusion below is re-cut for this size — see the note on the step. */
  font:800 clamp(29px,4.1vw,58px)/1.06 var(--f-display);
  letter-spacing:-.01em;text-transform:uppercase;color:var(--blue);
}
/* ── The letter shadow: an extrusion ──────────────────────────────────────────
   The word is a solid object with a little depth. Six copies of it step down and right at
   one pixel a time in --blue-soft, so the side face reads as one continuous block rather
   than as a shadow — the teal front face sits on top of it.

   SHALLOW AND IN THE PALETTE, not deep and dark. A fourteen-step version in the deep navy
   was built and is the obvious way to read "3D": it has more depth and far more presence.
   It was rejected because on a masthead label the navy block ends up carrying as much
   visual mass as the teal face itself, and the word stops being type with depth and starts
   being a poster device. Six steps of a colour already in the palette keeps the extrusion
   subordinate to the letterform, which is the difference between dimension and decoration.

   THE STEP IS 1PX AT FULL SIZE and that is the whole reason it is not a round number: the
   finest step a stacked text-shadow can make is one pixel, and any coarser and the diagonal
   edge of the extrusion visibly stairs.

   That is also why enlarging the label was not just a font-size change. At the old 46px the
   step was .022em over six layers — 1.01px each, 6px deep. Carrying those same six layers up
   to 58px would have made every step 1.28px and the diagonal would have started to stair, in
   the one place on the page that is nothing but diagonal edges. So the extrusion is re-cut
   rather than rescaled: eight layers at .0165em. The total is still .132em, so the word has
   exactly the same proportional depth it always had; each step is now .957px at 58px, back
   under the one-pixel line.

   At the 29px the label takes on a phone the same figure is .48px, so the steps fall
   sub-pixel and the browser smooths them on its own — the extrusion gets shallower and
   cleaner as the type gets smaller, which is the right direction, and at eight steps it is
   barely 3.8px deep there.

   WHAT THIS REPLACED. A sheared cast shadow on a ::before. The two do not combine: run
   together, the extrusion gives the word depth and the shear then throws a second,
   differently-angled shadow off a face that already has one, and the eye cannot resolve
   which light is which. The ::before is free again.

   The face colour is untouched — --blue on white, 4.02:1, which is what it was before. The
   extrusion sits behind the glyph and only ever adds edge definition. */
.pa-label{
  text-shadow:
    .0165em .0165em 0 rgb(var(--blue-soft-rgb)),
    .033em  .033em  0 rgb(var(--blue-soft-rgb)),
    .0495em .0495em 0 rgb(var(--blue-soft-rgb)),
    .066em  .066em  0 rgb(var(--blue-soft-rgb)),
    .0825em .0825em 0 rgb(var(--blue-soft-rgb)),
    .099em  .099em  0 rgb(var(--blue-soft-rgb)),
    .1155em .1155em 0 rgb(var(--blue-soft-rgb)),
    .132em  .132em  0 rgb(var(--blue-soft-rgb));
}
/* Decoration. In forced colours all six layers resolve to solid CanvasText and the word
   becomes a smear; on paper it is six passes of ink for an effect nobody asked the printer
   for. */
@media (forced-colors:active){.pa-label{text-shadow:none;}}
@media print{.pa-label{text-shadow:none;}}
.pa-back{margin:0;padding-bottom:9px;border-bottom:1px solid var(--card-line);}
.pa-back a{font:600 14px/1 var(--f-display);color:var(--blue);text-decoration:none;white-space:nowrap;}
.pa-back a:hover{text-decoration:underline;}

/* The article's own title, sized off this theme's scale rather than the source's 30px.
   It sits inside .pa-body, at the body's measure — the source prints it as the first
   line of copy and that reads well — but it is this page's <h1>. */
.pa-title{margin:0 0 18px;font:700 clamp(26px,2.9vw,36px)/1.2 var(--f-display);letter-spacing:-.02em;color:var(--ink);}

.pa-share{
  margin:clamp(40px,4.4vw,60px) 0 0;padding-top:24px;border-top:1px solid var(--card-line);
  font:600 12px/1.6 var(--f-display);letter-spacing:.14em;text-transform:uppercase;color:var(--muted);
}
.pa-share a{color:var(--blue);text-decoration:none;}
.pa-share a:hover{text-decoration:underline;}

/* ── Masthead mark: the setting-out drawing ────────────────────────────────────
   WHAT THIS REPLACES. .pa-label used to carry an oversized outlined ghost twin of its
   own word, echoed through attr(data-title) by a ::before. That was deleted — it was the
   previous site's device, and it restated at 200px a word the reader had just read at
   46px. The client asked for a new mark in its place rather than for the emptiness.

   WHAT IT IS. The masthead is drawn as a setting-out sheet. A construction axis runs
   right from the headline to the container edge, graduated over its first third the way
   a scale is; standing on that axis, its outer vertex registered exactly on the
   container's right edge, is one diamond with a concentric second inside it, and a
   registration cross on their shared centre.

   The figure is the brand's own 45-degree geometry drawn at construction scale. It is
   deliberately NOT the four-diamond rosette: reproducing the logo as wallpaper would be
   a brand violation, and the mark has to survive being seen beside the real logo in the
   header 60px above it. Two concentric diamonds are the construction the rosette is
   built from, not the rosette.

   WHY IT IS DRAWN, NOT TINTED. Everything decorative already on this site is stroke-only
   — the icon set at 1.75, the graduated rails on .cap-lede, the 72px hero grid. A tint
   patch or a gradient wash would be the one foreign object in that language, and the two
   the client has already rejected (the gold banner, the 8.6MB background plate) were both
   fills. This adds no filled shape anywhere.

   HOW IT IS BUILT. Two pseudo-elements, each a flat colour masked by an inline SVG data
   URI. Colour therefore stays in CSS tokens rather than being baked into the artwork, and
   because the mask is vector there is no moire — the 45-degree repeating-gradient lattice
   that was the obvious alternative shimmers at 125% zoom and on 1.5x displays. Two layers
   rather than one because the graduated axis is furniture and the figure is the mark:
   they are different weights and must be able to move independently.

   The plates are anchored to the section's FOOT, not its head. .pa-index-rule is the
   datum the whole drawing is measured from, and the masthead's height varies with how far
   the headline wraps — measuring down from the top would let a two-line headline push the
   axis into the type. */
.pa-index{
  position:relative;isolation:isolate;

  /* The one per-page variable. Scales the figure about its registered right vertex,
     so every page shows the same drawing at a different size and the mark still lands
     on the container edge. Nothing else differs page to page. */
  --pa-fig:1;

  --pa-ink:rgba(var(--ink-rgb),.42);      /* the axis and its graduations */
  --pa-mark:var(--blue);                  /* the figure and the register cross */
}

/* Layer 1 — the axis and its scale. */
.pa-index::before{
  content:"";position:absolute;z-index:-1;pointer-events:none;
  right:48px;bottom:0;width:760px;height:300px;
  background:var(--pa-ink);
  -webkit-mask:url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%27760%27%20height%3D%27300%27%20viewBox%3D%270%200%20760%20300%27%20fill%3D%27none%27%20stroke%3D%27%23000%27%20stroke-width%3D%271.1%27%20stroke-linecap%3D%27square%27%3E%3Cpath%20d%3D%27M190%20163H760%27%2F%3E%3Cpath%20d%3D%27M190%20156V170%27%2F%3E%3Cpath%20d%3D%27M190%20163V174M214%20163V168M238%20163V168M262%20163V168M286%20163V168M310%20163V174M334%20163V168M358%20163V168M382%20163V168M406%20163V168M430%20163V174M454%20163V168M478%20163V168M502%20163V168%27%2F%3E%3C%2Fsvg%3E") right bottom/760px 300px no-repeat;
          mask:url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%27760%27%20height%3D%27300%27%20viewBox%3D%270%200%20760%20300%27%20fill%3D%27none%27%20stroke%3D%27%23000%27%20stroke-width%3D%271.1%27%20stroke-linecap%3D%27square%27%3E%3Cpath%20d%3D%27M190%20163H760%27%2F%3E%3Cpath%20d%3D%27M190%20156V170%27%2F%3E%3Cpath%20d%3D%27M190%20163V174M214%20163V168M238%20163V168M262%20163V168M286%20163V168M310%20163V174M334%20163V168M358%20163V168M382%20163V168M406%20163V168M430%20163V174M454%20163V168M478%20163V168M502%20163V168%27%2F%3E%3C%2Fsvg%3E") right bottom/760px 300px no-repeat;
}

/* Layer 2 — the figure. Its box is square and right-aligned, so scaling --pa-fig keeps
   the outer vertex on the container edge and grows the drawing leftward along the axis.
   bottom = 137 - 115*scale keeps the centre on the axis at every size. */
.pa-index::after{
  content:"";position:absolute;z-index:-1;pointer-events:none;
  right:48px;bottom:calc(137px - 115px * var(--pa-fig));
  width:calc(230px * var(--pa-fig));height:calc(230px * var(--pa-fig));
  background:var(--pa-mark);
  -webkit-mask:url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%27230%27%20height%3D%27230%27%20viewBox%3D%270%200%20230%20230%27%20fill%3D%27none%27%20stroke%3D%27%23000%27%20stroke-linecap%3D%27square%27%3E%3Cpath%20d%3D%27M11%20115L115%2011L219%20115L115%20219Z%27%20stroke-width%3D%271.15%27%20stroke-opacity%3D%27.34%27%2F%3E%3Cpath%20d%3D%27M57%20115L115%2057L173%20115L115%20173Z%27%20stroke-width%3D%271.15%27%20stroke-opacity%3D%27.24%27%2F%3E%3Cpath%20d%3D%27M98%20115H110M120%20115H132M115%2098V110M115%20120V132%27%20stroke-width%3D%271.3%27%20stroke-opacity%3D%271%27%2F%3E%3C%2Fsvg%3E") right bottom/100% 100% no-repeat;
          mask:url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%27230%27%20height%3D%27230%27%20viewBox%3D%270%200%20230%20230%27%20fill%3D%27none%27%20stroke%3D%27%23000%27%20stroke-linecap%3D%27square%27%3E%3Cpath%20d%3D%27M11%20115L115%2011L219%20115L115%20219Z%27%20stroke-width%3D%271.15%27%20stroke-opacity%3D%27.34%27%2F%3E%3Cpath%20d%3D%27M57%20115L115%2057L173%20115L115%20173Z%27%20stroke-width%3D%271.15%27%20stroke-opacity%3D%27.24%27%2F%3E%3Cpath%20d%3D%27M98%20115H110M120%20115H132M115%2098V110M115%20120V132%27%20stroke-width%3D%271.3%27%20stroke-opacity%3D%271%27%2F%3E%3C%2Fsvg%3E") right bottom/100% 100% no-repeat;
}

/* Per page. Tighter where the masthead carries more furniture (the newsletter form on
   /insights/), larger where the band is bare. The ceiling is 1.19 rather than a round
   number: at that scale the figure's lower vertex reaches .pa-index-rule, and a figure
   that crosses its own datum has stopped standing on it. 1.10 keeps 10px of air. */
body.pg-insights        .pa-index{--pa-fig:.84;}
body.pg-articles        .pa-index{--pa-fig:1.10;}
body.pg-whitepapers     .pa-index{--pa-fig:1.10;}
body.pg-global-presence .pa-index{--pa-fig:.74;}

/* The entrance is additive: it is declared only where motion is welcome, and it fills
   "backwards" rather than "both", so the drawn state is the element's natural state.
   A cascade accident can leave this animation half-applied and the mark is still there —
   the failure mode that clipped a listing page to nothing came from a "both" fill on a
   clip-path, and is not repeated here. */
@media (prefers-reduced-motion:no-preference){
  @keyframes pa-mark-draw{from{clip-path:inset(0 100% 0 0);}to{clip-path:inset(0 0 0 0);}}
  @keyframes pa-mark-set {from{opacity:0;transform:scale(.955);}to{opacity:1;transform:none;}}
  .pa-index::before{animation:pa-mark-draw .95s var(--ease-out,cubic-bezier(.5,0,.35,1)) .12s backwards;}
  .pa-index::after {animation:pa-mark-set  .8s  var(--ease-out,cubic-bezier(.5,0,.35,1)) .5s  backwards;}
}

/* Below 1200 the void the drawing lives in is narrower than the drawing. */
@media (max-width:1199px){
  .pa-index::before{width:560px;-webkit-mask-size:560px 300px;mask-size:560px 300px;}
  .pa-index{--pa-fig:.78;}
  body.pg-insights .pa-index{--pa-fig:.68;}
  body.pg-articles .pa-index,body.pg-whitepapers .pa-index{--pa-fig:.88;}
  body.pg-global-presence .pa-index{--pa-fig:.6;}
}

/* Below 1024 there is no void at all: the headline runs to the container edge and the
   axis would strike straight through the label. The drawing does not shrink into the
   corner — a shrunken graphic always reads as a leftover. It re-forms: the axis is
   dropped, and the figure alone sits at the end of the label's own line, which is the
   one band a narrow masthead still has spare. Every page is identical here, and that is
   consistency rather than a compromise. */
@media (max-width:1023px){
  .pa-index::before,.pa-index::after{display:none;}
}

/* The compact mark. It is the same drawing at small scale, and it is also what the
   reading pages (.pa-hero on ported articles and case studies) carry at every width —
   their masthead is a label over a back link, far too short to hold the full sheet. */
.pa-label{position:relative;}
.pa-hero-in .pa-label::after,
.pa-index .pa-label::after{
  content:"";position:absolute;pointer-events:none;z-index:-1;
  right:0;top:50%;width:76px;height:76px;margin-top:-38px;
  background:var(--blue);
  -webkit-mask:url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%27230%27%20height%3D%27230%27%20viewBox%3D%270%200%20230%20230%27%20fill%3D%27none%27%20stroke%3D%27%23000%27%20stroke-linecap%3D%27square%27%3E%3Cpath%20d%3D%27M11%20115L115%2011L219%20115L115%20219Z%27%20stroke-width%3D%271.15%27%20stroke-opacity%3D%27.34%27%2F%3E%3Cpath%20d%3D%27M57%20115L115%2057L173%20115L115%20173Z%27%20stroke-width%3D%271.15%27%20stroke-opacity%3D%27.24%27%2F%3E%3Cpath%20d%3D%27M98%20115H110M120%20115H132M115%2098V110M115%20120V132%27%20stroke-width%3D%271.3%27%20stroke-opacity%3D%271%27%2F%3E%3C%2Fsvg%3E") right center/100% 100% no-repeat;
          mask:url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%27230%27%20height%3D%27230%27%20viewBox%3D%270%200%20230%20230%27%20fill%3D%27none%27%20stroke%3D%27%23000%27%20stroke-linecap%3D%27square%27%3E%3Cpath%20d%3D%27M11%20115L115%2011L219%20115L115%20219Z%27%20stroke-width%3D%271.15%27%20stroke-opacity%3D%27.34%27%2F%3E%3Cpath%20d%3D%27M57%20115L115%2057L173%20115L115%20173Z%27%20stroke-width%3D%271.15%27%20stroke-opacity%3D%27.24%27%2F%3E%3Cpath%20d%3D%27M98%20115H110M120%20115H132M115%2098V110M115%20120V132%27%20stroke-width%3D%271.3%27%20stroke-opacity%3D%271%27%2F%3E%3C%2Fsvg%3E") right center/100% 100% no-repeat;
}
/* On an index page the full sheet is already drawn above 1023, so the compact mark is
   only the small-screen form there. On a reading page it is the whole treatment. */
@media (min-width:1024px){
  .pa-index .pa-label::after{display:none;}
  .pa-hero-in .pa-label::after{width:96px;height:96px;margin-top:-48px;}
}
@media (max-width:520px){
  .pa-hero-in .pa-label::after,
  .pa-index .pa-label::after{width:56px;height:56px;margin-top:-28px;}
}

/* In forced colours a 1px 34%-alpha stroke resolves to solid CanvasText and the drawing
   becomes a fence across the masthead. It carries no information, so it goes. Same in
   print, where it would be a grey smudge across the head of the page. */
@media (forced-colors:active){
  .pa-index::before,.pa-index::after,
  .pa-index .pa-label::after,.pa-hero-in .pa-label::after{display:none;}
}
@media print{
  .pa-index::before,.pa-index::after,
  .pa-index .pa-label::after,.pa-hero-in .pa-label::after{display:none;}
}

/* Dated facts on the Mega Showcase card — a definition list, because that is
   what Date / Venue / Address actually are. */
/* ── Robotics page palette ────────────────────────────────────────────
   Removed, deliberately.

   This page used to remap --blue/--blue-hi/--teal to gold (#9E6932) because its banner was
   the purple-and-gold dial from the old design file, and the site's teal under a gold banner
   made the page change colour the moment you scrolled past the hero. The banner is now the
   "designs V2" marionette artwork, which is brand blue — so the gold has nothing left to
   agree with, and keeping it would recreate the same fault in reverse: a gold headline and a
   gold button sitting on a blue hero.

   Dropping it also answers the client's own note that layout and colour should be consistent
   across the site with only the graphic differing. If the gold is ever wanted back, it is
   this block and nothing else. */

/* ── Data page palette ────────────────────────────────────────────────
   Removed, for the same reason the Robotics one above was.

   This page remapped --blue/--blue-hi/--teal to the banner's rust (#9F4324) and then had to
   remap them BACK to teal for its own header and footer — so the page body and the site
   chrome around it were two different brands on one screen, which is precisely the "doesn't
   look tied together" the client reported. A page-scoped brand colour cannot be contained:
   every component that reads --blue follows it, and the ones that must not follow it need a
   second rule undoing the first.

   The maroon .acx panel that used to sit here has gone with them. It was kept on the
   argument that it matched this page's artwork and "the picture is allowed to differ" —
   but that artwork was the red-and-orange database banner, and this page's banner is the
   dark teal analytics plate now. A maroon panel under a teal banner matches nothing; it
   falls back to the shared .acx blue, which is what every other capability page shows. */

/* The purple-and-gold restatement of this panel went with the banner it matched — see the
   note above. .acx falls back to its own blues, which is now the whole page's palette. */
/* ── Capability page, left column ─────────────────────────────────────
   The copy column sat flat next to a panel carrying a network canvas, gradients
   and a lit border. Rather than decorate it, this borrows the drawing conventions
   the banners already use: a graduated rail and a registration cross, the marks an
   instrument face carries. Both are drawn in CSS from the column's own geometry —
   no images, no words, nothing that has to be kept in sync with the copy. */
.cap-lede{position:relative;padding-left:40px;}
/* The rail: a hairline that fades out at the foot, with ticks along it. The tick
   spacing is the body line-height, so the marks line up with the text they sit
   beside instead of floating on their own rhythm. */
.cap-lede::before{
  content:"";position:absolute;left:0;top:6px;bottom:12px;width:1.5px;
  /* colour-mix so the rail follows --blue, which each page may remap to its own
     banner's accent — a literal teal here stayed teal on a gold page. */
  background:linear-gradient(180deg,var(--blue) 0%,
    color-mix(in srgb,var(--blue) 62%,transparent) 52%,
    color-mix(in srgb,var(--blue) 10%,transparent) 100%);
}
/* Major and minor ticks, as a scale actually carries: a long mark every body line,
   a short one halfway between. Two layers rather than one, because a single
   repeating dash reads as a texture while an alternating pair reads as a scale. */
.cap-lede::after{
  content:"";position:absolute;left:0;top:6px;bottom:12px;width:13px;
  background-image:
    linear-gradient(90deg,color-mix(in srgb,var(--blue) 72%,transparent) 0 13px,transparent 0),
    linear-gradient(90deg,color-mix(in srgb,var(--blue) 38%,transparent) 0 7px,transparent 0);
  background-size:100% 27.2px, 100% 13.6px;
  background-position:0 0, 0 13.6px;
  background-repeat:repeat-y, repeat-y;
  -webkit-mask-image:linear-gradient(180deg,#000 0%,#000 66%,transparent 100%);
          mask-image:linear-gradient(180deg,#000 0%,#000 66%,transparent 100%);
}
/* Registration cross at the head of the rail, where the heading starts. */
.cap-lede .h2{position:relative;}
.cap-lede .h2::before{
  content:"";position:absolute;left:-44px;top:.46em;width:11px;height:11px;
  background:
    linear-gradient(var(--blue),var(--blue)) center/11px 1.5px no-repeat,
    linear-gradient(var(--blue),var(--blue)) center/1.5px 11px no-repeat;
  opacity:1;
}
@media (max-width:900px){
  .cap-lede{padding-left:24px;}
  .cap-lede::after{display:none;}
  .cap-lede .h2::before{left:-28px;width:7px;height:7px;
    background-size:7px 1px,1px 7px;}
}
/* SVG banner stands in for the raster one. <object>, not <img>: an SVG loaded
   through <img> does not run its animation. */
/* ── AI hero, moving ──────────────────────────────────────────────────
   The banner is a flat raster, so the motion comes from two copies of itself: the
   red mesh and the blue glow cores, separated out of the same pixels by colour and
   laid back on with screen blending. Screen only adds light, so drifting or fading
   a layer brightens and shifts what is already there rather than exposing a hole
   where the element used to be.

   They are pseudo-elements on .bg, not <img> tags. An earlier attempt added real
   images and they were caught by .interior-v2 .hero-image .bg img — a higher
   specificity rule that sizes the banner to 791px and lets .bg clip it — which
   dragged the hero from 670px to 1699px. A pseudo-element cannot be matched by an
   img selector and adds nothing to flow.

   Periods of 54s and 23s do not divide evenly, so the pair never resolves into a
   loop the eye can catch. */
.interior-v2 .capability-hero--ai.sai-hero .bg::before,
.interior-v2 .capability-hero--ai.sai-hero>.container::before{
  content:"";position:absolute;top:0;left:0;width:100%;height:100%;
  background-position:center;background-repeat:no-repeat;background-size:cover;
  mix-blend-mode:screen;pointer-events:none;will-change:transform,opacity;
}
/* Mesh: a long lateral drift with a breath of scale, so the lattice reads as
   having depth instead of sliding as a flat sheet. */
.interior-v2 .capability-hero--ai.sai-hero .bg::before{
  background-image:url("img/hero-ai-mesh.webp");
  opacity:.62;
}
/* Glow: the cores brighten and dim. Scale stays near 1 — the light pulses, not
   the geometry. */
/* Every other pseudo-element in this hero was already carrying a gradient — .bg::after,
   .sai-hero::before/::after and .sai-rail::before are all spoken for — so the glow rides
   the container, held behind the copy by a negative z-index. */
.interior-v2 .capability-hero--ai.sai-hero>.container::before{
  background-image:url("img/hero-ai-glow.webp");z-index:-1;
  opacity:.3;animation:hxAiPulse 16s ease-in-out infinite;
}
/* Amplitudes are the second pass. The first drifted 1.4% over 27s — about
   0.75px a second on a 1440px hero, which nobody can see. These move enough to
   register without asking to be watched. */

@keyframes hxAiPulse{
  0%,100%{opacity:.14;transform:scale(1.002);}
  38%    {opacity:.86;transform:scale(1.028);}
  67%    {opacity:.34;transform:scale(1.010);}
}
@media (prefers-reduced-motion:reduce){
  .interior-v2 .capability-hero--ai.sai-hero .bg::before,
  .interior-v2 .capability-hero--ai.sai-hero>.container::before{animation:none;}
}
/* Both paragraphs, one setting.
   These were deliberately set apart — the first larger with a darker first line, the
   second smaller behind a blue rule — on the reasoning that they are different kinds of
   sentence. The client's 25/08 review rejected that with the section screenshotted:
   "don't break the paragraphs further into different styling". So they share a size, a
   leading and a colour, and the rule is gone. */
.sai-lede,.sai-sub{
  max-width:52ch;margin:0 0 18px;
  font:400 16.9px/1.76 var(--f-body);color:var(--text);
}
.sai-sub{margin-bottom:0;}
/* ---------- partner row ----------------------------------------------------
   Was a bare flex row of greyscale marks on the page background. It worked at six
   logos and fell apart at two: /data/ carries only Snowflake and Databricks, and two
   small grey marks pinned to the left of a full-width band read as a section that
   failed to load rather than one with a short list.

   So the row is a band now. One cell per logo on an auto-fit grid, which means two
   logos each take half the width and six take a sixth — the band is always full,
   whatever the count. The hairlines between cells are the 1px grid gap showing the
   container's colour through, so they land correctly however the row wraps, which a
   per-cell border cannot do.

   Marks stay grey and quiet at rest and come up to full colour on hover: this is a
   credential, not a feature list, and six brand palettes at full strength would
   out-shout the page they sit in. */
.dat-partners{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(clamp(132px,15vw,190px),1fr));
  gap:var(--sp-4);
  background:var(--card-line);
  border:1px solid var(--card-line);
  border-radius:var(--radius-14);
  overflow:hidden;
}
/* The cell carries the fill, the image carries the filter. They have to be separate
   elements: a CSS filter applies to everything the element paints, its own background
   included, so putting the white behind the mark and then inverting an .on-dark logo
   turned the whole cell black. */
.dat-partners .pw-cell{
  display:flex;align-items:center;justify-content:center;
  padding:30px 22px;min-height:30px;
  background:#fff;
  transition:background var(--dur-fast) var(--ease);
}
.dat-partners .pw-cell:hover{background:#FBFDFE;}
.dat-partners img{
  max-height:30px;max-width:100%;width:auto;height:auto;object-fit:contain;
  opacity:.78;filter:grayscale(1);
  transition:opacity var(--dur-fast) var(--ease),filter var(--dur-fast) var(--ease);
}
.dat-partners .pw-cell:hover img{opacity:1;filter:none;}
/* Artwork that is white-on-transparent: inverting a white monochrome mark gives a black one. */
.dat-partners img.on-dark{filter:grayscale(1) invert(1);}
.dat-partners .pw-cell:hover img.on-dark{filter:invert(1);}

@media (max-width:560px){
  .dat-partners{grid-template-columns:repeat(2,1fr);}
  .dat-partners .pw-cell{padding:22px 14px;}
  .dat-partners img{max-height:24px;}
}
/* Label carried by artwork. The four Innovation capability cards have their own
   titles drawn into the image, so the HTML label is moved off-screen rather than
   deleted — screen readers still announce it and the i18n dictionary still
   translates it, it just is not painted twice. */
.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;
  clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0;}
.related-card{display:block;border-radius:var(--radius-14);overflow:hidden;background:var(--card);
  border:1px solid var(--card-line);box-shadow:var(--sh-contact);
  transition:transform var(--dur-base) var(--ease),box-shadow var(--dur-base) var(--ease),border-color var(--dur-fast);}
.related-card img{display:block;width:100%;height:auto;}
.related-card:hover{transform:translateY(-5px);border-color:var(--blue);
  box-shadow:0 30px 60px -28px rgba(var(--blue-rgb),.45);}
.related-card:focus-visible{outline:2px solid var(--blue);outline-offset:3px;}
@media (max-width:720px){.grid.related-art{grid-template-columns:1fr;}}
.rc-date{margin:6px 0 0;font-size:12.5px;letter-spacing:.04em;color:var(--muted);}
/* Listing pager. Plain links; the current page is the one that is not a link. */
.bs-pager{display:flex;flex-wrap:wrap;gap:var(--sp-8);justify-content:center;margin:clamp(34px,3.6vw,52px) 0 0;}
.bs-pager :is(a,span){display:inline-flex;align-items:center;justify-content:center;min-width:40px;height:40px;
  padding:0 14px;border:1px solid var(--card-line);border-radius:var(--radius-8);background:#fff;
  font:600 14px/1 var(--f-display);color:var(--ink);text-decoration:none;}
.bs-pager a:hover{border-color:var(--blue);color:var(--blue);}
.bs-pager .current{background:var(--blue);border-color:var(--blue);color:#fff;}
.bs-pager .dots{border-color:transparent;background:none;color:var(--muted);}

/* margin:0 auto centres the 768px reading column inside the wider .container — the
   source does this too, by putting justify-content:center on the flex row the column
   sits in. Missing that here was the bug: the column just sat pinned to the container's
   left edge, with the whole right side of the page empty above ~1560px. Text INSIDE
   the column stays left-aligned, exactly as the source sets it — centring the column
   is not the same as centring the text within it. */
.pa-body{max-width:74ch;margin-left:auto;margin-right:auto;font:400 16.9px/1.76 var(--f-body);color:var(--text);}
.pa-body > :first-child{margin-top:0;}
.pa-body > :last-child{margin-bottom:0;}
.pa-body p{margin:0 0 18px;}
.pa-body h2{margin:clamp(34px,3.4vw,48px) 0 14px;font:700 clamp(21px,2.2vw,27px)/1.24 var(--f-display);letter-spacing:-.015em;color:var(--ink);}
.pa-body h3{margin:clamp(26px,2.6vw,36px) 0 12px;font:600 clamp(18px,1.7vw,21px)/1.3 var(--f-display);color:var(--ink);}
.pa-body :is(h4,h5,h6){margin:24px 0 10px;font:600 17px/1.35 var(--f-display);color:var(--ink);}
.pa-body strong{font-weight:650;color:var(--ink);}
.pa-body a{color:var(--blue);text-decoration:underline;text-underline-offset:2px;text-decoration-thickness:1px;}
.pa-body a:hover{text-decoration-thickness:2px;}
.pa-body :is(ul,ol){margin:0 0 18px;padding-left:0;}
.pa-body li{position:relative;margin:0 0 10px;padding-left:24px;list-style:none;}
.pa-body li:last-child{margin-bottom:0;}
.pa-body ul > li::before{content:"";position:absolute;left:3px;top:.63em;width:7px;height:7px;border-radius:var(--radius-4);background:var(--blue);}
.pa-body ol{counter-reset:pa;}
.pa-body ol > li::before{counter-increment:pa;content:counter(pa) ".";position:absolute;left:0;top:0;
  font:600 15px/1.76 var(--f-display);color:var(--blue);}
.pa-body li :is(ul,ol){margin:10px 0 0;}
.pa-body blockquote{margin:26px 0;padding:2px 0 2px 22px;border-left:3px solid var(--blue);
  font:400 18px/1.62 var(--f-body);color:var(--text-2);}
.pa-body blockquote p:last-child{margin-bottom:0;}
.pa-body figure{margin:26px 0;}
.pa-body :is(img,iframe,video){display:block;max-width:100%;height:auto;border-radius:var(--radius-14);}
.pa-body figcaption{margin-top:10px;font:400 13.5px/1.55 var(--f-body);color:var(--muted);}
.pa-body hr{margin:34px 0;border:0;border-top:1px solid var(--card-line);}
/* Tables can be wider than the measure — they scroll in their own box so the
   page body never picks up a horizontal scrollbar. */
.pa-body :is(table,.wp-block-table){display:block;overflow-x:auto;margin:26px 0;max-width:100%;}
.pa-body table{border-collapse:collapse;font-size:15.5px;}
.pa-body :is(th,td){padding:11px 14px;border:1px solid var(--card-line);text-align:left;vertical-align:top;}
.pa-body th{background:#F6F8FB;font-weight:650;color:var(--ink);}

/* ── the editorial setting ────────────────────────────────────────────────
   Chosen from four directions that were each built, rendered and scored by three
   independent lenses (does it belong to this site / does it survive the real
   content / is it design or decoration), then narrowed by the client's 25/08 note:
   "don't break the paragraphs further into different styling".

   That note is the shape of what is left. The structure a reader navigates by —
   the section rule and its number, the figure and quote marks — is on HEADINGS and
   on elements that are not running prose. Every <p> of body copy is set identically:
   no lead paragraph in a larger face, no coloured run-in, nothing that makes one
   paragraph look unlike the one above it.

   Type and space only: no boxes, no tints, one accent. Everything degrades to
   nothing when its element is absent — an article with no h2 gets no rules and no
   numbers, one with no figure never sees that mark, and nothing depends on how many
   paragraphs a piece has (they run 14 to 31).

   .pa-share is a <p> inside .pa-body, so the paragraph rules exclude it. */

.pa-body{counter-reset:pa-sec;}
.pa-body p:not(.pa-share){margin:0 0 21px;text-wrap:pretty;}

/* Sections: a hairline the width of the measure — the same rule that closes the
   masthead above — with the section number counted in CSS, so there is no markup
   to maintain. Leading-zero ordinals are already this site's vocabulary (.bignum,
   .acc-n, .st-k, .sm-num all set 01/02), and the tracking here matches theirs at
   .16em; the draft used .08em, which read as a different family of label. */
.pa-body h2{
  position:relative;counter-increment:pa-sec;
  margin:clamp(46px,4.8vw,70px) 0 15px;
  padding-top:clamp(15px,1.5vw,20px);
  border-top:1px solid var(--card-line);
  text-wrap:balance;
}
.pa-body h3{text-wrap:balance;}
.pa-body h2::before{
  content:counter(pa-sec,decimal-leading-zero);
  display:block;margin-bottom:9px;
  font:700 12.6px/1 var(--f-display);letter-spacing:.16em;color:var(--blue);
}

/* A <strong> opening a paragraph is left as bold text. It was briefly set in the
   brand blue to read as a run-in head, which is exactly the paragraph-level
   differentiation the client's note rules out — in the articles that use this
   pattern it recurs up to fourteen times, so it would have been the loudest thing
   on the page. */

/* Displayed quotation. This is not running prose — it is quoted matter, and the
   source HTML gives it no quote marks of its own, so without a mark of some kind a
   reader cannot tell it from a paragraph. The bar is what says "quote"; all three
   reviews called its removal a net loss. Kept at 2px and in the same blue as the
   section numbers, so the page still runs on one accent. */
.pa-body blockquote{
  margin:clamp(34px,3.6vw,50px) 0;padding:2px 0 2px 22px;
  border-left:2px solid var(--blue);
  font:400 clamp(19.5px,1.8vw,22px)/1.46 var(--f-display);
  letter-spacing:-.014em;color:var(--ink);text-wrap:pretty;
}
/* :not(.pa-share) purely to out-specify .pa-body p:not(.pa-share) above, which
   at (0,2,1) otherwise beats a plain .pa-body blockquote p at (0,1,2) and leaves
   this margin dead — the exact specificity trap this file warns about elsewhere. */
.pa-body blockquote p:not(.pa-share){margin:0 0 12px;}
.pa-body blockquote p:last-child{margin-bottom:0;}

/* Figures. The caption's mark sits ABOVE it rather than to its left, so the
   caption keeps the same left edge as the prose at every width; the draft
   indented it 32px below 1000px and broke that alignment. */
.pa-body figure{margin:clamp(32px,3.4vw,46px) 0;}
.pa-body figcaption{
  position:relative;margin-top:14px;max-width:58ch;
  font-size:13.4px;line-height:1.6;
}
.pa-body figcaption::before{
  content:"";display:block;width:20px;height:0;
  border-top:1px solid var(--blue);margin-bottom:9px;
}

/* The end mark. Rounded to 2px to match .pa-body ul > li::before, which is the
   site's other small filled mark — the draft left it a sharp square, the only
   one on the page. Anchored to the share row the template always prints last,
   so it counts nothing; a piece ending on a figure or list simply gets no mark.
   :has() is load-bearing here and degrades to no mark where unsupported. */
.pa-body > p:has(+ .pa-share){margin-bottom:clamp(30px,3.4vw,44px);}
.pa-body > p:has(+ .pa-share)::after{
  content:"";display:inline-block;width:.45em;height:.45em;
  margin-left:.5em;border-radius:var(--radius-4);background:var(--blue);
}

/* Wide screens: hang the section number in the left gutter so the text keeps one
   left edge. The gate is 880px, not the draft's 1000px — .pa-body is capped at
   74ch, and the hung gutter was measured to render cleanly from 820px, so 1000px
   switched the treatment off across a wide band of ordinary laptop widths. */
@media (min-width:880px){
  .pa-body h2::before{
    position:absolute;right:100%;margin:0 17px 0 0;white-space:nowrap;
    top:calc(clamp(15px,1.5vw,20px) + 5px);
  }
}
@media (max-width:720px){
  .pa-body{max-width:none;}
}

@media (max-width:720px){
  .cs-back .btn{flex:1 1 100%;}
}

/* ── Tech Bridge ──────────────────────────────────────────────────────
   Four programme pillars and four featured solutions — reuses the Innovation Lab's card
   language so the two pages read as one programme rather than two builds. */

/* ── Dark top bar — currently OFF ─────────────────────────────────────
   White on navy. Everything here is undoing the light skin's header block (:682), which
   itself overrides the original dark header still sitting at :154 — so this is closer to
   restoring a treatment the theme already had than inventing one.
   Inert until the nav-dark body class is switched back on in functions.php (:123). */
.nav-dark .site-header{background:#0A1220;border-bottom:1px solid rgba(var(--white-rgb),.10);}
.nav-dark .site-header.scrolled{
  background:rgba(10,18,32,.92);
  -webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);
  border-bottom:1px solid rgba(var(--white-rgb),.14);
  box-shadow:none;
}
/* The home page pinned its header to solid white so the hero could dissolve into it
   (:686). With a dark bar that seam runs the other way, so the rule has to go. */
.nav-dark.home .site-header:not(.scrolled){background:#0A1220;}

.nav-dark .nav-links :is(a,button){color:rgba(var(--white-rgb),.78);}
.nav-dark .nav-links :is(a,button):hover,
.nav-dark .nav-links :is(a,button).active{color:#fff;}
.nav-dark .nav-burger span{background:#fff;}

/* The icon buttons (search, region, language) are drawn in the ink colour by the light
   skin; on navy they would be all but invisible. */
.nav-dark .site-header :is(button,a) svg{color:rgba(var(--white-rgb),.82);fill:currentColor;}
.nav-dark .site-header :is(button,a):hover svg{color:#fff;}
.nav-dark .site-header .lang-btn,
.nav-dark .site-header .region-btn,
.nav-dark .site-header .search-btn{color:rgba(var(--white-rgb),.82);}

/* Dropdown panels keep the light skin — they open over page content, not over the bar. */
.nav-dark .mega,.nav-dark .lang-menu{color:var(--ink);}

/* The Systems hero's pulse layer. Sits over the artwork inside .bg, adds light only. */
.fx-sysboard{
  position:absolute;inset:0;width:100%;height:100%;
  pointer-events:none;z-index:1;
  mix-blend-mode:screen;
}
@media (prefers-reduced-motion:reduce){ .fx-sysboard{display:none;} }

/* ---------- Systems: deployed-industry cards -------------------------------
   The artwork carries the illustration; the label is text on top of it, placed where the
   baked-in wordmark used to sit (7% from the left, across the lower quarter). Text rather
   than pixels because it has to translate, stay sharp on a retina screen, and be readable
   by a screen reader — three things a word drawn into a JPEG cannot do.

   No scrim behind the label: the left third of every one of the four images is close to
   flat #0F2038, and white on that measures better than 12:1. A gradient here would be
   solving a contrast problem that does not exist. */
/* Four across. These are a row of industries, so they read as a row — .g-4 in the markup
   already says four columns, but it steps down to two at 1000px and one at 720px, and a
   picture card cannot hold four that long. Measured: with the label sized off the card
   (below), four abreast survives down to a 1200px viewport, where the card is 263x117.
   Past that the label hits its floor while the card keeps shrinking, so it steps to two
   there instead of at 1000. The 720px rule has to be restated because these selectors sit
   later in the file than .g-4's own, and would otherwise win at phone widths. */
.dep-grid{gap:var(--sp-20);grid-template-columns:repeat(4,1fr);}
@media (max-width:1200px){.dep-grid{grid-template-columns:repeat(2,1fr);}}
@media (max-width:720px){.dep-grid{grid-template-columns:1fr;}}
.dep-card{
  position:relative;display:block;overflow:hidden;
  border-radius:var(--radius-14);
  background:#0F2038;
  /* Makes the card a query container so the label can be sized off the CARD rather than
     off the viewport. That distinction is the whole reason four-across works: the same
     1440px viewport gives a 649px card at two columns and a 319px one at four, and a
     viewport-based clamp cannot tell those apart. */
  container-type:inline-size;
  transition:transform var(--dur-base) var(--ease),box-shadow var(--dur-base) var(--ease);
}
.dep-card img{display:block;width:100%;height:auto;}
.dep-card .dep-t{
  position:absolute;left:7%;bottom:11%;
  /* Capped so a long label wraps inside the card's empty left band instead of running
     across the artwork. One value has to serve all eight pictures, so it is set by the
     one that starts its artwork earliest — dep-data, at 42.9% of the card. 42.9 less the
     7% inset, less a couple of points of air, is 35%.

     Longest consequence: "Banking & Financial Services" sets on three lines at four
     across. Three lines of 17px is 59px on a 151px card, which clears the 11% inset. */
  max-width:35%;
  font:600 clamp(20px,2.1vw,30px)/1.15 var(--f-display);
  letter-spacing:-.01em;color:#fff;
  /* Sized off the card, not the window — see container-type above. 4.96cqw is the 30px
     the two-column card used to get, expressed as a fraction of that card's width, so a
     wide card is unchanged and a four-across one lands at 17px. The plain clamp on the
     line before is the fallback for engines without container queries; browsers that do
     support them discard it for this one. */
  font-size:clamp(14px,4.96cqw,30px);
}
.dep-card:hover{transform:translateY(-2px);box-shadow:var(--sh-float);}
@media (max-width:720px){
  .dep-card .dep-t{font-size:19px;bottom:10%;}
}

/* ============================================================
   Our track record — the client roster walls on the industry pages.

   Entries are wordmarks, not images, until a licensed logo pack arrives (see the note in
   inc/bs-client-logos.php). That constraint decides the design rather than fighting it:
   a wall of one typeface at one weight is a deliberate-looking set, where 25 sourced
   logos at 25 different weights, colours and aspect ratios would be the "iconography is
   all over the place" the client already flagged. Cells are boxed on a hairline grid so
   the wall reads as a roster and not as a paragraph of comma-separated names.
   ============================================================ */
.clogos{
  list-style:none;margin:0;padding:0;
  display:grid;grid-template-columns:repeat(5,1fr);
  /* One shared hairline between cells: the container draws top and left, each cell draws
     its own right and bottom, so no border doubles up and the outer edge stays 1px. */
  border-top:1px solid var(--card-line);border-left:1px solid var(--card-line);
}
.clogo{
  display:grid;place-items:center;
  min-height:96px;padding:18px 14px;
  border-right:1px solid var(--card-line);border-bottom:1px solid var(--card-line);
  text-align:center;
}
.clogo-word{
  font:600 clamp(13px,1.05vw,15.5px)/1.3 var(--f-display);
  letter-spacing:.005em;
  color:var(--ink);
  /* Long public-sector names ("Institute of Technical Education") must wrap inside the
     cell rather than widen the column past its 1fr share. */
  overflow-wrap:anywhere;
}
.clogo-img{
  max-width:100%;max-height:50px;width:auto;height:auto;
  /* Greyed so a wall mixing supplied logos with wordmarks reads as one set; colour returns
     on hover, the same affordance the partner strip uses.

     No resting opacity: the wordmarks are 600-weight at --ink, which measures around 26/255,
     and knocking the images back to .72 landed them between 73 and 219 — every logo lighter
     than every word beside it, and the palest of them (BIPROGY) close to invisible. Grayscale
     alone is what makes the set cohere; the opacity was only making it faint. */
  filter:grayscale(1);
  transition:filter var(--dur-fast);
}
@media (hover:hover){
  .clogo:hover .clogo-img{filter:none;}
  .clogo:hover .clogo-word{color:var(--blue);}
}
@media (max-width:1080px){ .clogos{grid-template-columns:repeat(4,1fr);} }
@media (max-width:820px){  .clogos{grid-template-columns:repeat(3,1fr);} .clogo{min-height:84px;} }
@media (max-width:520px){  .clogos{grid-template-columns:repeat(2,1fr);} }
@media (prefers-reduced-motion:reduce){ .clogo-img{transition:none;} }

/* ============================================================
   Robotics hero — the client's banner, flat.

   It used to be a rig: the plate as one image with the robot lifted out of the source PDF
   as six vector sprites — head, torso, both arms, both legs — each positioned as a
   percentage of the banner and each turning about its own joint on a 2.6s walk loop, plus
   a seventh layer of puppet strings that fell away a few seconds in. All of it is gone at
   the client's call; the hero is the supplied plate and nothing else.

   Removed with it: .rb-rig, .rb-p and the six per-part positions, the rbHang settle, the
   rbLegA/B, rbArmA/B and rbHead keyframes, both of their media overrides, and the six
   sprite files. .rb-stage and .rb-base stay: they hold the plate, and .rb-base still has
   to out-specify .interior-v2 .hero-image .bg img — that rule is (0,3,1) and would
   otherwise stretch the plate to height:118%.

   ---- what the rig was, kept for the record ----

   The background is one flat image; the robot is six sprites sitting on top of it, each
   positioned as a percentage of the banner so the whole rig scales with the image and never
   needs a media query to stay registered. Percentages, origins and z-order were measured off
   the source PDF, not eyeballed.

   The motion is a marionette's, because that is what the artwork draws: the figure sways and
   rises on its strings while the limbs swing in counter-phase about their own joints. The
   amplitudes are small — 2 to 5 degrees — for two reasons. The art is drawn mid-stride, so a
   big swing bends it past what the shapes support; and the strings in the background are
   fixed, so the figure has to stay close enough to them that the join reads.
   ============================================================ */
/* Every selector below is written past .interior-v2 .hero-image .bg img — that rule is
   (0,3,1) and sets width:100% / height:118% on any image inside a hero .bg, which is exactly
   what these sprites are. A plain .rb-p loses to it and every part renders full-bleed. */
.rb-stage{position:absolute;inset:0;overflow:hidden;}
.interior-v2 .hero-image .rb-stage img.rb-base,
.hero-image .rb-stage img.rb-base{
  position:absolute;inset:0;
  width:100%;height:100%;object-fit:cover;object-position:center;display:block;
  opacity:1;mask-image:none;-webkit-mask-image:none;transform:none;
}

/* ---- The release ------------------------------------------------------------------
   One timeline, 7.4s, played once and left where it ends. Two things run on it — the rig's
   hang and the strings' fall — and they share the clock so the robot stops being suspended
   at the same instant the strings stop holding it.

     0 - 38%   (0-2.8s)   strung: the figure sways on its lines
     38 - 57%  (2.8-4.2s) the hand lets go; the strings drop away and are gone
     57 - 100%            free: the sway is out, the walk carries on alone

   The walk itself is a separate infinite loop, so it never pauses for this. */
