/* ═══════════════════════════════════════════════════════════════════════
   Brock Gillespie executive CV
   Structure follows the Wix "UX/UI Designer Resume" template:
   full-bleed photo panels tinted flat into one palette, centred numbered
   section headers, a card floating over the hero seam, and an alternating
   timeline on a centre rule.
   Palette is that template's slate and navy with oxblood in place of its
   green. Plain CSS, no build step.
   ═══════════════════════════════════════════════════════════════════════ */

:root {
  /* Structure. Lifted a few steps lighter on 2026-08-01 at Vicky's request.
     --bg now sits essentially on the Wix template's own page slate. */
  /* Page stone, 2026-08-04. The blue slate went with the navy: brass on a
     blue grey reads green, and every veil is a hard-coded gradient stop
     that has to move with the page or the panel edges show a seam. */
  --bg:      #6A6660;   /* page stone */
  --bg2:     #5E5A55;
  /* Dark stone, 2026-08-04, replacing the navy family. Warm neutral rather
     than blue so it sits with brass instead of fighting it. Same three
     steps, same roles: panels, rail and footer, deepest. */
  --navy:    #3B3A38;   /* floating panels */
  --deep:    #2C2B29;   /* metric rail, footer */
  --ink:     #1B1A18;

  /* type */
  --white:   #FFFFFF;
  --text:    #EAE7E1;
  --muted:   #A8A49C;
  --num:     #C9C4BB;   /* the template's section-number grey */

  /* Gold, as a scale, replacing the oxblood one on 2026-08-04. Same rule
     it inherited: the deep end is dark enough to carry white type (4.98:1) so it is only
     ever a fill, and anything that has to stay legible on slate uses the
     light end, which reaches 4.27:1 against the 3.66:1 the pink managed. */
  /* Pushed properly gold on 2026-08-04, saturation .25 to .60 on the light
     end. It could go this far because every element carrying --gold-lt sits
     on --deep or darker, where even this reaches 8.65:1. On the mid stone
     it would only make 3.49, so nothing may use it there. */
  --gold:      #8F6B22;   /* fills, carries white type at 4.89:1 */
  --gold-mid:  #B8912F;   /* hover */
  --gold-acc:  #D4AF37;   /* brass: rules, dots, the timeline line */
  --gold-lt:   #EDC65F;   /* gold: accent text on dark */

  --rule:    rgba(255,255,255,.15);
  --rule-sd: rgba(255,255,255,.09);

  --wrap:    1180px;
  --ease:    cubic-bezier(.16,1,.3,1);

  --f-disp:  'Poppins', 'Futura', system-ui, sans-serif;
  --f-body:  'Nunito Sans', -apple-system, BlinkMacSystemFont, sans-serif;
}

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

html { scroll-behavior: smooth; }
/* The header is fixed at 68px, so an anchor jump landed with the section
   heading tucked underneath it. Affects where a jump stops, never where
   anything sits at rest. */
[id] { scroll-margin-top: 68px; }
html, body { overflow-x: hidden; }               /* guard: no sideways scrollbar */

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--f-body);
  font-size: 17px;
  line-height: 1.66;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 { margin: 0; font-weight: 600; line-height: 1.1; }
p { margin: 0 0 1.15em; }
p:last-child { margin-bottom: 0; }
img { max-width: 100%; display: block; }
a { color: inherit; }
ul, ol, dl, dd { margin: 0; padding: 0; list-style: none; }

::selection { background: var(--gold); color: #fff; }
:focus-visible { outline: 2px solid var(--gold-lt); outline-offset: 3px; }

.wrap { width: 100%; max-width: var(--wrap); margin-inline: auto; padding-inline: 24px; }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip:focus {
  position: fixed; top: 12px; left: 12px; z-index: 200; width: auto; height: auto;
  clip: auto; margin: 0; padding: 12px 18px; background: var(--gold); color: #fff;
  text-decoration: none;
}

/* ── the template's display voice ───────────────────────────────────────
   Lulo Clean One Bold is an Adobe font we cannot ship, so this is Poppins
   set the way Lulo sits: caps only, wide even tracking, weight over size. */
.disp {
  font-family: var(--f-disp);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .14em;
}

/* ── nav ────────────────────────────────────────────────────────────── */
.nav {
  position: fixed; inset: 0 0 auto 0; z-index: 100;
  background: rgba(38,37,35,.94);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid rgba(255,255,255,.07);
}
.nav .wrap { display: flex; align-items: center; justify-content: space-between; gap: 32px; height: 68px; }

.brand { display: flex; align-items: center; gap: 12px; text-decoration: none; }
.mono {
  width: 34px; height: 34px; flex: none;
  display: grid; place-items: center;
  border: 1.5px solid var(--gold-acc); border-radius: 50%;
  font-family: var(--f-disp); font-weight: 700; font-size: .74rem;
  letter-spacing: .04em; color: var(--gold-lt);
}
.brand-nm { font-family: var(--f-disp); font-weight: 600; font-size: .84rem; letter-spacing: .16em; text-transform: uppercase; color: #fff; }

.nav nav { display: flex; align-items: center; gap: 30px; }
.nav nav a {
  font-size: .75rem; letter-spacing: .17em; text-transform: uppercase;
  color: rgba(255,255,255,.74); text-decoration: none; transition: color .2s;
}
.nav nav a:hover, .nav nav a.on { color: var(--gold-lt); }
@media (max-width: 900px) { .nav nav a.hide-sm { display: none; } }

/* ── photographic panels ────────────────────────────────────────────────
   Every photo is pushed flat into the palette so it recedes behind the
   type. That tinting is also what lets a low-resolution source fill a
   full-height slot without reading as low-resolution. */
.panel { position: relative; isolation: isolate; overflow: hidden; }
.panel-img {
  position: absolute; inset: -8% 0; z-index: -2;
  background-size: cover; background-position: center;
  /* The plates are warm-hour photographs now, so the tint only has to take
     the edge off rather than manufacture colour. An earlier pass tried to
     warm cold blue-grey sources with sepia and it never really took: the
     fix was the photographs, not the filter. */
  /* Lifted from brightness .84 on 2026-08-04. The plates were built dark AND
     filtered dark, so they read as murky. Walked up against the probe: 1.00
     is clean, 1.04 fails at 768 (4.49:1). .98 keeps a margin. */
  filter: grayscale(.08) saturate(1.14) contrast(1.03) brightness(.98);
  will-change: transform;
}
/* One panel is allowed its own colour: the arena in The Global Game. It is
   the only warm frame on the page and the section it carries is the human
   one, so it keeps its amber court and teal light instead of being tinted
   flat like the rest. */
.panel--vivid .panel-img {
  filter: grayscale(0) saturate(1.34) contrast(1.08) brightness(1.02);
}
.panel-veil { position: absolute; inset: 0; z-index: -1; }
.panel-tint { position: absolute; inset: 0; z-index: -1; mix-blend-mode: color; }

/* ── section headers, centred and numbered ──────────────────────────── */
.sec-head { text-align: center; margin-bottom: 60px; }
.sec-num, .sec-word {
  font-family: var(--f-disp); font-weight: 700; text-transform: uppercase;
  font-size: clamp(1.75rem, 4.2vw, 2.65rem); letter-spacing: .17em;
  display: inline-block; vertical-align: middle;
}
.sec-num  { color: var(--num); opacity: .55; margin-right: .5em; }
.sec-word { color: #fff; }
.sec-sub {
  display: block; margin-top: 18px;
  font-size: clamp(.76rem, 1.3vw, .88rem); letter-spacing: .3em;
  text-transform: uppercase; color: rgba(255,255,255,.92); font-weight: 400;
}

/* ── buttons ────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--f-disp); font-size: .74rem; font-weight: 500;
  letter-spacing: .19em; text-transform: uppercase; text-decoration: none;
  padding: 15px 30px; border: 1px solid transparent;
  transition: background-color .22s, border-color .22s, color .22s;
  cursor: pointer;
}
.btn-line  { color: #fff; border-color: var(--gold-acc); background: none; }
.btn-line:hover  { background: rgba(212,175,55,.16); }
.btn-solid { color: #fff; background: var(--gold); border-color: var(--gold); }
.btn-solid:hover { background: var(--gold-mid); border-color: var(--gold-mid); }

/* ══ HERO ═══════════════════════════════════════════════════════════════
   Name set left of centre, his face cropped huge and bleeding off the
   right edge, colour-matched into the slate so it merges with the
   background instead of sitting in a frame. */
.hero {
  position: relative; isolation: isolate; overflow: hidden;
  min-height: 100vh; display: flex; flex-direction: column; justify-content: center;
  padding: 150px 0 190px;
  background: var(--deep);
}
.hero-glow {
  position: absolute; inset: 0; z-index: -1;
  background: radial-gradient(115% 85% at 82% 22%, rgba(143,107,34,.32) 0%, transparent 62%);
}

/* The layer spans the whole hero and the photograph is right-anchored
   inside it. If the layer were only as wide as the photo, the wash and
   fade would paint a hard-edged rectangle down the middle of the hero. */
.face {
  position: absolute; inset: 0; z-index: -1;
  pointer-events: none; user-select: none;
}
/* two full-height columns, right-anchored: the work, then the man */
.face-art {
  position: absolute; inset: 0 0 0 auto;
  /* Wider, so the plate reaches most of the way across instead of leaving
     a third of the hero as bare background that the fade then had to
     disguise. The portrait keeps its old pixel width: 45% of 1240 is the
     same 558px that 62% of 900 was. */
  width: min(88vw, 1240px);
  display: grid; grid-template-columns: 55% 45%;
  -webkit-mask-image: linear-gradient(90deg, transparent 0%, #000 26%, #000 100%),
                      linear-gradient(180deg, #000 66%, transparent 99%);
          mask-image: linear-gradient(90deg, transparent 0%, #000 26%, #000 100%),
                      linear-gradient(180deg, #000 66%, transparent 99%);
  -webkit-mask-composite: source-in;
          mask-composite: intersect;
}
/* the plate crops the drift so the slow scale never shows an edge */
.face-art .plate { position: relative; overflow: hidden; }
.face-art .plate img {
  position: absolute; inset: -6%;
  width: 112%; height: 112%; max-width: none; object-fit: cover; object-position: 50% 42%;
  /* kept light enough that the traffic light trails still read, since the
     movement in this frame is the whole point of it being here */
  filter: contrast(1.08) brightness(1.02) saturate(1.16);
}
/* The portrait overlaps the plate and dissolves into it on its left edge.
   Butted straight up against each other the two columns met at a hard
   vertical seam down the middle of the hero. The overlap is what the mask
   needs to fade into: fading the edge without it would expose the hero
   background and trade the seam for a pale band. */
/* The overlap has to be at least as wide as the fade, or the portrait is
   still transparent where the plate has already ended and a pale band of
   hero background shows between them. The mask fades over 24% of the
   portrait, so -9% left an 84px gap. */
.face-art .portrait {
  position: relative; overflow: hidden; z-index: 1; margin-left: -26%;
  -webkit-mask-image: linear-gradient(90deg, transparent 0%, #000 24%, #000 100%);
          mask-image: linear-gradient(90deg, transparent 0%, #000 24%, #000 100%);
}
/* Centred, not left-biased. The outgoing headshot was already a tight head
   crop, so pulling the window left still framed his face. This one carries
   more chest, and at 30% the narrow portrait column on a phone showed the
   side of his head and nothing else. */
/* In colour on Vicky's direction, 2026-08-03. The brightness 1.24 that was
   here existed to stop a fully desaturated face going muddy under the wash;
   in colour it blows the highlights off his forehead and cheek, so it comes
   back down. A little saturation is still pulled out because a broadcast
   still is already punchy and the pink tie is the loudest thing on the page. */
.face-art .portrait img {
  width: 100%; height: 100%; object-fit: cover; object-position: 50% 62%;
  filter: saturate(1.0) contrast(1.02) brightness(1.08);
}
@media (max-width: 700px) {
  .face-art { width: 86vw; grid-template-columns: 32% 68%; }
  /* On a narrow screen the eyebrow and the full stop cross the portrait
     rather than clearing it, so he has to be a darker ground than either.
     Darkening the photograph is a better fix than veiling the whole hero
     flat, because it keeps the plate beside him.

     But dark is not the same as grey, and the first colour pass conflated
     them: at saturate(.8) under the mobile fade he still read black and
     white on a phone. Saturation goes UP to carry the colour through the
     darkening, and only brightness holds the contrast line. */
  .face-art .portrait img { filter: saturate(1.2) contrast(1.02) brightness(1.06); }
}
/* The wash is what married him to the slate, and at .72 to .92 alpha a
   `color` blend replaces the hue outright, which is a greyscale portrait by
   another route. Dropped to a lean rather than a repaint: enough to keep him
   from looking pasted onto the hero, not enough to take the colour back out.
   The oxblood corner stays, it is the only thing tying him to the accent. */
.face-wash {
  position: absolute; inset: 0; mix-blend-mode: color;
  background: linear-gradient(215deg, rgba(143,107,34,.16) 0%, rgba(106,102,96,.24) 48%, rgba(106,102,96,.34) 100%);
}
/* Retuned when the hero plate became the two-capitals photograph, which is
   considerably brighter than the street it replaced. The eyebrow, the
   subtitle and the dot after the name all sit in the 30 to 48 percent band
   and all three dropped under threshold until this carried further right.
   Past 60 percent it stays open so the towers and the traffic keep their
   colour, which is the reason for the picture. */
.face-fade {
  position: absolute; inset: 0;
  /* Was a LIGHT stone wash, which is the grey haze Vicky flagged: it lay
     over the capitol and turned it milky. A dark ramp does the same job for
     the type and does the opposite to the photograph, letting it deepen
     rather than fade. Nothing over the right third at all. */
  background: linear-gradient(90deg, var(--deep) 0%, rgba(44,43,41,.94) 24%,
                              rgba(44,43,41,.66) 44%, rgba(44,43,41,.22) 66%,
                              rgba(44,43,41,0) 84%);
}

/* On a narrow screen the type crosses the photograph. The first version of
   this carried a flat 90deg slate scrim all the way across at .4 to .5,
   which protected the type and greyed his face out along with it. That is
   the wash Vicky objected to, and it was doing far more work than the type
   actually needed.

   Measured at 390px: his face occupies y70 to y394. Of the type that
   crosses it, only the eyebrow sits inside that band. The h1 is huge bold
   white and survives on anything, and the subtitle and buttons sit at y409
   and below, over his suit.

   So the scrim is now vertical, not horizontal: near clear across the top
   third where his face is, ramping in below it where the rest of the type
   sits. The eyebrow is handled separately, by wrapping it clear of him
   rather than by veiling him. */
@media (max-width: 700px) {
  .face-fade {
    background:
      linear-gradient(180deg, rgba(106,102,96,0) 0%, rgba(106,102,96,0) 48%,
                              rgba(106,102,96,.30) 60%, rgba(106,102,96,.58) 74%,
                              rgba(106,102,96,.66) 100%),
      linear-gradient(90deg, var(--bg) 0%, rgba(106,102,96,.94) 36%,
                             rgba(106,102,96,.66) 50%, rgba(106,102,96,.14) 66%,
                             rgba(106,102,96,0) 80%);
  }
}

.hero h1 {
  font-family: var(--f-disp); font-weight: 700; text-transform: uppercase;
  font-size: clamp(2.6rem, 7.4vw, 5.4rem);
  letter-spacing: .1em; line-height: 1.12; color: #fff;
  margin: 0 0 34px;
}

.hero-sub {
  font-size: clamp(.84rem, 1.5vw, 1.02rem); letter-spacing: .27em;
  text-transform: uppercase; color: rgba(255,255,255,.9); font-weight: 300;
  margin: 0 0 42px; max-width: 34ch;
}

/* ── metric rail ────────────────────────────────────────────────────── */
/* four metrics since the Rice points figure came out, 2026-08-04 */
.rail { display: grid; grid-template-columns: repeat(4, 1fr); }
.rail div { padding: 34px 22px; border-left: 1px solid var(--rule-sd); text-align: center; }
.rail div:first-child { border-left: 0; }
.rail b {
  display: block; font-family: var(--f-disp); font-weight: 700;
  font-size: clamp(1.5rem, 3.1vw, 2.25rem); letter-spacing: .04em;
  color: var(--gold-lt); line-height: 1;
}
.rail span {
  display: block; margin-top: 12px;
  font-size: .66rem; letter-spacing: .21em; text-transform: uppercase;
  color: rgba(255,255,255,.7);
}
@media (max-width: 860px) {
  .rail { grid-template-columns: repeat(2, 1fr); }
  .rail div {
    border-left: 1px solid var(--rule-sd); border-top: 1px solid var(--rule-sd);
    /* the labels wrap to different line counts, so without this the cells
       are different heights and the grid reads ragged */
    display: flex; flex-direction: column; justify-content: center;
  }
  .rail div:nth-child(odd) { border-left: 0; }
  /* No last-child span. That existed when the rail had FIVE metrics, where
     the odd one out had to absorb the remainder of a two column grid. The
     Rice points figure came out on 2026-08-04 and four divides evenly, so
     the rule was stranding "100+ Exhibitions directed" alone on its own
     full width row instead of beside "14 Countries worked". */
}

/* ── section rhythm ─────────────────────────────────────────────────── */
.sec { padding: clamp(76px, 9vw, 112px) 0; }

.lead {
  font-size: clamp(1.08rem, 1.9vw, 1.42rem); line-height: 1.62;
  color: #fff; font-weight: 300; margin: 0;
}
.note { color: rgba(255,255,255,.8); font-size: .95rem; }

.two { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(32px, 5vw, 68px); align-items: start; }
@media (max-width: 900px) { .two { grid-template-columns: 1fr; } }

/* ── 01 Meet Brock: photograph, capabilities, photograph ────────────────
   The list is the centre of gravity, so it takes the wider middle track and
   the two frames flank it. Both photographs were the Trade and the Policy
   cards in 02 Practice until 2026-08-04. */
.meet {
  display: grid; grid-template-columns: 1fr 1.35fr 1fr;
  gap: clamp(24px, 3.4vw, 48px); align-items: center;
}
.meet-ph { margin: 0; }
.meet-ph img {
  width: 100%; height: auto; aspect-ratio: 1 / 1; object-fit: cover;
  /* Brock found these dull. They were being darkened twice: toned down at
     derive time AND dropped to brightness .94 here. Both frames are built
     bright now and this only lifts them slightly. No text sits on them, so
     nothing depends on holding them back. */
  filter: saturate(1.04) contrast(1.02) brightness(1.03);
}
.meet-ph figcaption {
  margin-top: 14px; text-align: center;
  font-family: var(--f-disp); font-size: .64rem; font-weight: 600;
  letter-spacing: .19em; text-transform: uppercase;
  /* Own value, not --gold-lt. These sit on the Meet Brock panel, the
     lightest ground on the page, where the brass reaches only 3.5:1.
     Same exception .caps .k already carries, and for the same reason. */
  color: #F7E4AF;
}
/* Two square frames beside a five row list stack into a very tall column on
   a phone, so below 900px the photographs go side by side above the list
   and keep it reachable. */
@media (max-width: 900px) {
  .meet { grid-template-columns: 1fr 1fr; gap: 20px 16px; }
  .meet .caps { grid-column: 1 / -1; order: 2; }
  .meet-ph:last-of-type { order: 1; }
}
@media (max-width: 520px) {
  .meet { grid-template-columns: 1fr; }
  .meet-ph:last-of-type { order: 3; }
}

/* capability rows, the slot the template fills with skill bars */
.caps li {
  display: grid; grid-template-columns: 108px 1fr; gap: 20px; align-items: baseline;
  padding: 15px 0; border-top: 1px solid var(--rule-sd);
}
.caps li:last-child { border-bottom: 1px solid var(--rule-sd); }
.caps dt, .caps .k {
  font-family: var(--f-disp); font-size: .68rem; font-weight: 600;
  letter-spacing: .19em; text-transform: uppercase;
  /* a step lighter than --gold-lt: these sit on the Brief panel, whose warm
     stone is the lightest ground on the page, and the shared token does not
     reach 4.5:1 against it */
  color: #FAEBC8;
}
.caps .v { color: rgba(255,255,255,.9); font-size: .95rem; }
@media (max-width: 620px) { .caps li { grid-template-columns: 1fr; gap: 4px; } }

/* ── timeline ───────────────────────────────────────────────────────────
   Alternating either side of a centre rule that draws down on scroll.
   No cards or boxes: the entries sit straight on the photograph, the way
   the template does it. */
.tl-key {
  display: grid; grid-template-columns: 1fr 1fr; gap: 76px; margin-bottom: 34px;
}
.tl-key span { font-size: .66rem; letter-spacing: .24em; text-transform: uppercase; color: rgba(255,255,255,.76); }
.tl-key span:first-child { text-align: right; }
@media (max-width: 860px) { .tl-key { display: none; } }

.tl { position: relative; }
.tl-line, .tl-fill {
  position: absolute; top: 0; bottom: 0; width: 1px; left: 7px;
}
.tl-line { background: rgba(255,255,255,.18); }
/* centred with a margin rather than a transform, so GSAP owns the whole
   transform property and scaleY cannot clobber the centring */
.tl-fill { background: var(--gold-acc); transform-origin: top; transform: scaleY(0); }

.tl-item { position: relative; padding-left: 38px; margin-bottom: 52px; }
.tl-item:last-child { margin-bottom: 0; }
.tl-dot {
  position: absolute; left: 7px; top: 9px; width: 11px; height: 11px;
  border-radius: 50%; background: var(--gold-acc); transform: translateX(-50%);
  box-shadow: 0 0 0 4px rgba(106,102,96,.75);
}
.tl-yr { font-size: .72rem; letter-spacing: .2em; text-transform: uppercase; color: var(--gold-lt); margin: 0 0 6px; }
/* The current role leads the list, so the entry below it steps back to 2023
   and reads as a jump. Marking this one current explains the top slot and
   lets the 2023 engagement read as concurrent, which it is. */
.tl-now {
  display: inline-block; vertical-align: middle; margin-left: 10px;
  padding: 3px 9px 2px; background: var(--gold); color: #fff;
  font-family: var(--f-disp); font-size: .58rem; font-weight: 600;
  letter-spacing: .18em; text-transform: uppercase;
}
.tl-item h3 {
  font-family: var(--f-disp); font-weight: 400; text-transform: uppercase;
  font-size: clamp(1.15rem, 2.1vw, 1.5rem); letter-spacing: .1em; color: #fff; margin: 0 0 4px;
}
.tl-org { font-weight: 700; font-size: .92rem; color: #fff; margin: 0 0 8px; }
.tl-item p:last-child { color: rgba(255,255,255,.82); font-size: .93rem; margin: 0; max-width: 42ch; }

@media (min-width: 861px) {
  .tl-line, .tl-fill { left: 50%; margin-left: -.5px; }
  .tl-item { width: calc(50% - 54px); padding-left: 0; margin-bottom: 26px; }
  .tl-item.side-cn { margin-left: auto; }                       /* right column */
  .tl-item.side-us { margin-right: auto; text-align: right; }   /* left column  */
  .tl-item.side-us p:last-child { margin-left: auto; }
  .tl-dot { left: auto; }
  .side-cn .tl-dot { left: -54px; transform: none; }
  .side-us .tl-dot { right: -54px; left: auto; }
}

/* ── policy list ────────────────────────────────────────────────────── */
.orgs li {
  position: relative; padding: 13px 0 13px 26px;
  border-top: 1px solid var(--rule-sd);
  font-size: .92rem; letter-spacing: .04em; color: rgba(255,255,255,.92);
}
.orgs li:last-child { border-bottom: 1px solid var(--rule-sd); }
.orgs li::before {
  content: ''; position: absolute; left: 0; top: 1.5em;
  width: 12px; height: 1px; background: var(--gold-acc);
}

/* ── honors ─────────────────────────────────────────────────────────────
   Was a definition list of label plus detail. Two of the three entries are
   now verbatim resume sentences with no label to pull out of them, so it is
   a plain list and only the degree keeps a heading. */
.honors > li { padding: 18px 0; border-top: 1px solid var(--rule-sd); color: rgba(255,255,255,.86); font-size: .92rem; }
.honors > li:last-child { border-bottom: 1px solid var(--rule-sd); }
.honors b {
  display: block; font-family: var(--f-disp); font-weight: 600; font-size: .82rem;
  letter-spacing: .15em; text-transform: uppercase; color: var(--gold-lt); margin-bottom: 6px;
}

figure { margin: 0; }
/* pushed cold so the warm court floor does not fight the slate panel */

/* the jersey wall, sitting with the countries it is evidence for */
.jerseys { margin: 30px 0 40px; }
.jerseys img {
  /* No aspect-ratio and no cover: the whole 750x610 frame, so every jersey
     is in shot. Cropping this to a 21/8 band was what made it read as a
     blurry zoom. */
  width: 100%; height: auto; max-width: 900px; margin-inline: auto;
  filter: saturate(1.06) contrast(1.02) brightness(1.05);
}

/* ── 05, rebuilt as horizontal bands, 2026-08-04 ──────────────────────
   Was two columns: intro plus two photographs on the left, three honours
   and a third photograph on the right. The columns ended up wildly
   different heights and the third frame sat inside a list item, which is
   why it read as badly balanced. Now it runs as four full width bands:
   lead, three frames, three honours, then the countries. */
.bb-lead {
  text-align: center; max-width: 58ch; margin: 0 auto 52px;
  color: rgba(255,255,255,.9); font-size: clamp(.94rem, 1.5vw, 1.06rem);
}
/* Desktop puts the three frames in row 1 and the three honours in row 2 of
   one grid. `display: contents` lets the two lists' children participate in
   it directly, so the Rice frame can sit in row 1 column 3 even though it
   comes last in the markup. `role="list"` keeps the list semantics that
   `display: contents` would otherwise drop in Safari. */
.bb-body { display: grid; grid-template-columns: repeat(3, 1fr); column-gap: 16px; }
.bb-shots { display: contents; }
.bb-shots > li { grid-row: 1; }
.bb-rice { grid-row: 1; grid-column: 3; margin: 0; }
.bb-rice img,
.bb-shots img {
  width: 100%; height: auto; aspect-ratio: 4 / 5; object-fit: cover;
  filter: saturate(1.05) contrast(1.02) brightness(1.04);
}

/* the three honours occupy row 2 of the same grid */
/* Four entries now that Glory Road is back, so this is its own two column
   grid spanning row 2 rather than three cells of the parent. The two long
   resume sentences take the top row at half width each, the two short ones
   sit beneath them. */
.honors {
  display: grid; grid-template-columns: repeat(2, 1fr);
  gap: 0 36px; grid-column: 1 / -1; grid-row: 2; margin-top: 58px;
}
.honors > li { margin-top: 0; }
.honors cite { font-style: italic; }
/* Near white, not .86. Three across puts these over the lit court of the
   arena at 1024, where the warm plate is brighter than the teal one it
   replaced and .86 dropped to 3.41:1. */
.honors > li { padding: 20px 0 0; border-top: 1px solid var(--rule-sd); border-bottom: 0; color: #fff; }

/* the jersey wall beside the countries it is evidence for, not above them.
   At full width it was a 900px slab that dominated the section. */
.bb-atlas { display: grid; grid-template-columns: 380px 1fr; gap: 38px; align-items: start; }
.bb-atlas .jerseys { margin: 0; }
.bb-atlas .jerseys img { max-width: none; }
.bb-atlas .atlas { grid-template-columns: repeat(4, 1fr); }
.bb-atlas .atlas li:last-child { grid-column: span 4; }

@media (max-width: 900px) {
  .bb-atlas { grid-template-columns: 1fr; gap: 26px; }
  .bb-atlas .jerseys { max-width: 460px; margin-inline: auto; }
  /* Plain flow on a phone, so the markup order is what shows: the two
     action frames, the three honours, then the Rice frame directly under
     the degree line it illustrates. */
  .bb-body { display: block; }
  .bb-shots { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
  .bb-shots > li, .honors > li { grid-row: auto; }
  .honors { display: block; grid-column: auto; grid-row: auto; margin-top: 44px; }
  .honors > li { margin-top: 0; }
  .bb-rice { grid-row: auto; grid-column: auto; margin: 18px auto 0; max-width: 300px; }
}
@media (max-width: 620px) {
  .bb-shots { gap: 8px; }
  .bb-atlas .atlas { grid-template-columns: repeat(2, 1fr); }
  .bb-atlas .atlas li:last-child { grid-column: span 2; }
}

/* ── the atlas ──────────────────────────────────────────────────────── */
.atlas-n {
  display: flex; align-items: baseline; gap: 20px; flex-wrap: wrap; margin: 0 0 26px;
}
.atlas-n b {
  font-family: var(--f-disp); font-weight: 700; font-size: clamp(2.4rem, 5.4vw, 3.6rem);
  letter-spacing: .04em; color: var(--gold-lt); line-height: .9;
}
/* .76 white cleared this everywhere except 1024, where the arena plate
   sits with its lit court exactly behind this line. Raised rather than
   veiled, because #game is the one panel that keeps its own colour. */
.atlas-n span { font-size: .72rem; letter-spacing: .22em; text-transform: uppercase; color: rgba(255,255,255,.88); }

/* Each cell carries its own hairline rather than the grid carrying a
   background, so the incomplete last row does not read as an empty band. */
/* Thirteen is prime, so no column count divides it evenly and the last row
   always ends short. The last cell absorbs the remainder at each breakpoint
   so the row closes: 7 cols leaves 6 over, 3 leaves 1, 2 leaves 1. Hard
   coded on purpose, the list is a fixed thirteen and will not grow. */
.atlas { display: grid; grid-template-columns: repeat(7, 1fr); gap: 1px; }
.atlas li:last-child { grid-column: span 2; }
.atlas li {
  background: rgba(40,39,37,.66); padding: 16px 18px; transition: background-color .2s;
  box-shadow: 0 0 0 1px rgba(255,255,255,.11);
}
.atlas li:hover { background: rgba(143,107,34,.42); }
.atlas b { display: block; font-size: .92rem; font-weight: 600; color: #fff; letter-spacing: .02em; }
.atlas span { display: block; margin-top: 3px; font-size: .6rem; letter-spacing: .18em; text-transform: uppercase; color: rgba(255,255,255,.66); }
@media (max-width: 1100px) { .atlas { grid-template-columns: repeat(3, 1fr); } .atlas li:last-child { grid-column: span 3; } }
@media (max-width: 560px)  { .atlas { grid-template-columns: repeat(2, 1fr); } .atlas li:last-child { grid-column: span 2; } }

/* ── the three-across image band ────────────────────────────────────────
   The template's portfolio grid: three photographs edge to edge with no
   gutter, label centred over each. Here it carries his three domains. */
.work { display: grid; grid-template-columns: repeat(3, 1fr); }
.work li {
  position: relative; overflow: hidden; aspect-ratio: 1 / 1;
  isolation: isolate;
}
.work img {
  position: absolute; inset: -5%;
  /* max-width:none is required: the base img rule would cap these at 100%
     of the cell, and the oversize is what gives the drift room to move */
  width: 110%; height: 110%; max-width: none; object-fit: cover;
  filter: grayscale(.14) saturate(1.3) contrast(1.08) brightness(.76);
  transition: filter .55s ease, transform .9s var(--ease);
  z-index: -1;
}
.work li::after {
  content: ''; position: absolute; inset: 0; z-index: -1;
  /* Weighted to the middle rather than the foot of the card. The label sits
     centred, and on these warm plates the brightest thing in frame (floodlit
     columns, arena lights) is at exactly that height, so a bottom-heavy
     scrim darkened everything except the part that needed it. */
  background: linear-gradient(180deg,
    rgba(22,29,44,.14) 0%, rgba(22,29,44,.62) 40%,
    rgba(22,29,44,.62) 64%, rgba(22,29,44,.48) 100%);
}
.work li:hover img { filter: grayscale(0) saturate(1.44) contrast(1.1) brightness(.94); transform: scale(1.05); }

.work b {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 12px; padding: 20px; text-align: center;
  font-family: var(--f-disp); font-weight: 600;
  font-size: clamp(.76rem, 1.35vw, .92rem); letter-spacing: .17em;
  text-transform: uppercase; color: #fff;
  text-shadow: 0 2px 18px rgba(16,15,14,.8);
}
.work b i {
  font-style: normal; font-size: .68rem; letter-spacing: .24em;
  color: var(--gold-lt); opacity: .95;
}
@media (max-width: 760px) { .work { grid-template-columns: 1fr; } }

/* ── 02 Expertise, the disciplines ──────────────────────────────────────
   Set as plain words on Vicky's direction, 2026-08-04. These used to be
   bordered pills, which read as UI chips rather than as a list of what he
   does. Nothing but type and space now, so the spacing has to do the work
   the borders were doing: generous column gaps, a looser row gap so wrapped
   lines stay distinct, and no hover state because there is nothing to
   hover on. */
.tags {
  display: flex; flex-wrap: wrap; justify-content: center;
  column-gap: clamp(22px, 3.2vw, 46px); row-gap: 16px;
}
.tags li {
  font-family: var(--f-disp); font-size: clamp(.68rem, 1.1vw, .78rem);
  font-weight: 500; letter-spacing: .19em; text-transform: uppercase;
  color: rgba(255,255,255,.9);
}

/* ── 02 Expertise, the three media frames ───────────────────────────── */
.media { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; margin-top: 52px; }
.media img {
  width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover;
  filter: saturate(1.04) contrast(1.02) brightness(1.04);
}
@media (max-width: 760px) { .media { grid-template-columns: 1fr; gap: 12px; } }

/* ── 04, him leaving the West Wing, under the lead ──────────────────── */
/* Desktop: lead top left, photograph beneath it, list down the right across
   both rows. The markup order is lead, list, photograph, because that is the
   order a phone needs. */
.statecraft-two { align-items: start; }
.statecraft-two .lead { grid-row: 1; grid-column: 1; }
.statecraft-two .orgs { grid-row: 1 / span 2; grid-column: 2; }
.statecraft-two .statecraft-ph { grid-row: 2; grid-column: 1; }
/* Base first, media query after. This rule used to sit BELOW the query and
   its `margin` shorthand reset the `margin-inline: auto` in it, which is why
   the frame stayed hard left on a phone and a tablet. */
.statecraft-ph { margin: 30px 0 0; max-width: 330px; }
@media (max-width: 900px) {
  /* single column, so plain flow puts the photograph last, centred */
  .statecraft-two .lead,
  .statecraft-two .orgs,
  .statecraft-two .statecraft-ph { grid-row: auto; grid-column: auto; }
  .statecraft-ph { margin: 30px auto 0; }
}
.statecraft-ph img {
  width: 100%; height: auto;
  filter: saturate(1.05) contrast(1.02) brightness(1.05);
}


/* ── 06, the photograph that replaced the copy beside the form ──────── */
.inquiry-ph { margin: 0; align-self: start; }
.inquiry-ph img {
  width: 100%; height: auto;
  filter: saturate(1.05) contrast(1.02) brightness(1.04);
}

/* ── contact, a panel floating on a photograph ──────────────────────── */
.contact-card {
  background: var(--navy); padding: clamp(38px, 6vw, 76px);
  display: grid; grid-template-columns: 320px 1fr; gap: clamp(32px, 5vw, 64px);
  box-shadow: 0 24px 64px rgba(16,15,14,.36);
}
@media (max-width: 900px) { .contact-card { grid-template-columns: 1fr; } }

.contact-card h2 {
  font-family: var(--f-disp); font-weight: 700; text-transform: uppercase;
  font-size: clamp(1.4rem, 2.6vw, 1.9rem); letter-spacing: .13em; color: #fff; margin: 0 0 18px;
}

.form { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
.form .full { grid-column: 1 / -1; }
@media (max-width: 620px) { .form { grid-template-columns: 1fr; } }

.f { display: flex; flex-direction: column; gap: 7px; }
.f label { font-size: .68rem; letter-spacing: .18em; text-transform: uppercase; color: rgba(255,255,255,.74); }

/* Fields sit in the palette rather than as white boxes punched through the
   navy card. color-scheme keeps the native select popup and the caret dark
   to match instead of rendering light. */
.form { color-scheme: dark; }
.f input, .f select, .f textarea {
  font-family: var(--f-body); font-size: .96rem; color: #fff;
  background: rgba(22,29,44,.5); border: 1px solid rgba(255,255,255,.17);
  padding: 12px 14px; width: 100%;
  transition: border-color .2s, background-color .2s, box-shadow .2s;
}
.f input::placeholder, .f textarea::placeholder { color: rgba(255,255,255,.42); }
.f textarea { resize: vertical; }
.f input:hover, .f select:hover, .f textarea:hover { border-color: rgba(255,255,255,.3); }
.f input:focus, .f select:focus, .f textarea:focus {
  outline: none; border-color: var(--gold-acc);
  background: rgba(22,29,44,.66);
  box-shadow: 0 0 0 3px rgba(212,175,55,.26);
}
/* the native arrow would be dark on a dark field, so it is drawn here */
.f select {
  appearance: none; -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath fill='%23F2BEC9' d='M1 1.5 6 6.5l5-5'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 14px center; background-size: 12px 8px;
  padding-right: 38px;
}
/* the popup list is drawn by the OS, so it needs its own colours */
.f select option { background: var(--deep); color: #fff; }
/* without this the browser repaints an autofilled field white and the
   fields the visitor actually used become the odd ones out */
.f input:-webkit-autofill,
.f input:-webkit-autofill:focus,
.f textarea:-webkit-autofill,
.f select:-webkit-autofill {
  -webkit-text-fill-color: #fff;
  -webkit-box-shadow: 0 0 0 40px #232B3C inset;
  caret-color: #fff;
}
.hp { position: absolute; left: -9999px; }

/* ── footer ─────────────────────────────────────────────────────────── */
.foot { background: var(--deep); padding: 40px 0; }
.foot .wrap { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 20px; }
.foot a { color: rgba(255,255,255,.82); text-decoration: none; transition: color .2s; }
.foot a:hover { color: var(--gold-lt); }
.foot-links { display: flex; gap: 26px; font-size: .7rem; letter-spacing: .18em; text-transform: uppercase; }
.foot small { font-size: .7rem; color: rgba(255,255,255,.72); }
.foot small a { color: var(--gold-lt); }

/* ── motion base states ─────────────────────────────────────────────────
   Applied only under .js, which motion.js sets itself. If the GSAP CDN
   fails the page renders fully visible rather than blank. */
.js .a-up     { opacity: 0; transform: translateY(30px); }
.js .a-fade   { opacity: 0; }
.js .a-wipe   { opacity: 0; clip-path: inset(0 0 100% 0); }
.js .a-reveal { clip-path: inset(0 0 100% 0); }

/* Slow continuous drift on the photographs. Not scroll driven, so the page
   is never completely still even when the visitor is not moving. */
@keyframes drift {
  0%   { transform: scale(1)    translate3d(0, 0, 0); }
  50%  { transform: scale(1.07) translate3d(-1.2%, -1.4%, 0); }
  100% { transform: scale(1)    translate3d(0, 0, 0); }
}
.js [data-drift] { animation: drift 26s ease-in-out infinite; }
.js .work li:nth-child(2) [data-drift] { animation-duration: 31s; animation-delay: -7s; }
.js .work li:nth-child(3) [data-drift] { animation-duration: 22s; animation-delay: -13s; }
/* hover scale must beat the drift keyframes */
.work li:hover img[data-drift] { animation-play-state: paused; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .js .a-up, .js .a-fade, .js .a-wipe, .js .a-reveal {
    opacity: 1 !important; transform: none !important; clip-path: none !important;
  }
  .panel-img, .face { transform: none !important; }
  .js [data-drift] { animation: none !important; }
}

/* ── narrow screens: the vivid panel needs a heavier veil ──────────────
   #game keeps its colour on purpose, but once the two columns stack, the
   honors list sits directly on the lit court instead of beside it. The
   veil is written inline on the section, so this has to override it. */
@media (max-width: 900px) {
  #game .panel-veil {
    /* Raised again once #game got a portrait plate. The landscape one was
       cropped to an 8 percent sliver here, which was effectively its own
       veil. Showing 29 percent of the actual arena put more lit court
       behind the honors list, and "1,007 CAREER POINTS" dropped to 4.36:1
       at 430px. Wider phones show more of the plate, so this is tuned at
       430, not 390. */
    background: linear-gradient(180deg, #1B1A18 0%, rgba(27,26,24,.72) 18%,
      rgba(27,26,24,.86) 46%, rgba(27,26,24,.90) 82%, #1B1A18 100%) !important;
  }
}

/* ═══════════════════════════════════════════════════════════════════════
   SMALL SCREENS
   ═══════════════════════════════════════════════════════════════════════
   Everything below lives inside a max-width query. Nothing here can reach
   the desktop layout, which is deliberate: the desktop composition is
   signed off and mobile is treated as its own design rather than as the
   desktop squeezed narrow.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── the menu button ────────────────────────────────────────────────── */
.nav-toggle {
  display: none;                       /* shown only under 900px, below */
  width: 46px; height: 46px; flex: none;
  align-items: center; justify-content: center;
  background: none; border: 1px solid var(--rule); cursor: pointer;
  padding: 0; margin-left: auto;
}
.nav-bars, .nav-bars::before, .nav-bars::after {
  display: block; width: 19px; height: 1.5px; background: #fff;
  transition: transform .3s var(--ease), opacity .2s;
}
.nav-bars::before, .nav-bars::after { content: ''; position: absolute; }
.nav-bars { position: relative; }
.nav-bars::before { transform: translateY(-6px); }
.nav-bars::after  { transform: translateY(6px); }
/* the bars converge into a cross */
.nav.open .nav-bars { background: transparent; }
.nav.open .nav-bars::before { transform: rotate(45deg); }
.nav.open .nav-bars::after  { transform: rotate(-45deg); }

/* ── the panel ──────────────────────────────────────────────────────── */
.menu {
  position: absolute; top: 100%; left: 0; right: 0;
  display: none;                       /* shown only under 900px, below */
  /* solid, not translucent: at 98.5% the hero name still ghosted through
     the panel and read as a rendering fault rather than an effect */
  background: #202634;
  border-bottom: 1px solid rgba(255,255,255,.08);
  box-shadow: 0 24px 54px rgba(10,14,24,.5);
  padding: 10px 0 26px;
  /* dvh, not vh: the panel has to fit the space the address bar leaves */
  max-height: calc(100dvh - 68px);
  overflow-y: auto;
  opacity: 0; visibility: hidden; transform: translateY(-10px);
  transition: opacity .3s var(--ease), transform .3s var(--ease), visibility .3s;
}
.nav.open .menu { opacity: 1; visibility: visible; transform: none; }

/* All of these need the .nav prefix. The panel lives inside <header
   class="nav">, so the base `.nav nav` and `.nav nav a` rules apply to it
   and out-specify a lone class: they were centring the links, spacing them
   30px apart and shrinking them to the desktop nav's 12px. */
.nav .menu-nav { display: flex; flex-direction: column; align-items: stretch; gap: 0; }
.nav .menu-nav a {
  display: flex; align-items: baseline; gap: 16px;
  padding: 17px 24px;                  /* 55px tall, comfortably tappable */
  font-family: var(--f-disp); font-weight: 500; font-size: .94rem;
  letter-spacing: .13em; text-transform: uppercase;
  color: rgba(255,255,255,.9); text-decoration: none;
  border-bottom: 1px solid rgba(255,255,255,.07);
  transition: color .2s, background-color .2s;
}
.nav .menu-nav a:first-child { border-top: 1px solid rgba(255,255,255,.07); }
.nav .menu-nav a:hover, .nav .menu-nav a:active, .nav .menu-nav a.on { color: #fff; background: rgba(212,175,55,.14); }
.nav .menu-nav a.on i { opacity: 1; }
/* full width rather than shrink to fit: it is the one action in the panel */
.menu-cta { display: flex; margin: 24px 24px 0; }

body.menu-open { position: fixed; left: 0; right: 0; width: 100%; }

@media (prefers-reduced-motion: reduce) {
  .menu, .nav-bars, .nav-bars::before, .nav-bars::after { transition: none; }
}

/* ══════════════════════════════════════════════════════════════════════ */
@media (max-width: 900px) {
  .nav-toggle { display: flex; }
  .menu { display: block; }
  /* The inline links are replaced by the panel rather than sitting beside
     it, otherwise Contact appears twice. Needs .nav .nav-links, not just
     .nav-links: the base rule is `.nav nav`, which out-specifies a lone
     class and left the link visible next to the button. */
  .nav .nav-links { display: none; }

  /* svh, not vh. A 100vh hero is taller than the visible area while the
     mobile address bar is showing, so the buttons start below the fold and
     the page jumps as the bar retracts. */
  /* ── the mobile hero is stacked, not overlaid ──────────────────────
     Every previous attempt kept type on top of the photograph and then
     tried to keep it legible with a scrim, and the scrim always landed on
     his face. Three passes of tuning gradients did not fix that because
     the overlap was the problem, not the gradient.

     So there is no overlap. The photograph takes the upper region on its
     own, edge to edge, with nothing over it at all, and the name sits
     below it on solid stone. Perfect contrast for the type, an untouched
     photograph, and no gradient to tune. */
  .hero {
    min-height: 100svh; padding: 0;
    display: grid; grid-template-rows: 1fr auto; justify-content: stretch;
  }
  .hero-glow { display: none; }

  /* z-index must come back to auto: the base rule parks .face at -1 so it
     sits behind the hero in the overlaid desktop layout, and in the stacked
     one that puts it behind the hero's own background colour, which renders
     the photo region as an empty grey box. */
  .face { position: relative; inset: auto; z-index: auto; grid-row: 1; overflow: hidden; }
  .face-art {
    position: absolute; inset: 0; width: 100%;
    /* one track, not two. `.plate` is display:none below, so the portrait
       becomes the first grid item: a `0 100%` template put it in the zero
       width track and the photo region rendered empty. */
    grid-template-columns: 100%;
    -webkit-mask-image: none; mask-image: none;
  }
  .face-art .plate { display: none; }
  .face-art .portrait { margin-left: 0; -webkit-mask-image: none; mask-image: none; }
  /* nothing sits on him now, so he needs no darkening and no colour wash */
  .face-art .portrait img { object-position: 50% 58%; filter: saturate(1.06) contrast(1.02) brightness(1.05); }
  /* The photograph met the stone block on a hard horizontal line. This
     dissolves the last 90px of it into that block. It sits over his chest,
     never his face, which is the distinction that matters here. */
  .face::after {
    content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 92px;
    background: linear-gradient(180deg, rgba(44,43,41,0) 0%, rgba(44,43,41,.72) 62%, var(--deep) 100%);
    pointer-events: none;
  }
  .face-fade { display: none; }

  .hero .wrap { grid-row: 2; background: var(--deep); padding-top: 34px; padding-bottom: 40px; }

  /* ── moderate trim: less padding, same content ── */
  .sec { padding: 62px 0; }
  .sec-head { margin-bottom: 38px; }

  /* Eight lines of centred uppercase is the hardest thing on the page to
     read on a phone. Sentence case, left aligned, tighter leading. */

  /* under 13px is a strain at arm's length */
  .sec-sub { font-size: .84rem; letter-spacing: .2em; }
  .btn { font-size: .82rem; padding: 16px 26px; }
  .rail span { font-size: .72rem; letter-spacing: .16em; }
  .rail div { padding: 26px 16px; }
  .rail b { font-size: 2rem; }

  /* 44px minimum tap targets */
  .foot-links a { display: inline-block; padding: 12px 0; }
  .foot small a { display: inline-block; padding: 6px 0; }

  /* The two column grid existed to stop seven pills wrapping raggedly.
     Without borders there is nothing to line up, so they centre and wrap
     as words. */
  .tags { column-gap: 20px; row-gap: 12px; }
  .tags li { font-size: .64rem; letter-spacing: .14em; }


  /* The eyebrow ran the full 390 and crossed his face, and it was the only
     run that forced the old flat scrim. Held to the left column it wraps to
     two lines and clears him, so the photograph does not have to be veiled
     to protect 11px of letterspaced caps. Same for the subtitle. */
  /* THE FULL STOP IS WHY HIS FACE WAS GREY. It lands on his jaw, the
     ground there is lit skin next to dark lapel, and no mark colour clears
     3:1 against both. Every attempt to rescue it ended in a scrim band
     across his face, which is the exact thing being fixed. It is a
     decorative full stop after a name that already reads as a name. On a
     phone it goes, and his face gets to be a photograph. */

  /* Same reasoning. The wash is a `mix-blend-mode: color` layer that pulls
     him toward the slate so the hero reads as one image. That is right on
     a desktop, where he is one column of a diptych. On a phone he IS the
     hero, and marrying him to the background is what made him look washed
     out. Desktop keeps it. */
  .face-wash { display: none; }

  /* The leading rule eats about 50px of a 390px screen. Dropping it buys
     the text enough room to break in two rather than three lines while
     still stopping clear of his face. It is decoration and it is already
     aria-hidden. */
  /* Narrowing alone could not clear him: "INTERNATIONAL" is a single
     unbreakable word and at .74rem/.3em it is already 190px wide, so the
     box could not get smaller than the word. Tracking and size come down
     together, which is what actually moves the right edge off his face. */
  .hero-sub { max-width: 190px; }

  /* The drift loop scales plates to 1.07 and slides them -1.2%/-1.4% over
     26s. On a desktop that is ambient. On a phone it reads as the page
     sliding left to right under your thumb, and the plates are cropped so
     hard here that it buys nothing anyway. */
  .js [data-drift] { animation: none !important; }

  /* ── portrait plates for the tall mobile panels ──────────────────────
     Every panel plate is a 16:9 photograph and `background-size: cover`
     against a 390px wide box that runs 888 to 2685px tall. Measured on
     the live page, that showed a vertical sliver of each: 8 percent of
     the arena, 11 percent of the pumpjack, 14 to 25 percent of the rest.
     The pumpjack read as a dark smear and the arena as flat navy.

     Portrait sources fix it at the image, not the CSS: at 0.50 these keep
     roughly a third to a half of their width instead of a tenth. The
     background-image is set inline in index.html, so these need
     !important to be reached at all.

     Media-query background-images are only fetched when the query
     matches, so desktop never downloads these and mobile never downloads
     the landscape ones. No page weight cost either way. */
  #brief    .panel-img { background-image: url('../assets/img/m-brief-campus.jpg') !important; }
  #practice .panel-img { background-image: url('../assets/img/m-practice-skyline.jpg') !important; }
  #record   .panel-img { background-image: url('../assets/img/m-record-rig.jpg') !important; }
  #game     .panel-img { background-image: url('../assets/img/m-arena-warm.jpg') !important; }
  #contact  .panel-img { background-image: url('../assets/img/m-inquiries-palace.jpg') !important; }

  /* 04 Policy keeps its landscape plate. At a 888px tall box it still
     shows 25 percent of the Blue Room, which reads as a room. */

  /* Full-width squares cost about 1000px of scroll for three labels, so
     these are letterboxed on a phone. 16/10 was chosen when the three
     cards were generated plates with nothing in them, and cropping the
     top and bottom off scenery costs nothing.

     They are photographs of people now, and 16/10 out of a 900x900 source
     keeps only 63 percent of the height, centred, which cut the tops of
     the heads off cards 01 and 02. 4/3 keeps 75 percent and costs about
     130px of scroll in total across the three. */
  .work li { aspect-ratio: 4 / 3; }

  /* Centre is the wrong anchor once there is a subject in frame. With
     cover, object-position Y places the kept band at Y x 25% from the top.
     01 has both men's heads high in the crop, 02 reads better weighted
     down onto him and off the sky. 03 is a flat wall of jerseys and does
     not care. */
  .work li:nth-child(1) img { object-position: 50% 18%; }
  .work li:nth-child(2) img { object-position: 50% 62%; }

  /* The float card that #brief used to clear is gone, so its compensating
     padding went with it. */

  /* The Global Game is the longest section on the page by some way. This is
     spacing only, nothing is dropped. */
  .shot { margin-top: 26px; }
  #game .two > div > .note { max-width: none; }
  .atlas-n { margin-bottom: 18px; }
}

/* ── the timeline keeps its two sides ───────────────────────────────────
   The rule collapses to a single column here, but the section's own copy
   says each appointment sits on the side of the relationship it was worked
   from. Without a marker that sentence describes something the reader
   cannot see, so each entry states its side and the dot carries the
   colour. */
@media (max-width: 860px) {
  .tl-item { padding-left: 34px; margin-bottom: 40px; }
  .tl-item::before {
    content: 'United States';
    display: inline-block; margin-bottom: 9px;
    font-family: var(--f-disp); font-size: .56rem; font-weight: 600;
    letter-spacing: .19em; text-transform: uppercase;
    color: rgba(255,255,255,.66);
    border: 1px solid rgba(255,255,255,.2); padding: 4px 9px;
  }
  .tl-item.side-cn::before {
    content: 'China & International';
    color: var(--gold-lt); border-color: rgba(212,175,55,.55);
  }
  .tl-item.side-us .tl-dot { background: rgba(255,255,255,.5); }
}

@media (max-width: 560px) {
  .rail { grid-template-columns: 1fr 1fr; }
  .nav .menu-nav a { font-size: .88rem; }
}

/* ── wikipedia citation, footer band ─────────────────────────────
   Official unmodified marks, linked only to the article. Globe is a trimmed
   raster (the source SVG is 54KB gzipped for a 30px mark); wordmark is the
   public-domain white SVG so it stays crisp and needs no recolouring. */
.wiki-note {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  margin: 0; font-size: .68rem; font-weight: 400;
  letter-spacing: .22em; text-transform: uppercase;
  color: rgba(255,255,255,.72);
}
.wiki-note a {
  display: inline-flex; align-items: center; gap: 9px;
  text-decoration: none; padding: 4px 2px;
  opacity: .88; transition: opacity .25s var(--ease);
}
.wiki-note a:hover, .wiki-note a:focus-visible { opacity: 1; }
.wiki-note img { display: block; width: auto; }
.wiki-note .wiki-wordmark { height: auto; }

/* hero: sits under the tagline, deliberately quiet */

/* footer band: its own strip above the footer rule, centred.
   Wide lockup here rather than the bare wordmark, chosen 2026-08-13. */
.wiki-band { background: var(--deep); padding: 34px 0 6px; }
.wiki-band .wrap { display: flex; justify-content: center; }
.wiki-note--foot { justify-content: center; text-align: center; }
.wiki-note--foot .wiki-lockup { height: 58px; }

@media (max-width: 560px) {
  .wiki-note { gap: 10px; font-size: .63rem; letter-spacing: .18em; }
  .wiki-note--foot { flex-direction: column; gap: 12px; }
  .wiki-note--foot .wiki-lockup { height: 46px; }
}
