/* ============================================================================
   vpshimpi.com — base, layout, components, motion. Built on tokens.css.

   The layout variants the design panel toggled (data-hero, data-opener,
   data-density) are kept as plain attribute selectors on <body>, so the three
   choices can still be changed by editing one attribute -- without shipping
   React, Babel and a tweaks panel to visitors.
   ============================================================================ */

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--fs-md);
  line-height: var(--lh-body);
  font-weight: var(--fw-regular);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

::selection { background: var(--accent-tint); color: var(--accent-deep); }

a { color: var(--accent); text-decoration: none; transition: color var(--dur) var(--ease); }
a:hover { color: var(--accent-deep); }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: var(--fw-regular);
  color: var(--ink);
  letter-spacing: var(--ls-display);
  line-height: var(--lh-heading);
  text-wrap: balance;
  margin: 0;
}
p { text-wrap: pretty; margin: 0; }

:focus-visible { outline: none; box-shadow: var(--shadow-focus); border-radius: var(--r-sm); }

/* Keyboard users land on the content, not the whole nav, every time. */
.skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--accent); color: #fff; padding: var(--sp-3) var(--sp-4);
  border-radius: 0 0 var(--r-md) 0; font-weight: var(--fw-semibold);
}
.skip:focus { left: 0; color: #fff; }

/* ---- Layout primitives ---- */
.wrap { max-width: var(--maxw); margin-inline: auto; padding-inline: var(--gutter); }
.wrap-wide { max-width: var(--maxw-wide); margin-inline: auto; padding-inline: var(--gutter); }

.section { padding-block: var(--sp-9); }
.section--alt { background: var(--paper-alt); }
.section--deep { background: var(--paper-deep); color: var(--on-deep); }

/* The header is sticky and 64px tall, so an in-page jump would land the section
   opener underneath it. Every nav link needs this or the first thing a visitor
   sees after clicking is a heading cut in half. */
:target, section[id] { scroll-margin-top: calc(64px + var(--sp-4)); }
@media (max-width: 900px) { section[id] { scroll-margin-top: 132px; } }

[data-density="compact"] .section { padding-block: var(--sp-8); }

/* ---- Mono eyebrow / numbered section opener ---- */
.eyebrow {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--ink-3);
}
.section-opener {
  display: flex;
  align-items: baseline;
  gap: var(--sp-4);
  margin-bottom: var(--sp-6);
}
.section-opener .num {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-wide);
  color: var(--accent);
}
.section-opener .rule { flex: 1; height: 1px; background: var(--line); align-self: center; }
[data-opener="plain"] .section-opener .num { display: none; }
[data-opener="plain"] .section-opener { gap: var(--sp-3); }
.section--deep .section-opener .rule { background: var(--line-deep); }
.section--deep .eyebrow { color: var(--on-deep-2); }

.section-title { font-size: var(--fs-3xl); letter-spacing: var(--ls-display); }
/* Accent emphasis is BOLD, not italic. Newsreader's italic at display sizes
   in mid-blue was the hardest thing on the page to read -- the slant plus a
   non-black colour costs legibility exactly where the line matters most.
   Weight carries the same emphasis and stays crisp. Nothing on the page uses
   italic now, so the font request drops the italic axis entirely. */
.section-title em { font-style: normal; font-weight: var(--fw-semibold); color: var(--accent); }
.section--deep .section-title { color: var(--on-deep); }

.lede {
  font-size: var(--fs-lg);
  line-height: var(--lh-relaxed);
  color: var(--ink-2);
  max-width: var(--maxw-prose);
}

/* ---- Buttons ---- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  font-family: var(--font-sans);
  font-size: var(--fs-base);
  font-weight: var(--fw-semibold);
  line-height: 1;
  padding: 0.72em 1.15em;
  border-radius: var(--r-md);
  border: 1px solid transparent;
  cursor: pointer;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease),
              color var(--dur) var(--ease), transform var(--dur-fast) var(--ease);
  text-decoration: none;
}
.btn:active { transform: translateY(1px); }
.btn .i { width: 16px; height: 16px; flex: none; }

.btn--primary { background: var(--accent); color: #fff; }
.btn--primary:hover { background: var(--accent-deep); color: #fff; }

.btn--ghost { background: transparent; color: var(--ink); border-color: var(--line-2); }
.btn--ghost:hover { border-color: var(--ink); color: var(--ink); }

.section--deep .btn--ghost { color: var(--on-deep); border-color: var(--line-deep); }
.section--deep .btn--ghost:hover { border-color: var(--on-deep); color: var(--on-deep); }

/* ---- Standard chips (mono) ----
   The three states carry meaning and the meaning is the point: --earned is a
   standard he works to and can be questioned on, plain is a tool or practice,
   --applying is something being adopted or tracked. Do not use --earned as
   decoration. */
.std {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  /* Was a hardcoded 0.01em -- the one value on the page that sat off the
     letter-spacing scale, for 0.12px nobody can see. */
  letter-spacing: var(--ls-normal);
  padding: 0.34em 0.6em;
  border-radius: var(--r-xs);
  background: var(--surface);
  color: var(--ink-2);
  border: 1px solid var(--line);
  white-space: nowrap;
}
.std--earned { background: var(--accent-tint); color: var(--accent-deep); border-color: var(--accent-line); }
.std--applying { background: var(--warn-tint); color: var(--warn); border-color: #E4D2A8; }
.std--ok { background: var(--ok-tint); color: var(--ok); border-color: #BFD9CB; }
.std-row { display: flex; flex-wrap: wrap; gap: var(--sp-2); }

/* Legend so the colour coding is explained rather than guessed at. */
.chip-legend {
  display: flex; flex-wrap: wrap; gap: var(--sp-4);
  margin-top: var(--sp-5); padding-top: var(--sp-4);
  border-top: 1px solid var(--line);
  font-size: var(--fs-xs); color: var(--ink-3);
}
.chip-legend span { display: inline-flex; align-items: center; gap: var(--sp-2); }
.chip-legend i {
  width: 10px; height: 10px; border-radius: var(--r-xs); display: inline-block;
  border: 1px solid var(--line);
}
.chip-legend .k-earned { background: var(--accent-tint); border-color: var(--accent-line); }
.chip-legend .k-tool { background: var(--surface); }
.chip-legend .k-applying { background: var(--warn-tint); border-color: #E4D2A8; }

/* ---- Header ---- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: color-mix(in srgb, var(--paper) 78%, transparent);
  backdrop-filter: saturate(140%) blur(10px);
  -webkit-backdrop-filter: saturate(140%) blur(10px);
  border-bottom: 1px solid var(--line);
  transition: opacity var(--dur-slow) var(--ease),
              transform var(--dur-slow) var(--ease);
}

/* The header restates the hero: same name, same three disciplines. While the
   hero is on screen it is a duplicate competing with the thing it duplicates,
   so it stands down and returns once the hero is behind you.

   Visible is the DEFAULT and JS adds `is-tucked` -- the reverse would hide the
   only navigation on the page for anyone whose JS did not run.

   It stays in the DOM and keyboard-reachable: :focus-within brings it straight
   back, so tabbing from the address bar lands on a visible control rather than
   an invisible one. */
.site-header.is-tucked {
  opacity: 0;
  transform: translateY(-6px);
  pointer-events: none;
}
.site-header.is-tucked:focus-within {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}
@media (prefers-reduced-motion: reduce) {
  .site-header { transition: none; }
}
.site-header .bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  min-height: 64px;
}
.brand { display: flex; align-items: center; gap: var(--sp-3); color: var(--ink); }
.brand .mark { width: 26px; height: 26px; color: var(--accent); flex: none; }
.brand .name { font-family: var(--font-display); font-size: var(--fs-lg); letter-spacing: var(--ls-tight); white-space: nowrap; }
.brand .name b { font-weight: var(--fw-medium); }
.brand .dot { color: var(--ink-4); }
.brand .role { font-family: var(--font-mono); font-size: var(--fs-xs); letter-spacing: var(--ls-wide); text-transform: uppercase; color: var(--ink-3); white-space: nowrap; }
/* ---- Nav: hamburger everywhere, Contact always visible ----
   The header keeps only the mark, the name, the menu button and Contact. That
   is a deliberate trade: a hamburger costs some discoverability on desktop,
   where five links would have fitted, in exchange for a header that stays clean
   at every width and never needs re-measuring when a link is added. (Reverting
   to inline links above ~1000px is a one-rule change: unhide .navmenu links in
   a min-width query and hide .navtoggle.)

   The panel is CSS-only in its resting state -- no layout depends on the script
   having run -- and `hidden` is toggled so it is out of the accessibility tree
   and out of the tab order when closed. */
.navbar { display: flex; align-items: center; gap: var(--sp-3); }

.navtoggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px;
  background: none; border: 1px solid transparent; border-radius: var(--r-md);
  color: var(--ink); cursor: pointer; padding: 0;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.navtoggle:hover { background: var(--surface); border-color: var(--line-2); }
.navtoggle .i { width: 20px; height: 20px; }
.navtoggle .close { display: none; }
.navtoggle[aria-expanded="true"] .open { display: none; }
.navtoggle[aria-expanded="true"] .close { display: block; }
.navtoggle[aria-expanded="true"] { background: var(--surface); border-color: var(--line-2); }

.navmenu-anchor { position: relative; display: flex; }

.navmenu {
  position: absolute;
  top: calc(100% + 8px);
  /* Centred on the toggle. Centring uses `translate` rather than `transform`
     because the navpop keyframe animates `transform` -- put both on the same
     property and the animation's `from` wipes out the centring for its duration,
     so the panel jumps sideways as it opens. */
  left: 50%;
  translate: -50% 0;
  z-index: 60;
  display: flex;
  flex-direction: column;
  min-width: 232px;
  padding: var(--sp-2);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
  transform-origin: top center;
}
.navmenu[hidden] { display: none; }

/* The open animation is additive only -- if the script never runs, the panel is
   simply hidden, never half-faded or unclickable. */
.navmenu.is-open { animation: navpop var(--dur) var(--ease); }
@keyframes navpop { from { opacity: 0; transform: translateY(-4px) scale(0.99); } }
@media (prefers-reduced-motion: reduce) { .navmenu.is-open { animation: none; } }

.navmenu .navlink {
  display: flex; align-items: center; min-height: 44px;
  padding-inline: var(--sp-3);
  border-radius: var(--r-sm);
  font-size: var(--fs-base); font-weight: var(--fw-medium);
  color: var(--ink-2); letter-spacing: var(--ls-tight); white-space: nowrap;
}
.navmenu .navlink:hover { background: var(--paper-alt); color: var(--ink); }

/* The résumé download is a different kind of action from an in-page jump. */
.navmenu .navlink[download] {
  margin-top: var(--sp-2); padding-top: var(--sp-3);
  border-top: 1px solid var(--line);
  border-radius: 0 0 var(--r-sm) var(--r-sm);
  color: var(--accent);
}

@media (max-width: 1000px) {
  .brand .role, .brand .dot { display: none; }
}
@media (max-width: 400px) {
  /* Centred on a 40px button near the right edge, a 232px panel would run
     past the gutter. Anchor it to the button's right edge instead and let
     it size to its content -- still under the control, never off-screen.
     (This replaced a gutter-to-gutter rule that positioned against the page;
     with the panel now inside .navmenu-anchor those offsets would resolve
     against a 40px box instead.) */
  .navmenu { left: auto; right: 0; translate: none; transform-origin: top right;
             min-width: 0; width: max-content; max-width: calc(100vw - 2 * var(--gutter)); }

  /* At 320px the name, the menu button and Contact together overflowed the bar
     by 14px. Everything shrinks a little rather than any one element being
     dropped -- the name is the brand, and Contact is the whole point of the
     header, so neither should be the thing that goes. */
  .site-header .bar { gap: var(--sp-2); }
  .brand { gap: var(--sp-2); }
  .brand .name { font-size: var(--fs-md); }
  .brand .mark { width: 22px; height: 22px; }
  .navbar { gap: var(--sp-2); }
  .navtoggle { width: 40px; height: 40px; }
  /* min-height keeps it a real touch target after the padding is trimmed. */
  .navbar .btn { font-size: var(--fs-sm); padding: 0.7em 0.85em; min-height: 40px; }
}

/* Hero identity row: portrait beside the name, so a visitor sees a face in the
   first screenful. One headshot per page -- the About copy carries the story,
   it does not need a second photo. */
.hero-id { display: flex; align-items: center; gap: var(--sp-5); margin-bottom: var(--sp-5); }
/* The source is a transparent cutout, so every framing property on .portrait has
   to come back off: a radius clips nothing, and the border and shadow draw a
   rounded rectangle around empty space -- which is exactly what they did until
   this rule existed. The silhouette is the shape.
   Larger than the old 96px circle because a cutout carries transparent margin
   and its bottom fades out, so the same box reads smaller. */
.portrait.portrait--hero {
  width: 116px; max-width: 116px; height: 116px; flex: none;
  border-radius: 0;
  border: 0;
  box-shadow: none;
  object-fit: contain;
}
.hero .kicker { margin-bottom: var(--sp-2); }
.hero h1 { margin-bottom: 0; }
.hero-sub {
  font-family: var(--font-display);
  font-size: var(--fs-2xl);
  line-height: var(--lh-snug);
  color: var(--ink-3);
  margin-bottom: var(--sp-5);
  max-width: 30ch;
}
.hero-sub em { font-style: normal; font-weight: var(--fw-semibold); color: var(--accent); }
@media (max-width: 560px) {
  .hero-id { gap: var(--sp-4); }
  .portrait.portrait--hero { width: 68px; max-width: 68px; height: 68px; }
}
@media (max-width: 430px) {
  /* Below this the photo and a 40px name cannot share a row -- 272px of content
     at 320px, and the name alone wants ~230. Stack rather than shrink the name
     into something apologetic. */
  .hero-id { flex-direction: column; align-items: flex-start; gap: var(--sp-4); }
  .portrait.portrait--hero { width: 76px; max-width: 76px; height: 76px; }
}

/* ---- Hero ---- */
.hero { padding-top: var(--sp-9); padding-bottom: var(--sp-9); }
.hero-grid {
  display: grid;
  grid-template-columns: 1.45fr 1fr;
  gap: var(--sp-8);
  align-items: start;
}
[data-hero="stacked"] .hero-grid { grid-template-columns: 1fr; max-width: var(--maxw-prose); }
[data-hero="stacked"] .ledger { margin-top: var(--sp-2); }

.hero .kicker { margin-bottom: var(--sp-5); }
.hero h1 {
  font-size: var(--fs-5xl);
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-display);
  margin-bottom: var(--sp-5);
}
.hero h1 .sub { display: block; font-size: var(--fs-2xl); color: var(--ink-3); margin-top: var(--sp-4); line-height: var(--lh-snug); }
.hero h1 em { font-style: normal; font-weight: var(--fw-semibold); color: var(--accent); }
.hero .position {
  font-size: var(--fs-lg);
  line-height: var(--lh-relaxed);
  color: var(--ink-2);
  max-width: 42ch;
  margin-bottom: var(--sp-6);
}
.hero .cta-row { display: flex; flex-wrap: wrap; gap: var(--sp-3); }

@media (max-width: 880px) {
  .hero-grid { grid-template-columns: 1fr; gap: var(--sp-7); }
  .hero h1 { font-size: var(--fs-4xl); }
}
@media (max-width: 480px) {
  .hero h1 { font-size: var(--fs-3xl); }
  .hero h1 .sub { font-size: var(--fs-xl); }
}

/* ---- Ledger (data column) ---- */
.ledger {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}
.ledger .head {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--sp-3) var(--sp-5);
  border-bottom: 1px solid var(--line);
  background: var(--surface-sub);
}
/* ls-wide, not ls-label: this took the section eyebrow's tracking with the field
   label's weight, so it matched neither tier. It is the ledger's own header, so
   it follows the ledger's own labels (.row .k) -- one card, one treatment. */
.ledger .head .label { font-family: var(--font-mono); font-size: var(--fs-xs); letter-spacing: var(--ls-wide); text-transform: uppercase; color: var(--ink-3); white-space: nowrap; }
.ledger .head .mk { width: 16px; height: 16px; color: var(--accent); }
.ledger .row {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--sp-4);
  padding: var(--sp-4) var(--sp-5);
  border-bottom: 1px solid var(--line);
  align-items: baseline;
}
.ledger .row:last-child { border-bottom: 0; }
.ledger .row .k { font-family: var(--font-mono); font-size: var(--fs-xs); letter-spacing: var(--ls-wide); text-transform: uppercase; color: var(--ink-3); white-space: nowrap; }
.ledger .row .v { font-size: var(--fs-base); color: var(--ink); text-align: right; font-weight: var(--fw-medium); }
.ledger .row .v small { display: block; font-weight: var(--fw-regular); color: var(--ink-3); font-size: var(--fs-xs); letter-spacing: 0; margin-top: 2px; }

/* ---- About ---- */
.about-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-8); align-items: start; }
@media (max-width: 880px) { .about-grid { grid-template-columns: 1fr; gap: var(--sp-6); } }
.about-grid p + p { margin-top: var(--sp-4); }
.about-grid .body { font-size: var(--fs-md); line-height: var(--lh-relaxed); color: var(--ink-2); }
.about-grid .body strong { color: var(--ink); font-weight: var(--fw-semibold); }

/* Portrait sits above the pull quote in the right column. The headshot's grey
   backdrop is within a shade of --paper-alt, so it reads as part of the page
   rather than as a pasted-in photo -- no vignette or heavy border needed.
   width/height are set on the element so the image reserves its space before it
   loads and nothing below it jumps. */
.about-side { display: flex; flex-direction: column; gap: var(--sp-5); align-items: start; }
.portrait {
  /* height:auto is load-bearing. The width/height ATTRIBUTES on the <img> exist
     so the browser reserves space before the file loads, but the height
     attribute also sets a used height of 800px, which beats aspect-ratio unless
     height is explicitly auto. Without this the box renders 248x800 and
     object-fit crops the sides off the face. */
  width: 100%; max-width: 248px; height: auto; aspect-ratio: 1 / 1;
  object-fit: cover; display: block;
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-sm);
}
@media (max-width: 880px) {
  /* Stacked, the photo belongs at the top of the section, not marooned between
     the bio and the quote. */
  .about-grid { display: flex; flex-direction: column; }
  .about-side { order: -1; }
  .portrait { max-width: 168px; }
}
.pull {
  font-family: var(--font-display);
  font-size: var(--fs-xl);
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-tight);
  color: var(--ink);
  padding-left: var(--sp-5);
  border-left: 2px solid var(--accent);
  margin: 0;
}
.pull em { font-style: normal; font-weight: var(--fw-semibold); color: var(--accent); }

/* ---- Expertise grid (ruled table) ---- */
.exp-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  overflow: hidden;
}
@media (max-width: 880px) { .exp-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .exp-grid { grid-template-columns: 1fr; } }

/* flex column so `margin-top:auto` on the chip row actually works -- in the
   design source .exp-cell was a block, so the rule was inert and the chip rows
   sat directly under text of varying length, leaving the ruled grid ragged. */
.exp-cell {
  background: var(--surface);
  padding: var(--sp-6) var(--sp-5);
  display: flex;
  flex-direction: column;
  transition: background var(--dur) var(--ease);
}
.exp-cell:hover { background: var(--surface-sub); }
.exp-cell .ic { width: 22px; height: 22px; color: var(--accent); margin-bottom: var(--sp-4); display: block; flex: none; }
.exp-cell h3 { font-family: var(--font-sans); font-size: var(--fs-md); font-weight: var(--fw-semibold); letter-spacing: var(--ls-tight); color: var(--ink); margin-bottom: var(--sp-3); }
.exp-cell p { font-size: var(--fs-base); line-height: var(--lh-body); color: var(--ink-2); margin-bottom: var(--sp-4); }
.exp-cell .std-row { margin-top: auto; }

/* ---- Technical edge: stepped arc ---- */
.arc { display: grid; grid-template-columns: 1fr; gap: 0; margin-top: var(--sp-2); }
.arc-step {
  display: grid;
  grid-template-columns: 56px 1fr;
  gap: var(--sp-5);
  padding-block: var(--sp-6);
  border-top: 1px solid var(--line);
}
.arc-step:last-child { border-bottom: 1px solid var(--line); }
.arc-rail { display: flex; flex-direction: column; align-items: center; gap: var(--sp-3); }
.arc-node {
  width: 44px; height: 44px; flex: none;
  border-radius: var(--r-md);
  display: grid; place-items: center;
  background: var(--accent-tint);
  border: 1px solid var(--accent-line);
  color: var(--accent);
  /* Matched to .section-opener .num. Both are numbered markers and they appear
     within one screen of each other in Differentiators, where this was 13px/600
     with no tracking against the opener's 12px/500/wide -- the same device
     rendered two ways, side by side. */
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-wide);
}
.arc-step:last-child .arc-node { background: var(--accent); color: #fff; border-color: var(--accent); }
.arc-line { flex: 1; width: 1px; background: var(--line); min-height: 8px; }
.arc-body h3 { font-family: var(--font-display); font-size: var(--fs-xl); letter-spacing: var(--ls-tight); margin-bottom: var(--sp-2); }
.arc-body .when { font-family: var(--font-mono); font-size: var(--fs-xs); letter-spacing: var(--ls-wide); text-transform: uppercase; color: var(--ink-3); margin-bottom: var(--sp-3); display: block; }
.arc-body p { font-size: var(--fs-md); line-height: var(--lh-relaxed); color: var(--ink-2); max-width: 62ch; }
.arc-body .artifacts { margin-top: var(--sp-4); }
@media (max-width: 560px) { .arc-step { grid-template-columns: 40px 1fr; gap: var(--sp-4); } .arc-node { width: 38px; height: 38px; } }

/* governance callout */
.callout {
  margin-top: var(--sp-6);
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--sp-4);
  padding: var(--sp-5) var(--sp-6);
  background: var(--surface);
  border: 1px solid var(--line);
  border-left: 2px solid var(--accent);
  border-radius: var(--r-md);
}
.callout .ic { width: 22px; height: 22px; color: var(--accent); margin-top: 2px; flex: none; }
.callout p { font-size: var(--fs-base); line-height: var(--lh-relaxed); color: var(--ink-2); }
.callout strong { color: var(--ink); font-weight: var(--fw-semibold); }

/* ---- Experience ---- */
.xp-list { display: flex; flex-direction: column; gap: var(--sp-4); }
.xp {
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}
.xp-head {
  display: grid;
  grid-template-columns: 1fr auto auto;
  gap: var(--sp-4);
  align-items: center;
  width: 100%;
  text-align: left;
  padding: var(--sp-5) var(--sp-6);
  background: none;
  border: 0;
  cursor: pointer;
  font-family: inherit;
  color: inherit;
}
.xp-head:hover { background: var(--surface-sub); }
.xp-head .org { font-family: var(--font-display); font-size: var(--fs-xl); letter-spacing: var(--ls-tight); color: var(--ink); }
.xp-head .org small { display: block; font-family: var(--font-sans); font-size: var(--fs-base); font-weight: var(--fw-medium); color: var(--ink-2); letter-spacing: 0; margin-top: 2px; }
.xp-head .yr { font-family: var(--font-mono); font-size: var(--fs-xs); letter-spacing: var(--ls-wide); color: var(--ink-3); }
.xp-head .chev { width: 18px; height: 18px; color: var(--ink-3); transition: transform var(--dur) var(--ease); flex: none; }
.xp.is-open .xp-head .chev { transform: rotate(180deg); }
.xp-body {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--dur-slow) var(--ease);
}
.xp.is-open .xp-body { grid-template-rows: 1fr; }
.xp-body > div { overflow: hidden; }
.xp-body .inner { padding: 0 var(--sp-6) var(--sp-6); border-top: 1px solid var(--line); }
.xp-body .inner ul { margin: var(--sp-4) 0 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: var(--sp-3); }
.xp-body .inner li { position: relative; padding-left: var(--sp-5); font-size: var(--fs-base); line-height: var(--lh-body); color: var(--ink-2); }
.xp-body .inner li::before { content: ""; position: absolute; left: 0; top: 0.62em; width: 6px; height: 6px; border-radius: var(--r-xs); background: var(--accent); }
.xp-body .inner li strong { color: var(--ink); font-weight: var(--fw-semibold); }
/* Overlapping dates are the first thing a reader notices on the consulting
   entry, so the answer sits above the bullets rather than waiting inside one.
   Tinted and ruled so it reads as context for the block, not as a first item. */
.xp-body .inner .xp-note {
  margin: var(--sp-4) 0 0;
  padding: var(--sp-3) var(--sp-4);
  border-left: 2px solid var(--accent);
  background: var(--accent-tint);
  border-radius: 0 var(--r-xs) var(--r-xs) 0;
  /* Base, not sm. It introduces the bullets below it, and set smaller than what
     it introduces it read as a footnote that had floated to the top. The tint
     and the rule already mark it as context; size did not need to as well.
     (fs-sm is used almost nowhere else on the page, which is what made it
     conspicuous here.) */
  font-size: var(--fs-base);
  line-height: var(--lh-body);
  color: var(--ink-2);
}
.xp-body .inner .xp-note strong { color: var(--ink); font-weight: var(--fw-semibold); }
.xp-body .inner .std-row { margin-top: var(--sp-5); }
@media (max-width: 560px) { .xp-head { grid-template-columns: 1fr auto; } .xp-head .yr { grid-column: 1 / -1; } }

/* ---- Credentials ---- */
.cred-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-4); }
@media (max-width: 720px) { .cred-grid { grid-template-columns: 1fr; } }
.cred {
  display: flex; flex-direction: column; gap: var(--sp-3);
  padding: var(--sp-6) var(--sp-5);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
  transition: box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.cred:hover { box-shadow: var(--shadow-md); transform: translateY(-2px); }
@media (prefers-reduced-motion: reduce) { .cred:hover { transform: none; } }
.cred .ic { width: 24px; height: 24px; color: var(--accent); flex: none; }
.cred .t { font-family: var(--font-display); font-size: var(--fs-lg); letter-spacing: var(--ls-tight); color: var(--ink); }
.cred .d { font-size: var(--fs-base); color: var(--ink-2); line-height: var(--lh-body); }
.cred .meta { font-family: var(--font-mono); font-size: var(--fs-xs); letter-spacing: var(--ls-wide); text-transform: uppercase; color: var(--ink-3); margin-top: auto; }

/* ---- Contact band (deep) ---- */
.contact { padding-block: var(--sp-9); }
.contact .grid { display: grid; grid-template-columns: 1.3fr 1fr; gap: var(--sp-8); align-items: end; }
@media (max-width: 760px) { .contact .grid { grid-template-columns: 1fr; gap: var(--sp-6); align-items: start; } }
.contact h2 { font-size: var(--fs-3xl); color: var(--on-deep); letter-spacing: var(--ls-display); }
.contact h2 em { font-style: normal; font-weight: var(--fw-semibold); color: #9CC0E2; }
.contact p { color: var(--on-deep-2); font-size: var(--fs-md); line-height: var(--lh-relaxed); margin-top: var(--sp-4); max-width: 46ch; }
/* align-items:start so the email cluster hugs its content instead of stretching
   to the full column and leaving the label marooned at the left edge. */
.contact .actions { display: flex; flex-direction: column; gap: var(--sp-3); align-items: start; }
.contact .email-cluster {
  display: inline-flex; align-items: center; gap: var(--sp-3);
  font-family: var(--font-mono); font-size: var(--fs-base); letter-spacing: 0.01em;
  padding: 0.8em 1.05em; border-radius: var(--r-md);
  background: rgba(255,255,255,0.05); border: 1px solid var(--line-deep); color: var(--on-deep);
  cursor: pointer; user-select: none; outline: none;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.contact .email-cluster:hover,
.contact .email-cluster:focus-visible,
.contact .email-cluster.is-open { background: rgba(255,255,255,0.09); border-color: #3A4651; }
.contact .email-cluster .mailicon { width: 16px; height: 16px; color: #7FA8D0; flex: none; }
.contact .email-cluster .email-swap { position: relative; flex: 1; display: flex; align-items: center; min-height: 1.45em; }
.contact .email-cluster .email-label {
  position: absolute; left: 0; top: 50%; transform: translateY(-50%); white-space: nowrap;
  transition: opacity 240ms var(--ease), transform 420ms var(--ease);
}
.contact .email-cluster .email-reveal {
  display: inline-flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap;
  opacity: 0; transform: translateX(-14px); pointer-events: none;
  transition: opacity 320ms var(--ease) 40ms, transform 460ms var(--ease);
}
.contact .email-cluster.is-open .email-label { opacity: 0; transform: translateY(-50%) translateX(10px); pointer-events: none; }
.contact .email-cluster.is-open .email-reveal { opacity: 1; transform: none; pointer-events: auto; }
@media (prefers-reduced-motion: reduce) {
  .contact .email-cluster .email-label,
  .contact .email-cluster .email-reveal { transition: opacity 120ms linear; transform: none; }
  .contact .email-cluster.is-open .email-label { transform: none; }
}
.contact .email-value { white-space: nowrap; color: var(--on-deep); }
.contact .email-mini {
  display: inline-flex; align-items: center; gap: 0.4em;
  font-family: var(--font-sans); font-size: var(--fs-xs); font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-tight);
  padding: 0.55em 0.7em; min-height: 36px; border-radius: var(--r-sm);
  background: rgba(255,255,255,0.06); border: 1px solid var(--line-deep); color: var(--on-deep);
  cursor: pointer; text-decoration: none; white-space: nowrap;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
.contact .email-mini:hover { background: rgba(127,168,208,0.18); border-color: #46596B; color: #fff; }
.contact .email-mini .i { width: 13px; height: 13px; }
.contact .links { display: flex; gap: var(--sp-5); margin-top: var(--sp-2); flex-wrap: wrap; }
.contact .links a { color: var(--on-deep-2); font-size: var(--fs-base); display: inline-flex; align-items: center; gap: 0.45em; }
.contact .links a:hover { color: var(--on-deep); }
.contact .links a .i { width: 15px; height: 15px; }

/* ---- Footer ---- */
.site-footer { background: var(--paper-deep); color: var(--on-deep-2); border-top: 1px solid var(--line-deep); padding-block: var(--sp-6); }
.site-footer .bar { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4); flex-wrap: wrap; }
.site-footer .brand .name { color: var(--on-deep); font-size: var(--fs-md); font-family: var(--font-display); }
.site-footer .brand .mark { color: #7FA8D0; width: 22px; height: 22px; }
.site-footer .fine { font-family: var(--font-mono); font-size: var(--fs-xs); letter-spacing: var(--ls-wide); color: var(--on-deep-2); }

/* ---- Reveal on scroll ---- */
.reveal { opacity: 0; transform: translateY(14px); transition: opacity var(--dur-slow) var(--ease), transform var(--dur-slow) var(--ease); }
.reveal.in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { .reveal { opacity: 1; transform: none; transition: none; } }

/* Content must not depend on JavaScript to be visible. If the observer never
   runs -- script blocked, error, old browser -- .reveal would hide the entire
   page permanently. */
.no-js .reveal { opacity: 1; transform: none; }

/* ---- Print: a recruiter saving the page should get something readable ---- */
@media print {
  .site-header, .skip, .cta-row, .chip-legend { display: none; }
  body { background: #fff; font-size: 10.5pt; }
  .section { padding-block: var(--sp-5); break-inside: avoid; }
  .section--alt, .section--deep { background: #fff; color: var(--ink); }
  .contact h2, .section--deep .section-title { color: var(--ink); }
  .contact p, .site-footer .fine { color: var(--ink-2); }
  .xp-body { grid-template-rows: 1fr !important; }
  .reveal { opacity: 1 !important; transform: none !important; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 9pt; color: var(--ink-3); }
}
