
:root{
  /* ---- surfaces: slate / near-black -------------------------------- */
  --ink:#05070d; --ink-2:#080b12; --edge:rgba(255,255,255,.09);
  --panel:rgba(255,255,255,.045); --panel-hi:rgba(255,255,255,.075);
  /* ---- blue ramp: navy at the dark end, steel at the lit end ------- */
  --b-100:#e0edff; --b-200:#bfdcfe; --b-300:#8fc2fb; --b-400:#60a5fa;
  --b-500:#3b82f6; --b-600:#2563eb; --b-700:#1d4ed8; --b-800:#1e3a8a; --b-900:#152a63;
  --text-primary:#e8eef7; --text-secondary:#b9c6d8; --text-muted:#9fb0c7;
  --accent:var(--b-400); --accent-contrast:#04070e;
  /* ---- craft (unchanged from the original build) ------------------- */
  --r-sm:10px; --r-md:16px; --r-lg:22px;
  --sh-1:0 1px 2px rgba(0,0,0,.5), 0 10px 30px -14px rgba(0,0,0,.85);
  --sh-2:0 2px 6px rgba(0,0,0,.55), 0 26px 56px -22px rgba(0,0,0,.95);
  --glow:0 0 34px rgba(59,130,246,.30);
  --ease:cubic-bezier(.22,.61,.36,1);
}
*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth}
body{
  color:var(--text-primary); line-height:1.55;
  font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
  -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility;
  background-color:var(--ink);
}
.wrap{max-width:1280px;margin:0 auto;padding-inline:22px}

/* ---- the gradient lettering --------------------------------------- */
/* Runs bright->navy: the lit stops carry legibility, the navy stop carries
   the colour identity. True navy alone measures 1.9:1 on this ground. */
.grad{
  background:linear-gradient(135deg,var(--b-100) 0%,var(--b-300) 38%,var(--b-400) 66%,var(--b-500) 100%);
  -webkit-background-clip:text;background-clip:text;
  color:transparent;-webkit-text-fill-color:transparent;
}
.grad-deep{
  background:linear-gradient(135deg,var(--b-200) 0%,var(--b-300) 48%,var(--b-400) 100%);
  -webkit-background-clip:text;background-clip:text;
  color:transparent;-webkit-text-fill-color:transparent;
}
/* Chiselled into the slab: dark bevel below, faint blue bloom around. */
.carve{filter:drop-shadow(0 1px 0 rgba(0,0,0,.85)) drop-shadow(0 0 26px rgba(59,130,246,.22))}

h1,h2,h3{letter-spacing:-.022em;line-height:1.06;font-weight:900}
h1{font-size:clamp(1.75rem,3.5vw,2.9rem);line-height:1.1}
h2{font-size:clamp(1.6rem,3vw,2.35rem);line-height:1.12}
h3{font-size:1.05rem;line-height:1.3}

/* ---- header -------------------------------------------------------- */
header{position:sticky;top:0;z-index:60;backdrop-filter:blur(16px) saturate(1.3);
  background:linear-gradient(180deg,rgba(5,7,13,.93),rgba(5,7,13,.78));
  border-bottom:1px solid var(--edge)}
.hrow{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:13px 0;min-width:0}
.brand{display:flex;align-items:center;gap:12px;text-decoration:none;flex:0 0 auto}
.mark{width:38px;height:38px;border-radius:11px;display:grid;place-items:center;
  background:linear-gradient(145deg,var(--b-400),var(--b-800));color:#fff;font-weight:900;font-size:14px;
  box-shadow:var(--sh-1),0 1px 0 rgba(255,255,255,.28) inset,var(--glow)}
.bname{font-size:14.5px;font-weight:800;color:#fff;line-height:1.2}
.bsub{font-size:10px;white-space:nowrap;text-transform:uppercase;letter-spacing:.15em;color:var(--text-muted)}
nav.top{display:flex;gap:19px;white-space:nowrap;flex:0 1 auto;justify-content:center}
nav.top a{font-size:13px;font-weight:600;color:var(--text-secondary);text-decoration:none;transition:color .18s var(--ease)}
nav.top a:hover{color:var(--b-300)}
@media(max-width:1400px){nav.top{display:none}}

.btn{display:inline-flex;align-items:center;gap:9px;border-radius:999px;font-weight:700;
  text-decoration:none;transition:transform .18s var(--ease),box-shadow .18s var(--ease)}
.btn-primary{background:linear-gradient(145deg,var(--b-400),var(--b-700));color:#fff;
  padding:11px 20px;font-size:13.5px;flex:0 0 auto;white-space:nowrap;
  box-shadow:var(--sh-1),0 1px 0 rgba(255,255,255,.25) inset,var(--glow)}
.btn-primary:hover{transform:translateY(-1px);box-shadow:var(--sh-2),0 0 44px rgba(59,130,246,.45)}
.btn-lg{padding:15px 30px;font-size:16px}
.btn-ghost{border:1.5px solid rgba(143,194,251,.35);color:var(--b-200);padding:13px 26px;font-size:15px;
  background:rgba(255,255,255,.04)}
.btn-ghost:hover{border-color:var(--b-400);background:rgba(59,130,246,.10)}

/* ---- section shells ------------------------------------------------ */
section{padding:78px 0}
.band{background:linear-gradient(rgba(255,255,255,.055),rgba(255,255,255,.028));
  border-block:1px solid var(--edge)}
.band-deep{background:linear-gradient(rgba(3,5,10,.42),rgba(3,5,10,.52));
  border-block:1px solid var(--edge)}
.kicker{font-size:11.5px;font-weight:800;text-transform:uppercase;letter-spacing:.19em;color:var(--b-400)}
.lede{margin-top:14px;max-width:60ch;color:var(--text-secondary);font-size:16.5px}
.sec-head{margin-bottom:40px}.sec-head h2{margin-top:11px}

/* ---- cards --------------------------------------------------------- */
.grid{display:grid;gap:20px}
.g2{grid-template-columns:repeat(2,1fr)}.g3{grid-template-columns:repeat(3,1fr)}
.g4{grid-template-columns:repeat(4,1fr)}.g5{grid-template-columns:repeat(5,1fr)}
@media(max-width:1024px){.g3,.g4,.g5{grid-template-columns:repeat(2,1fr)}}
@media(max-width:640px){.grid{grid-template-columns:1fr!important}}

.card{background:var(--panel);border:1px solid var(--edge);border-radius:var(--r-lg);
  padding:26px;box-shadow:var(--sh-1);backdrop-filter:blur(7px);
  transition:transform .22s var(--ease),box-shadow .22s var(--ease),border-color .22s var(--ease)}
.card:hover{transform:translateY(-3px);box-shadow:var(--sh-2);border-color:rgba(96,165,250,.35)}
.card p{color:var(--text-secondary);font-size:14.5px;margin-top:10px}
.metric{background:var(--panel-hi);border:1px solid var(--edge);border-radius:var(--r-md);
  padding:20px;box-shadow:var(--sh-1);backdrop-filter:blur(7px)}
.metric dt{font-size:27px;font-weight:900}
.metric dd{margin-top:6px;font-size:13.5px;color:var(--text-secondary);line-height:1.4}

.pill{display:inline-block;border:1px solid var(--edge);background:rgba(255,255,255,.05);
  border-radius:999px;padding:6px 15px;font-size:13.5px;color:var(--text-secondary);margin:0 7px 8px 0}
.tag{display:inline-block;background:rgba(96,165,250,.10);border:1px solid rgba(96,165,250,.16);
  border-radius:6px;padding:4px 9px;font-size:10.5px;font-weight:600;text-transform:uppercase;
  letter-spacing:.06em;color:var(--b-300);margin:0 5px 6px 0}
ul.bul{list-style:none;margin-top:16px;display:grid;gap:11px}
ul.bul li{display:flex;gap:11px;font-size:14.5px;color:var(--text-secondary);line-height:1.6}
ul.bul li::before{content:"";flex:0 0 auto;width:6px;height:6px;border-radius:50%;margin-top:9px;
  background:linear-gradient(145deg,var(--b-300),var(--b-700));box-shadow:0 0 10px rgba(59,130,246,.6)}

details{border-top:1px solid var(--edge);padding:17px 0}
details summary{cursor:pointer;list-style:none;display:flex;justify-content:space-between;
  align-items:center;gap:16px;font-weight:700;color:#fff;font-size:15.5px}
details summary::-webkit-details-marker{display:none}
details summary::after{content:"+";color:var(--b-400);font-size:19px;font-weight:800;transition:transform .2s var(--ease)}
details[open] summary::after{transform:rotate(45deg)}
details p{margin-top:11px;color:var(--text-secondary);font-size:14.5px}

/* ---- hero ---------------------------------------------------------- */
.hero{position:relative;overflow:hidden;padding:64px 0 68px;border-bottom:1px solid var(--edge)}
.hero::before{content:"";position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(ellipse at 18% 12%,rgba(59,130,246,.16),transparent 55%),
             radial-gradient(ellipse at 86% 88%,rgba(29,78,216,.13),transparent 52%)}
.portrait{position:absolute;top:2%;right:0;bottom:auto;width:34%;height:78%;pointer-events:none;
  -webkit-mask-image:linear-gradient(to right,transparent,#000 40%,#000 90%,transparent);
  mask-image:linear-gradient(to right,transparent,#000 40%,#000 90%,transparent)}
.portrait img{width:100%;height:100%;object-fit:contain;object-position:right top;
  filter:grayscale(.40) contrast(1.06) brightness(.85);opacity:.36}
.portrait::after{content:"";position:absolute;inset:0;
  background:linear-gradient(to top,var(--ink) 2%,transparent 40%),
             linear-gradient(to right,var(--ink),transparent 42%)}
@media(max-width:1023px){.portrait{display:none}}
.hero .inner{position:relative;max-width:62rem}
.hero .inner::before{content:"";position:absolute;inset:-40px -60px -30px -40px;z-index:-1;
  background:radial-gradient(ellipse at 30% 45%,rgba(5,7,13,.80),rgba(5,7,13,.45) 55%,transparent 78%)}
.hero h1{margin-top:22px}
.hero .sub{margin-top:22px;max-width:44rem;font-size:18px;color:var(--text-secondary)}
.hero .supp{margin-top:15px;max-width:44rem;font-size:15.5px;color:var(--text-muted)}
.ctas{margin-top:34px;display:flex;flex-wrap:wrap;gap:15px;align-items:center}
.tlink{font-size:14px;font-weight:700;color:var(--b-300);text-decoration:underline;text-underline-offset:4px}
.eyebrow{display:inline-flex;border:1px solid rgba(96,165,250,.30);background:rgba(59,130,246,.10);
  border-radius:999px;padding:7px 17px;font-size:11.5px;font-weight:700;text-transform:uppercase;
  letter-spacing:.13em;color:var(--b-200)}
.note{background:linear-gradient(145deg,var(--b-800),#0b1730);color:#cfe0f3;
  padding:11px 22px;font-size:12.5px;text-align:center}
.note b{color:var(--b-300)}
.foot{padding:44px 0;color:var(--text-muted);font-size:12.5px;border-top:1px solid var(--edge)}
.split{display:grid;gap:34px;grid-template-columns:1.35fr .95fr}
@media(max-width:900px){.split{grid-template-columns:1fr}}
input,select,textarea{padding:12px 15px;border-radius:12px;border:1px solid var(--edge);
  background:rgba(255,255,255,.05);color:var(--text-primary);font-size:14px;font-family:inherit;width:100%}
input::placeholder,textarea::placeholder{color:var(--text-muted)}

/* ================================================================== */
/* DEPTH PASS                                                          */
/* One key light, upper-left, matching the slate photograph behind the  */
/* page. Every raised surface gets the same three ingredients: a hair   */
/* of light on its top edge, a contact shadow under it, and a wider     */
/* ambient shadow. Paint-only — no compositing layers, no scroll cost.  */
/* ================================================================== */
:root{--px:.5;--py:.5;
  --edge-lit:rgba(255,255,255,.085);
  --d1:0 1px 1px rgba(0,0,0,.45), 0 6px 18px -10px rgba(0,0,0,.75);
  --d3:0 3px 6px rgba(0,0,0,.55), 0 34px 80px -34px rgba(0,0,0,.95);}

.card,.metric,.note{
  box-shadow:inset 0 1px 0 var(--edge-lit), inset 0 -1px 0 rgba(0,0,0,.35), var(--d1);
  background-image:linear-gradient(180deg,rgba(255,255,255,.045) 0%,rgba(255,255,255,.012) 38%,rgba(0,0,0,.10) 100%);
  transition:box-shadow .22s var(--ease), transform .22s var(--ease), border-color .22s ease;
}
/* Hover lifts the card off the page: the contact shadow tightens while the
   ambient one spreads. That is what happens when an object actually rises. */
.card:hover{transform:translateY(-3px);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.14), inset 0 -1px 0 rgba(0,0,0,.4), var(--d3), 0 0 0 1px rgba(59,130,246,.28);}

/* Stacked-slab section edges — light catches the top of each band and a
   shadow falls under it. More convincing and cheaper than a border. */
.band,.band-deep{border-top:1px solid var(--edge-lit);
  box-shadow:0 -14px 30px -22px rgba(0,0,0,.95) inset;}

/* The call button is the only control on this page with a job, so it is the
   one element that gets a real pressed-metal treatment. */
.btn-primary{
  box-shadow:inset 0 1px 0 rgba(255,255,255,.45), inset 0 -2px 0 rgba(0,0,0,.28),
             0 2px 0 rgba(2,6,23,.9), 0 10px 24px -10px rgba(59,130,246,.65);
  transition:transform .09s ease, box-shadow .09s ease;}
.btn-primary:active{transform:translateY(2px);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.25), inset 0 3px 8px rgba(0,0,0,.35),
             0 4px 12px -8px rgba(59,130,246,.5);}

.pill,.tag{box-shadow:inset 0 1px 0 rgba(255,255,255,.07), 0 1px 2px rgba(0,0,0,.4);}

/* Hero plate. The portrait sits on a physical plate a few centimetres in
   front of the slate. Rotation is driven by the pointer, never a timer, and
   3.2deg is deliberately small: enough to sell the parallax, small enough
   that nobody catches it moving. */
.hero{perspective:1400px;perspective-origin:calc(var(--px)*100%) calc(var(--py)*100%);}
.portrait{transform-style:preserve-3d;will-change:transform;
  transform:rotateY(calc((var(--px) - .5) * 3.2deg)) rotateX(calc((.5 - var(--py)) * 2.4deg)) translateZ(0);
  transition:transform .38s var(--ease);}
/* The specular band the rotation implies, positioned by the same two numbers. */
.portrait::before{content:"";position:absolute;inset:0;z-index:2;pointer-events:none;
  background:radial-gradient(120% 90% at calc(var(--px)*100%) calc(var(--py)*100%),
    rgba(147,197,253,.18) 0%, rgba(147,197,253,.06) 32%, transparent 62%);
  mix-blend-mode:screen;}

/* Specular sweep across the gradient lettering: the headline behaves like
   polished metal under a moving light instead of a static gradient. */
@media(hover:hover) and (pointer:fine){
  .grad{background:linear-gradient(135deg,var(--b-100) 0%,var(--b-300) calc(18% + var(--px)*26%),
        #dbeafe calc(30% + var(--px)*30%),var(--b-400) calc(58% + var(--px)*20%),var(--b-500) 100%);
        -webkit-background-clip:text;background-clip:text;}
}

/* Coarse pointers get the designed static version, not a struggling one. */
@media(hover:none),(pointer:coarse){
  .portrait{transform:none;transition:none;will-change:auto}
  .portrait::before{background:radial-gradient(120% 90% at 32% 22%,rgba(147,197,253,.16) 0%,transparent 60%)}
}

/* Reduced motion keeps every static depth cue and drops everything that moves. */
@media(prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  .card,.portrait,.btn-primary{transition:none!important}
  .portrait{transform:none!important;will-change:auto}
  .card:hover,.btn-primary:active{transform:none}
}

/* FIX: nav.top was hidden below 1400px, which is most laptops — the primary
   navigation simply vanished at 1399px with nothing to replace it. It now
   survives down to tablet width and wraps instead of disappearing. */
nav.top{flex-wrap:wrap;gap:14px;row-gap:6px}
@media(max-width:1400px){nav.top{display:flex;gap:13px;font-size:12.5px}}
@media(max-width:1180px){nav.top a{font-size:12px}}
@media(max-width:980px){nav.top{display:none}}


/* FIX: the portrait plate ended on a hard horizontal cut where its container
   stopped — a pasted rectangle, not depth. The plate now spans the full hero
   and is masked on both axes so it dissolves into the slate on every side. */
.portrait{top:0;height:100%;width:36%;
  -webkit-mask-image:linear-gradient(to right,transparent,#000 42%,#000 93%,transparent),
                     linear-gradient(to bottom,#000 0%,#000 46%,transparent 86%);
  -webkit-mask-composite:source-in;
  mask-image:linear-gradient(to right,transparent,#000 42%,#000 93%,transparent),
             linear-gradient(to bottom,#000 0%,#000 46%,transparent 86%);
  mask-composite:intersect;}
.portrait img{height:84%;object-position:right top}
.portrait::after{background:linear-gradient(to right,var(--ink),transparent 40%)}

/* FIX: at phone widths the header row overflowed and pushed the phone number
   — the one control the whole page exists to get pressed — off the right edge.
   The brand strapline is the least valuable thing in that row, so it goes. */
@media(max-width:700px){
  .hrow{gap:10px;padding:10px 0}
  .bsub{display:none}
  .bname{font-size:13.5px}
  .mark{width:32px;height:32px;border-radius:9px;font-size:12px}
  header .btn-primary{padding:10px 15px;font-size:13px;flex:0 0 auto;white-space:nowrap}
  h1{font-size:clamp(1.45rem,6.4vw,2rem)}
  .hero{padding:34px 0 44px}
  .hero .sub{font-size:16px}
  section{padding:52px 0}
  .wrap{padding-inline:18px}
}

/* ================================================================== */
/* EVEN ROWS                                                           */
/* CSS grid left-aligns a partial last row, so any count that is not a  */
/* clean multiple of the column count ended with a hole on the right —  */
/* and at n%cols==1, a single card stranded on its own row. Flex-wrap   */
/* with an explicit track width keeps the columns identical to the grid */
/* while centring whatever is left over, so every section closes        */
/* symmetrically instead of trailing off to one side.                   */
/* The 1px slack in each width absorbs sub-pixel rounding; without it a */
/* full row occasionally wraps its last item.                          */
/* ================================================================== */
.grid{display:flex;flex-wrap:wrap;gap:20px;justify-content:center;align-items:stretch}
.grid > *{flex:0 1 auto;min-width:0}
.g2 > *{width:calc((100% - 21px)/2)}
.g3 > *{width:calc((100% - 41px)/3)}
.g4 > *{width:calc((100% - 61px)/4)}
.g5 > *{width:calc((100% - 81px)/5)}
@media(max-width:1024px){
  .g3 > *,.g4 > *,.g5 > *{width:calc((100% - 21px)/2)}
}
@media(max-width:640px){
  .grid > *{width:100%!important}
}

/* Button rows: the primary button, the ghost button and the text link were
   three different heights sitting on three different baselines. One band,
   one centre line, and the row stays even when it wraps. */
.ctas{align-items:stretch;gap:14px;row-gap:12px}
.ctas > *{min-height:54px;display:inline-flex;align-items:center;justify-content:center}
.ctas .tlink{padding-inline:4px}
/* Between 700 and 900px the three-up CTA row wrapped and left the resume
   link stranded alone on a second line. Below 900 they stack as one column,
   capped so they stay button-shaped instead of spanning the hero. */
@media(max-width:900px){
  .ctas{flex-direction:column;align-items:stretch;max-width:26rem}
  .ctas > *{width:100%}
}

/* The portrait was still reading as a photograph pasted on top of the slate.
   Lower opacity and a longer, earlier bottom fade let it sink into the rock
   instead of sitting on it — no edge anywhere, on any side. */
.portrait{top:0;height:100%;width:38%;
  -webkit-mask-image:linear-gradient(to right,transparent,#000 46%,#000 92%,transparent),
                     linear-gradient(to bottom,#000 0%,rgba(0,0,0,.85) 26%,rgba(0,0,0,.45) 56%,transparent 82%);
  -webkit-mask-composite:source-in;
  mask-image:linear-gradient(to right,transparent,#000 46%,#000 92%,transparent),
             linear-gradient(to bottom,#000 0%,rgba(0,0,0,.85) 26%,rgba(0,0,0,.45) 56%,transparent 82%);
  mask-composite:intersect;}
.portrait img{height:82%;object-position:right top;opacity:.24;
  filter:grayscale(.46) contrast(1.04) brightness(.82)}
.portrait::after{background:linear-gradient(to right,var(--ink),transparent 44%),
                            linear-gradient(to top,var(--ink) 0%,rgba(5,7,13,.55) 14%,transparent 38%)}

/* A 27px display figure in a one-fifth-width card clipped "Nationwide" mid-word.
   The figure now scales with the track instead of overflowing it. */
.metric dt{font-size:clamp(18px,1.5vw,27px);overflow-wrap:anywhere;hyphens:none}
.metric{display:flex;flex-direction:column}
.metric dd{margin-top:auto;padding-top:6px}
@media(max-width:1024px){.metric dt{font-size:24px}}

/* The hero copy's backing glow bleeds 60px past its box by design; below
   desktop that bleed is wider than the gutter it has to live in. */
@media(max-width:1100px){.hero .inner::before{inset:-24px -18px -20px -18px}}

/* ================================================================== */
/* RTL — Arabic and Urdu.                                             */
/* The static build sets dir on <html> itself, so the header, footer   */
/* and every section mirror natively. Latin-script runs inside an RTL  */
/* page must be forced back to LTR or the digits reorder and the phone */
/* number silently becomes wrong — "(519) 278-5085" was rendering as   */
/* "278-5085 (519)".                                                   */
/* ================================================================== */
[dir="rtl"]{text-align:right}
[dir="rtl"] .hero .inner{margin-left:0;margin-right:auto}
[dir="rtl"] a[href^="tel:"],
[dir="rtl"] a[href^="mailto:"],
[dir="rtl"] code,
[dir="rtl"] .force-ltr{direction:ltr;unicode-bidi:isolate}
[dir="rtl"] .btn[href^="tel:"]{unicode-bidi:isolate-override;direction:ltr}
[dir="rtl"] ul.bul li::before{margin-left:0}
/* The key light flips with the reading direction, or the page is lit
   from the wrong side relative to how it is read. */
[dir="rtl"] .portrait{right:auto;left:0;
  -webkit-mask-image:linear-gradient(to left,transparent,#000 46%,#000 92%,transparent),
                     linear-gradient(to bottom,#000 0%,rgba(0,0,0,.85) 26%,rgba(0,0,0,.45) 56%,transparent 82%);
  mask-image:linear-gradient(to left,transparent,#000 46%,#000 92%,transparent),
             linear-gradient(to bottom,#000 0%,rgba(0,0,0,.85) 26%,rgba(0,0,0,.45) 56%,transparent 82%);}
[dir="rtl"] .portrait img{object-position:left top}

/* ================================================================== */
/* Portrait fade-in.                                                   */
/* Starts the moment the page paints and fills in evenly across three   */
/* full seconds, ending at the 0.24 the layout is tuned for.            */
/* The timing function is linear on purpose. Every eased curve tried    */
/* here either stalled and then rushed (ease-in-out) or was half done   */
/* in the first second (ease-out); only a straight ramp reads as the    */
/* photo slowly filling in for the whole three seconds.                 */
/* Opacity is a compositor-only property, so this costs no layout and  */
/* no repaint — it cannot move the LCP element or shift the page.      */
/* ================================================================== */
@keyframes portraitFade { from { opacity: 0 } to { opacity: .24 } }

.portrait img{
  opacity:0;
  animation: portraitFade 3s linear 0s both;
}

/* Reduced motion gets the end state immediately rather than a fade it
   did not ask for — the page still looks finished, it just skips the
   arrival. */
@media (prefers-reduced-motion: reduce){
  .portrait img{ opacity:.24; animation:none }
}

/* ================================================================== */
/* THE FUNNEL                                                          */
/* A diagram that carries information, not decoration: the width of     */
/* every band IS the drop-off it describes. Drawn once as inline SVG —  */
/* no library, no canvas, no render loop, nothing to dispose.           */
/* ================================================================== */
.funnel-wrap{margin-top:34px}
.funnel{display:block;width:100%;height:auto;max-width:1320px;margin-inline:auto;
  /* no filter: a blur this size is re-rasterised on every repaint */}
.fn-t{fill:#e8eef7;font:700 15.5px/1 var(--font,ui-sans-serif,system-ui,sans-serif);letter-spacing:-.01em}
.fn-n{fill:#9fb0c7;font:400 12.5px/1 var(--font,ui-sans-serif,system-ui,sans-serif)}

/* Staggered build. Driven by the section entering the viewport, never by a
   timer — the diagram assembles as you arrive at it and then stays put. */
.fn-band,.fn-lip,.fn-label{opacity:0;transform:translateY(14px) scaleX(.94);
  transform-origin:470px center;transform-box:view-box;
  transition:opacity .55s var(--ease), transform .65s var(--ease);
  transition-delay:calc(var(--i) * 90ms)}
.fn-label{transform:translateX(-16px)}
.reveal-in .fn-band,.reveal-in .fn-lip{opacity:1;transform:translateY(0) scaleX(1)}
.reveal-in .fn-label{opacity:1;transform:translateX(0)}

/* Below 900px the in-SVG labels would render around 4px tall, so they give
   way to a real list and the funnel keeps only its shape. */
.fn-legend{display:none}
@media(max-width:900px){
  .funnel{max-width:520px}
  .fn-label{display:none}
  .fn-legend{display:grid;gap:10px;margin:0 0 26px;padding:0;list-style:none;counter-reset:fn}
  .fn-legend li{counter-increment:fn;display:grid;grid-template-columns:26px 1fr;gap:12px;
    align-items:baseline;padding:11px 13px;border:1px solid var(--edge);border-radius:var(--r-md);
    background:rgba(255,255,255,.04)}
  .fn-legend li::before{content:counter(fn);color:var(--b-400);font-weight:800;font-size:12px}
  .fn-legend b{color:#fff;font-size:14.5px}
  .fn-legend span{grid-column:2;color:var(--text-secondary);font-size:13px;line-height:1.45}
}

/* ================================================================== */
/* SCROLL REVEAL                                                       */
/* Sections rise and settle as they enter the viewport. Driven by the   */
/* reader's scroll position, not a timer, and each element is           */
/* unobserved the moment it lands so nothing accumulates.               */
/* ================================================================== */
.reveal{opacity:0;transform:translateY(18px);
  transition:opacity .6s var(--ease), transform .7s var(--ease)}
.reveal-in{opacity:1;transform:none}

/* ================================================================== */
/* PRACTICE-AREA SPOTLIGHT                                             */
/* A light that follows the cursor across the card it is over. Applied  */
/* ONLY to the service cards, never uniformly to every card on the page */
/* — the restraint is what keeps it from reading as a template effect.  */
/* ================================================================== */
@media(hover:hover) and (pointer:fine){
  .spot{position:relative;isolation:isolate}
  .spot::before{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
    z-index:-1;opacity:0;transition:opacity .3s var(--ease);
    background:radial-gradient(420px circle at var(--mx,50%) var(--my,50%),
      rgba(96,165,250,.16), rgba(59,130,246,.05) 42%, transparent 66%)}
  .spot:hover::before{opacity:1}
}

@media(prefers-reduced-motion:reduce){
  .reveal,.fn-band,.fn-lip,.fn-label{opacity:1!important;transform:none!important;transition:none!important}
}

/* ================================================================== */
/* HERO HIERARCHY                                                      */
/* The H1 has to carry seven keyword phrases for search, which at one   */
/* size is a seven-line wall of heavy type with nowhere for the eye to  */
/* land. Splitting it into a display-weight name and a step-down role   */
/* line keeps every word in the H1 and gives the block a top.           */
/* ================================================================== */
.hero h1{font-size:clamp(1.5rem,2.75vw,2.45rem);line-height:1.14}
.hero h1 .name{display:block;font-size:1.72em;line-height:.95;letter-spacing:-.035em;
  margin-bottom:.3em}
.hero h1 .roles{display:block;font-weight:800;max-width:22ch}
@media(min-width:1024px){ .hero h1 .roles{max-width:30ch} }
@media(max-width:700px){
  .hero h1{font-size:clamp(1.28rem,5.2vw,1.7rem)}
  .hero h1 .name{font-size:1.62em}
  .hero h1 .roles{max-width:none}
}


/* ================================================================== */
/* THE GROUND                                                          */
/* This used to be `background-attachment:fixed` on <body>, which makes */
/* the compositor repaint the entire viewport on every scroll frame —   */
/* the single most expensive thing on the page, paid on every scroll of */
/* every page. A fixed pseudo-element is the identical picture as one   */
/* layer the scroller never touches again.                              */
/* ================================================================== */
body::before{
  content:"";position:fixed;inset:0;z-index:-1;pointer-events:none;
  background-color:var(--ink);
  background-image:linear-gradient(rgba(5,7,13,.62),rgba(5,7,13,.62)),url(/images/slate-hero.jpg);
  background-image:linear-gradient(rgba(5,7,13,.62),rgba(5,7,13,.62)),
    image-set(url(/images/slate-hero.avif) type("image/avif"),
              url(/images/slate-hero.webp) type("image/webp"),
              url(/images/slate-hero.jpg) type("image/jpeg"));
  background-position:center;background-size:cover;
  transform:translateZ(0);
}

/* Bound invalidation: a hover or a reveal inside one card cannot force the
   browser to re-examine the other twenty-six on the page. */
.card,.metric{contain:layout paint style}
.funnel-wrap{contain:layout paint}

/* ================================================================== */
/* THE PORTRAIT — final treatment                                      */
/* It had been sitting at 24% opacity, which is a texture, not a face.  */
/* This is a portrait now: 92% opacity, close to full colour, lit to    */
/* match the slate behind it. It still dissolves at its left and bottom */
/* edges so it belongs to the page instead of being a photo pasted on   */
/* top — but you can see who you would be hiring.                       */
/*                                                                     */
/* Safe because the copy column and the portrait do not overlap: the H1 */
/* role line is capped at 30ch and the body copy at 44rem, so text ends */
/* near x=810 at 1440px while the portrait starts at x=893.             */
/* ================================================================== */
.portrait{top:0;height:100%;width:44%;z-index:0;
  -webkit-mask-image:linear-gradient(to right,transparent 0%,rgba(0,0,0,.55) 20%,#000 44%,#000 97%,transparent),
                     linear-gradient(to bottom,#000 0%,#000 62%,rgba(0,0,0,.55) 84%,transparent 99%);
  -webkit-mask-composite:source-in;
  mask-image:linear-gradient(to right,transparent 0%,rgba(0,0,0,.55) 20%,#000 44%,#000 97%,transparent),
             linear-gradient(to bottom,#000 0%,#000 62%,rgba(0,0,0,.55) 84%,transparent 99%);
  mask-composite:intersect}

.portrait img{height:96%;object-fit:contain;object-position:right top;
  filter:grayscale(.12) contrast(1.05) brightness(.98) saturate(.95)}

/* The old ink wash existed to hide a faint image. At this opacity it would
   just grey the face out, so it becomes a soft edge-blend only. */
.portrait::after{background:linear-gradient(to right,rgba(5,7,13,.92) 0%,rgba(5,7,13,.35) 26%,transparent 52%)}

@keyframes portraitFade{from{opacity:0}to{opacity:.92}}
.portrait img{opacity:0;animation:portraitFade 3s linear 0s both}
@media(prefers-reduced-motion:reduce){.portrait img{opacity:.92;animation:none}}

/* Phones get the face too — a proper portrait band across the top of the
   hero, masked into the slate, with the copy running underneath it rather
   than across it. It was simply display:none before. */
@media(max-width:1023px){
  .hero{padding-top:0}
  .portrait{display:block;position:relative;width:100%;height:auto;
    aspect-ratio:16/10;max-height:44vh;margin:0 0 4px;
    -webkit-mask-image:linear-gradient(to bottom,#000 0%,#000 56%,rgba(0,0,0,.5) 82%,transparent 100%);
    mask-image:linear-gradient(to bottom,#000 0%,#000 56%,rgba(0,0,0,.5) 82%,transparent 100%);
    -webkit-mask-composite:source-over;mask-composite:add}
  .portrait img{height:100%;width:100%;object-fit:cover;object-position:50% 22%}
  .portrait::after{background:linear-gradient(to bottom,transparent 40%,rgba(5,7,13,.55) 82%,var(--ink) 100%)}
  .portrait::before{display:none}
}

/* The vertical fade has to live on the IMAGE, not the container. The image is
   object-fit:contain, so its box ends above the container's — a mask keyed to
   the container therefore stops fading before the photo stops, and the photo
   ends on a hard horizontal cut. Split the two axes: horizontal blend on the
   wrapper, vertical dissolve on the image itself. */
@media(min-width:1024px){
  .portrait{
    -webkit-mask-image:linear-gradient(to right,transparent 0%,rgba(0,0,0,.55) 20%,#000 44%,#000 97%,transparent);
    mask-image:linear-gradient(to right,transparent 0%,rgba(0,0,0,.55) 20%,#000 44%,#000 97%,transparent);
    -webkit-mask-composite:source-over;mask-composite:add}
  .portrait img{
    -webkit-mask-image:linear-gradient(to bottom,#000 0%,#000 58%,rgba(0,0,0,.45) 84%,transparent 100%);
    mask-image:linear-gradient(to bottom,#000 0%,#000 58%,rgba(0,0,0,.45) 84%,transparent 100%)}
}

/* The image element was 865px tall while the contained square photo rendered
   only 633px of it, so a mask keyed to the element box was still ~60% opaque
   where the photo actually ended — hence the hard horizontal cut. Letting the
   box size itself to the photo makes the mask and the picture the same thing. */
@media(min-width:1024px){
  .portrait{width:46%;align-items:flex-start;display:flex;justify-content:flex-end}
  .portrait img{width:100%;height:auto;object-fit:unset;display:block;
    -webkit-mask-image:linear-gradient(to bottom,#000 0%,#000 62%,rgba(0,0,0,.42) 86%,transparent 100%);
    mask-image:linear-gradient(to bottom,#000 0%,#000 62%,rgba(0,0,0,.42) 86%,transparent 100%)}
}

/* The 16/10 band cropped the top of the head and the bottom of the beard.
   A 4/3 band with the crop lifted keeps the whole face inside the frame. */
@media(max-width:1023px){
  .portrait{aspect-ratio:4/3;max-height:52vh}
  .portrait img{object-position:50% 14%}
}

/* ==================================================================
   PORTRAIT, final geometry.
   Desktop: half the previous size and held off the right edge, because the
   subject sits right-of-centre in the source frame and a flush box clipped
   the side of his head against the viewport.
   Below 1024px: a square, width-driven. It previously had aspect-ratio:1/1
   AND max-height:26vh, so on a wide-but-short panel the height cap won, the
   box became a letterbox and object-fit:cover sliced a band out of the face.
   ================================================================== */
@media (min-width:1024px){
  .portrait{right:2.5%;width:26%;
    -webkit-mask-image:linear-gradient(to right,transparent 0%,rgba(0,0,0,.5) 22%,#000 48%,#000 100%);
    mask-image:linear-gradient(to right,transparent 0%,rgba(0,0,0,.5) 22%,#000 48%,#000 100%);
    -webkit-mask-composite:source-over;mask-composite:add}
}
@media (max-width:1023px){
  .portrait{position:relative;width:min(320px,58vw);aspect-ratio:1/1;max-height:none;
    margin:14px auto 2px;
    -webkit-mask-image:radial-gradient(72% 68% at 50% 42%,#000 30%,rgba(0,0,0,.5) 62%,transparent 92%);
    mask-image:radial-gradient(72% 68% at 50% 42%,#000 30%,rgba(0,0,0,.5) 62%,transparent 92%);
    -webkit-mask-composite:source-over;mask-composite:add}
  .portrait img{width:100%;height:100%;object-fit:cover;object-position:50% 18%}
  .portrait::after{background:linear-gradient(to bottom,transparent 60%,rgba(5,7,13,.35) 90%,rgba(5,7,13,.6) 100%)}
}
