/* ============================================================
   Self hosted faces. 96KB for the five used weights; no third
   party request, so nothing to explain in a privacy policy.
   ============================================================ */

@font-face{
  font-family:"Big Shoulders Display"; font-style:normal; font-weight:500;
  font-display:swap; src:url("../fonts/big-shoulders-display-latin-500-normal.woff2") format("woff2");
}
@font-face{
  font-family:"Big Shoulders Display"; font-style:normal; font-weight:600;
  font-display:swap; src:url("../fonts/big-shoulders-display-latin-600-normal.woff2") format("woff2");
}
@font-face{
  font-family:"Instrument Sans"; font-style:normal; font-weight:400;
  font-display:swap; src:url("../fonts/instrument-sans-latin-400-normal.woff2") format("woff2");
}
@font-face{
  font-family:"Instrument Sans"; font-style:normal; font-weight:500;
  font-display:swap; src:url("../fonts/instrument-sans-latin-500-normal.woff2") format("woff2");
}
@font-face{
  font-family:"Instrument Sans"; font-style:normal; font-weight:600;
  font-display:swap; src:url("../fonts/instrument-sans-latin-600-normal.woff2") format("woff2");
}

/* ============================================================
   Patrick Egan cover page
   Tokens first; everything below is driven from them.
   ============================================================ */

:root{
  /* colour */
  --navy:        #2d3757;
  --navy-deep:   #232b45;
  --navy-soft:   #3c4874;
  --field-top:   #eef0f4;
  --field-bot:   #c2c8d2;
  --paper:       #f4f5f9;
  --amber:       #f2ac3c;
  --teal:        #408378;
  --teal-lift:   #4b998c;
  --scrim-rgb:   25, 42, 86;
  --rule:        rgba(45,55,87,.14);
  --rule-light:  rgba(244,245,249,.18);

  /* type */
  --display: "Big Shoulders Display", "Oswald", "Haettenschweiler", sans-serif;
  --text: "Instrument Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;

  /* measure + rhythm */
  --gut: clamp(1.25rem, 4vw, 4rem);
  --nav-h: 3.5rem;
  --overlap: 0vh;

  box-sizing: border-box;
  padding-top: env(safe-area-inset-top, 0px);
  padding-bottom: env(safe-area-inset-bottom, 0px);
}

*,*::before,*::after{ box-sizing: inherit; }

html{
  scroll-behavior: smooth;
  scroll-padding-top: calc(env(safe-area-inset-top, 0px) + 5.5rem);
  background: var(--navy);
}

body{
  margin:0;
  font-family: var(--text);
  font-size: clamp(.95rem, .55vw + .82rem, 1.0625rem);
  line-height: 1.6;
  color: var(--navy);
  background: var(--field-top);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

h4 {
font-size: clamp(1.00rem, calc(0.909rem + 0.455vw), 1.25rem);
}

img{ max-width:100%; height:auto; display:block; }
ul{ margin:0; padding:0; list-style:none; }

:where(a,button,[tabindex]):focus-visible{
  outline: 3px solid var(--amber);
  outline-offset: 3px;
  border-radius: 999px;
}

.vh{
  position:absolute; width:1px; height:1px; margin:-1px;
  padding:0; overflow:hidden; clip-path: inset(50%); white-space:nowrap;
}

/* ============================================================
   Navigation: floating glass pill group
   The full-width wrapper must not eat clicks across the page.
   ============================================================ */

.navwrap{
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 40;
  display: flex;
  justify-content: center;
  padding: calc(env(safe-area-inset-top, 0px) + .9rem) var(--gut) 0;
  pointer-events: none;
}

.navbar{ pointer-events: auto; max-width: 100%; }

.navlist{
  display: flex;
  align-items: center;
  gap: .15rem;
  padding: .3rem;
  border-radius: 999px;
  background: rgba(255,255,255,.34);
  border: 1px solid rgba(255,255,255,.5);
  box-shadow: 0 10px 30px -14px rgba(35,43,69,.45);
  backdrop-filter: blur(14px) saturate(1.3);
  -webkit-backdrop-filter: blur(14px) saturate(1.3);
  max-width: 100%;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  mask-image: linear-gradient(90deg, #000 calc(100% - 2.25rem), transparent 100%);
  -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 2.25rem), transparent 100%);
}
.navlist:not(.is-overflowing){
  mask-image: none;
  -webkit-mask-image: none;
}
.navlist::-webkit-scrollbar{ display:none; }

.pill{
  display:block;
  padding: .55rem 1.05rem;
  border-radius: 999px;
  font-family: var(--text);
  font-size: .77rem;
  font-weight: 800;
  letter-spacing: .13em;
  text-transform: uppercase;
  white-space: nowrap;
  text-decoration: none;
  color: var(--navy);
  opacity: .72;
  transition: opacity .16s ease, background-color .16s ease, color .16s ease;
}
.pill:hover{ opacity:1; }

/* Nav pills that carry a recognised icon. Below the breakpoint the label is
   visually hidden rather than removed, so the accessible name survives. */
.pill-has-ico{
  display:flex;
  align-items:flex-start;
  gap:.45rem;
}
.pico{ width:1.05rem; height:1.05rem; flex:none; }

.cta-short{ display:none; }

.navlist.is-dark{
  background: rgba(35,43,69,.5);
  border-color: rgba(244,245,249,.22);
}
.navlist.is-dark .pill{ color: var(--paper); }
.navlist.is-dark .pill.is-current{
  background: var(--paper);
  color: var(--navy);
}

/* Call to action. Deliberately not .is-current: the intersection observer
   reassigns that class on scroll, which would walk the teal off this pill. */
.pill-cta{
  background: var(--teal);
  color: var(--paper);
  opacity: 1;
  box-shadow: 0 2px 10px -4px rgba(35,43,69,.4);
}
.pill-cta:hover{ background: var(--teal-lift); opacity: 1; }
/* holds over the panel, where .navlist.is-dark would otherwise repaint it */
.navlist.is-dark .pill-cta{ background: var(--teal); color: var(--paper); }
.navlist.is-dark .pill-cta:hover{ background: var(--teal-lift); }

.pill.is-current{
  background: var(--teal);
  color: var(--paper);
  opacity: 1;
  box-shadow: 0 2px 10px -4px rgba(35,43,69,.4);
}

/* ============================================================
   Hero: sticky inside a wrapper that ends before the panel,
   so the panel rides up over it on ordinary page scroll.
   ============================================================ */

.herowrap{ height: calc(100vh + var(--overlap)); }

.hero{
  position: sticky;
  top: 0;
  height: 100vh;
  min-height: 34rem;
  overflow: hidden;
  background:
    radial-gradient(120% 80% at 50% 118%, rgba(45,55,87,.22), transparent 62%),
    linear-gradient(176deg, var(--field-top) 0%, #dfe3ea 46%, var(--field-bot) 100%);
  z-index: 1;
}

/* isometric lattice carried over from the previous design */
.lattice{
  position:absolute; inset:0;
  pointer-events:none;
  opacity:.9;
  background-image:
    repeating-linear-gradient( 30deg, rgba(45,55,87,.175) 0 1px, transparent 1px 122px),
    repeating-linear-gradient(150deg, rgba(45,55,87,.175) 0 1px, transparent 1px 122px),
    repeating-linear-gradient( 90deg, rgba(45,55,87,.15) 0 1px, transparent 1px 211px);
  mask-image: linear-gradient(180deg, transparent 0%, #000 26%, #000 72%, transparent 99%);
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 26%, #000 72%, transparent 99%);
  background-color: rgba(25, 42, 86, .077);
}

/* The name is the marquee. It sits behind the cut-out portrait. */
.marquee{
  position:absolute;
  left:50%; top: clamp(5.75rem, 11.5vh, 8.25rem);
  transform: translateX(-50%);
  width: calc(100% - (var(--gut) * 1.2));
  margin:0;
  z-index: 2;
  font-family: var(--display);
  font-weight: 600;
  font-size: clamp(2.5rem, 17.8vw, 18.5rem);
  line-height: .78;
  letter-spacing: -.005em;
  text-align: center;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--navy);
  text-shadow: 0 1px 0 rgba(255,255,255,.22);
}

.portrait{
  position:absolute;
  left:50%; 
  bottom:150px;
  transform: translateX(-50%);
  z-index: 3;
  display:flex;
  align-items:flex-end;
  justify-content:center;
    height: min(84vh, 69rem);
    width: min(69vw, 50rem);
    /* box-sizing is border-box, so this reserves headroom for the nav and
       keeps the crown of the head inside the viewport on short displays */
    padding-top: 11.25rem;
  pointer-events:none;
  filter: drop-shadow(0 30px 40px rgba(35,43,69,.48));
  mask-image: linear-gradient(180deg, #000 80%, rgba(0,0,0,.38) 93%, transparent 100%);
  -webkit-mask-image: linear-gradient(180deg, #000 80%, rgba(0,0,0,.38) 93%, transparent 100%);
}
.portrait img{
  height:100%; width:auto;
  max-width:100%;
  object-fit: contain;
  object-position: center bottom;
}

/* Hero foot: identity bottom-left, pitch bottom-right */
.scrim{ display: none; }

.herofoot{
  position:absolute;
  inset: auto 0 0 0;
  z-index: 4;
  display:grid;
  grid-template-columns: minmax(0, 40rem) minmax(0, 24rem);
  align-items: end;
  justify-content: space-between;
  gap: 1.5rem clamp(1.5rem, 5vw, 5rem);
  /* No band behind the content any more. The hero's own light field carries
     it, and the navy panel rising into view is the visual break instead. */
  padding: var(--gut);
}

.herofoot::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  border-radius: inherit;

  -webkit-backdrop-filter: blur(22px);
  backdrop-filter: blur(22px);

  -webkit-mask-image: linear-gradient(
    to bottom, transparent 0%, black 35%
  );
  mask-image: linear-gradient(
    to bottom, transparent 0%, black 25%
  );
}

.identity{ min-width:0; }

.status{
  display:flex; align-items:center; gap:.55rem;
  width: fit-content;
  margin: 0 0 1.1rem;
  padding: .36rem .85rem .36rem .7rem;
  border-radius: 999px;
  background: var(--amber);
  border: 1px solid var(--rule);
  font-size: .78rem;
  line-height:1.2;
  color: var(--navy-soft);
}
.dot{
  width:.5rem; height:.5rem; border-radius:50%;
  background: var(--teal);
  box-shadow: 0 0 0 3px rgba(64,131,120,.22);
  flex: none;
}

.role{
  margin:0;
  font-family: var(--display);
  font-weight: 500;
  font-size: clamp(2.75rem, 5.4vw, 4.4rem);
  line-height: .95;
  letter-spacing: .015em;
  text-transform: uppercase;
  color: var(--navy);
  border-top: 7px solid var(--amber);
  padding-top: .42rem;
  display:block;
  width: fit-content;
  max-width: 100%;
}

.herocol{ 
min-width:0; 
margin-bottom:2vh;
}

.herobio{ margin-top: 1rem; max-width: 40rem; }

/* Two columns halve the height of the bio block, which is what lets the
   scrim come down and leave more of the headshot unobstructed. One
   paragraph per column, kept whole. */
@media (min-width: 1001px){
  .herobio{
    columns: 2;
    column-gap: 2.25rem;
  }
  .herobio p{ break-inside: avoid; margin-bottom: 0; }
  /* one paragraph cannot be kept whole and also fill two columns */
  .herobio p:only-child{ break-inside: auto; }
}
.herobio p{
  font-size: .92rem;
  line-height: 1.62;
  margin-bottom: .78rem;
}
.herobio p:last-child{ margin-bottom: 0; }
/* .prose p sets a light colour further down the file, so this needs the extra
   class to win rather than relying on source order */
.prose.herobio p{ color: var(--navy-deep); }

.sectorblock .block-h{ margin-top: 1.25rem; margin-bottom: .7rem; color: var(--navy); }

.lead{
  margin: 0 0 1.1rem;
  max-width: 24rem;
  font-size: .97rem;
  line-height: 1.55;
  color: var(--paper);
}

/* ============================================================
   Action pills
   Icon is pinned left so a wrapped label cannot shift it.
   ============================================================ */

.actionrow{ display:flex; flex-wrap:wrap; gap:.55rem; align-items:center; }
.actions{ display:flex; flex-wrap:wrap; gap:.55rem; }

.btn{
  position:relative;
  display:inline-flex;
  align-items:center;
  gap:.5rem;
  min-width:0;
  padding: .62rem 2.35rem .62rem 2.5rem;
  border:1px solid transparent;
  border-radius: 999px;
  background: var(--teal);
  color: var(--paper);
  font-family: var(--text);
  font-size: .85rem;
  font-weight: 600;
  letter-spacing: .01em;
  line-height:1.25;
  text-decoration:none;
  cursor:pointer;
  transition: background-color .18s ease, color .18s ease, border-color .18s ease, transform .18s ease;
}
.btn:hover{ background: var(--teal-lift); }
.btn:active{ transform: translateY(1px); }
.btn-t{ min-width:0; }

.ico{
  position:absolute;
  left:.95rem; top:50%;
  margin-top:-.6875rem;
  width:1.375rem; height:1.375rem;
  flex:none;
}
.arr{
  position:absolute;
  right:.85rem; top:50%;
  margin-top:-.5rem;
  width:1rem; height:1rem;
  opacity:.75;
  transition: transform .18s ease, opacity .18s ease;
}
.btn:hover .arr{ transform: translateX(3px); opacity:1; }

.btn-ghost{
  background: transparent;
  color: var(--navy);
  border-color: rgba(45,55,87,.32);
}
.btn-ghost:hover{ background: rgba(45,55,87,.08); }

.btn-light{ background: var(--teal); }
.btn-ghost-light{
  background: transparent;
  color: var(--paper);
  border-color: var(--rule-light);
}
.btn-ghost-light:hover{ background: rgba(244,245,249,.1); }

/* ============================================================
   Panel: travels up over the hero
   ============================================================ */

.panel{
  position: relative;
  display: flex;
  flex-direction: column;
  z-index: 5;
  margin-top: calc(var(--overlap) * -1);
  border-radius: 1.75rem 1.75rem 0 0;
  background: linear-gradient(to bottom,
    rgb(var(--scrim-rgb)) 0%,
    var(--navy) 100%);
  color: var(--paper);
  box-shadow: 0 -22px 50px -24px rgba(35,43,69,.6);
  padding: clamp(1.5rem, 4vh, 2.5rem) var(--gut) 0;
}

/* The rounded shoulder and the lift only make sense once the panel is
   carrying something. Empty, it collapses to nothing. The moment any
   element is added inside it this stops matching and the card edge,
   the shadow and the padding all come back on their own. */
.panel:not(:has(*)) {
  border-radius: 0;
  box-shadow: none;
  padding: 0;
}

.block{
  width: 100%;
  max-width: 62rem;
  margin: 0 auto;
  padding-block: clamp(1.75rem, 4.5vh, 2.75rem);
  border-top: 1px solid var(--rule-light);
  display: grid;
  grid-template-columns: minmax(0, 13rem) minmax(0, 1fr);
  gap: .75rem clamp(1.5rem, 4vw, 3.5rem);
  align-items: start;
}
.block:first-of-type{ border-top:0; padding-top:0; }

.block-h{
  margin:0;
  font-family: var(--display);
  font-weight: 500;
  font-size: clamp(1.77rem, 2.77vw, 2.77rem);
  line-height: 1;
  letter-spacing: .02em;
  text-transform: uppercase;
  color: var(--amber);
}

.prose{ max-width: 52ch; }
.prose p{
  margin: 0 0 1.05rem;
  color: rgba(244,245,249,.88);
  line-height: 1.72;
}
.prose p:last-child{ margin-bottom:0; }
.prose[data-pre]{ white-space: pre-line; }

.sectors{
  display:flex; flex-wrap:wrap; gap:.5rem;
}
.sectors li{
  padding:.42rem .95rem;
  border-radius:999px;
  border:1px solid rgba(244,245,249,.42);
  background: rgba(244,245,249,.22);
  font-size:.85rem;
  color: var(--navy-soft);
}

.block-contact{ align-items:center; }
.contact-h{
  color: var(--paper);
  font-size: clamp(1.6rem, 3.2vw, 2.6rem);
  text-transform: none;
  letter-spacing: .005em;
  max-width: 13rem;
}

.foot{
  background: var(--navy);
  color: rgba(244,245,249,.55);
  font-size: .78rem;
  letter-spacing: .04em;
  padding: .75rem var(--gut) calc(env(safe-area-inset-bottom, 0px) + 1.75rem);
}

/* keeps the rule and the content on the same 62rem measure the panel uses,
   without adding a wrapper inside the branding block */
.foot > div{
  width: 100%;
  max-width: 62rem;
  margin: 0 auto;
  padding-top: 0rem;
  border-top: 0px solid var(--rule-light);
}

.foot p{ margin:0; }

/* ============================================================
   Business card overlay
   ============================================================ */

.cardmodal{
  border:0;
  padding: 0;
  max-width: min(42rem, 92vw);
  background: transparent;
  overflow: visible;
}
.cardmodal::backdrop{
  background: rgba(35,43,69,.72);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.cardmodal img{
  width:100%;
  border-radius: .9rem;
  box-shadow: 0 30px 70px -20px rgba(0,0,0,.6);
}
.cardclose{
  display:block;
  margin: 1rem auto 0;
  padding:.5rem 1.4rem;
  border-radius:999px;
  border:1px solid rgba(244,245,249,.4);
  background: transparent;
  color: var(--paper);
  font-family: var(--text);
  font-size:.78rem;
  font-weight:600;
  letter-spacing:.12em;
  text-transform:uppercase;
  cursor:pointer;
}
.cardclose:hover{ background: rgba(244,245,249,.12); }

/* ============================================================
   Narrow screens
   ============================================================ */

@media (max-width: 1000px){
  :root{ --overlap: 0vh; }

  /* A cover page this dense cannot hold one phone screen, so below 1000 the
     hero flows instead: name, portrait, then the content band underneath.
     Absolute positioning here is what put the bio across the face. */
  .herowrap{ height: auto; }

  .hero{
    position: relative;
    height: auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
  }

  .marquee{
    position: relative;
    left: auto; top: auto;
    transform: none;
    width: auto;
    margin: clamp(5rem, 13vh, 7rem) var(--gut) 0;
    font-size: clamp(3rem, 21vw, 9rem);
  }

  .portrait{
    position: relative;
    left: auto; top: auto; bottom: auto;
    transform: none;
    width: min(74vw, 27rem);
    height: auto;
    margin: -1.25rem auto -100px;
    padding-top: 0;
      filter: drop-shadow(0 30px 40px rgba(35,43,69,.18));
    mask-image: linear-gradient(180deg, #000 72%, rgba(0,0,0,.35) 90%, transparent 100%);
    -webkit-mask-image: linear-gradient(180deg, #000 72%, rgba(0,0,0,.5) 90%, transparent 100%);
  }
  .portrait img{ height: auto; width: 100%; }

  /* the fixed scrim only makes sense over an absolutely placed foot */
  .scrim{ display: none; }

  .herofoot{
    position: relative;
    inset: auto;
    grid-template-columns: minmax(0, 1fr);
    align-items: start;
    justify-content: stretch;
    gap: 1.75rem;
    margin-top: 0;
    padding: var(--gut);
    background: rgba(255, 255, 255, .28);
  }

  .herobio{ max-width: 36rem; }
}

@media (max-width: 820px){
  /* Stacked pills: icon over label, the tab-bar pattern.
     This block used to visually hide the label on any pill carrying an icon,
     on the assumption that the only icons were mail and LinkedIn, whose
     glyphs explain themselves. Once nav rows became client editable that
     assumption died: a globe or a generic document tells a phone user
     nothing, and the call to action could lose its own words purely because
     someone picked an icon for it. Stacking keeps every label and is in fact
     narrower than the same icon with the label inline, because both the
     horizontal gap and the label's full width stop being paid for. */
  .navlist{ align-items: stretch; }

  .pill{
    display:flex;
    align-items:center;
    justify-content:center;
    padding: .45rem .6rem;
  }

  .pill-has-ico{
    flex-direction: column;
    align-items: center;
    gap: .2rem;
    padding: .4rem .5rem;
  }

  .pill .pill-t{
    display:block;
    max-width: 9ch;
    overflow:hidden;
    text-overflow: ellipsis;
    font-size: .58rem;
    letter-spacing: .06em;
  }

  /* The call to action is the one label a visitor most needs to read, so it
     never collapses and carries a wider ellipsis budget than its neighbours.
     Floor, not preference: this must not depend on the client's icon choice. */
  .pill-cta .pill-t{ max-width: none; }

  /* A fourth pill is what actually costs room, so the CTA gives ground only
     when one exists. Three pills keep the full label from 390 up. */
  .navlist:has(li:nth-child(4)) .pill-cta .pill-t{ max-width: 13ch; }
}

@media (max-width: 375px){
  /* Four stacked pills need about 316px at a 9ch budget and only 278 is
     available at 320, so the budget tightens. It tightens ONLY when a fourth
     pill exists, because clamping a three pill group here would truncate
     "LinkedIn" on an iPhone SE to solve a problem that group does not have. */
  .pill-cta .pill-t{ max-width: 17ch; }
  .navlist:has(li:nth-child(4)) .pill-t{ max-width: 7ch; }
  .navlist:has(li:nth-child(4)) .pill-cta .pill-t{ max-width: 10ch; }
}

@media (max-width: 560px){
  .marquee{ white-space: normal; line-height:.84; }
  .portrait{ width: min(100vw, 28rem);       filter: drop-shadow(0 30px 40px rgba(35,43,69,.77));  }
  .btn{ padding-right: 2.15rem; }
  .navlist{ padding: .25rem; }
  .pill{ padding: .5rem .8rem; font-size: .645rem; letter-spacing: .1em; }
}

@media (max-width: 434px){
  /* Measured: with icons the group needs 379px for the full label and 309 for
     the short one. Below about 435 the full label no longer fits, and the call
     to action is what clips, so its label shortens before anything else does. */
  .cta-full{ display:none; }
  .cta-short{ display:inline; }
}

@media (max-width: 350px){
  /* Below about 351 even the short label will not fit alongside the anchor.
     The in-page anchor goes first: it is the only nav item whose destination
     is reachable by simply scrolling. */
  .nav-anchor{ display:none; }
}

@media (max-width: 344px){
  /* Nav labels are client editable now, so the old two-label swap on the call
     to action no longer applies once the data loads. Tighten the pills instead,
     which works whatever the client types. */
  .pill{ padding: .45rem .62rem; letter-spacing: .06em; }
  .pill-has-ico{ padding-left: .55rem; padding-right: .55rem; }
}

@media (prefers-reduced-motion: reduce){
  html{ scroll-behavior:auto; }
  *,*::before,*::after{
    animation-duration:.001ms !important;
    transition-duration:.001ms !important;
  }
}
