/* ═══════════════════════════════════════════════════════════════════════════
   The Trace — CV / experience page
   Extends site.css. Nothing here re-declares a token, a face, a button, a
   pill, a rule-head, a deflist or the stat wall: those all come from
   site.css, and .stats / .stat / .stat.tbc in particular are used as-is.

   Three rules this sheet inherits and does not bend:

   1. FONT FAMILY NAMES ARE ALWAYS QUOTED, which is why every family here
      comes through var(--display) / var(--label) / var(--text) / var(--code)
      rather than a literal name. That includes the SVG map labels.

   2. REVEALS NEVER GATE VISIBILITY. The three reveals ported from the live
      site (land-mass stagger, panel crossfade, APM chip settle) animated
      opacity from 0, so a chip whose rAF never ran was invisible. All three
      are transform-only here.

   3. ONE PULSING ELEMENT ON THE SITE, the header brand dot. The live site's
      selected-country contour pulsed for ever and the parked delivery rings
      pulsed too. The contour is now a static stroke, and the parked ring
      styling is not ported at all (coverage-map.js still carries the parked
      function, unstyled and uncalled).
   ═══════════════════════════════════════════════════════════════════════ */

/* the map section is an in-page anchor target under a sticky header */
.sec[id] { scroll-margin-top: 86px; }

/* ─────────── today: the claim, and the live GPN chip ─────────── */
/* the claim is two sentences, so it needs a smaller ceiling than the shared
   .page-head h1 clamp, which is sized for four or five words */
.page-head.cv-head h1 { font-size: clamp(29px, 4.3vw, 56px); max-width: 27ch; line-height: 1.0;
       text-wrap: balance; }
.page-head.cv-head p { margin-bottom: 14px; }

.gpn-tick { display: inline-flex; align-items: center; gap: 10px; flex-wrap: wrap;
       border: 1px solid var(--hair-2); background: var(--surface); padding: 8px 14px;
       font-family: var(--code); font-size: 12px; letter-spacing: 0.03em; color: var(--body); }
.gpn-tick b { color: var(--ox); font-weight: 700; }
.gpn-tick .sep { color: var(--meta); }
.gpn-tick em { font-style: normal; color: var(--meta); font-size: 10px;
       text-transform: uppercase; letter-spacing: 0.06em; }
@media (max-width: 700px) { .gpn-tick { font-size: 11px; padding: 7px 12px; } }

/* ─────────── the stat wall: site.css owns .stats / .stat ─────────── */
/* two cells the shared component does not cover: a paired figure, and a
   figure the source states in words because it states no number */
.stat .n .sep { color: var(--meta); font-size: 0.62em; margin: 0 2px; }
.stat.words .n { font-size: clamp(20px, 1.9vw, 25px); line-height: 1.16; letter-spacing: 0.01em; }
.stat .l a { color: var(--ox); font-weight: 700; border-bottom: 1.5px solid var(--ox);
       white-space: nowrap; }
.stat .l a:hover { color: var(--ink); border-color: var(--ink); }
/* Five cells, and the shared component's auto-fit only clears the right
   border on the very last one, so at any width where the wall wraps it leaves
   a stray vertical rule down its right edge and a bottom rule that stops
   short of it. Column counts are explicit here and the cell that ends each
   row drops its right border; the container carries the closing rule under a
   part-filled row. */
@media (min-width: 1120px) { .stats { grid-template-columns: repeat(5, minmax(0,1fr)); } }
/* the closing rule is only needed where the last row is part filled, so it
   never doubles up with a full row's own bottom border */
@media (max-width: 1119px) and (min-width: 769px) {
  .stats { grid-template-columns: repeat(3, minmax(0,1fr)); border-bottom: 1px solid var(--hair); }
  .stats .stat:nth-child(3n) { border-right: none; }
}
@media (max-width: 768px) and (min-width: 431px) {
  .stats { grid-template-columns: repeat(2, minmax(0,1fr)); border-bottom: 1px solid var(--hair); }
  .stats .stat:nth-child(2n) { border-right: none; }
}
@media (max-width: 430px) {
  .stats { grid-template-columns: minmax(0,1fr); }
  .stats .stat { border-right: none; }
}

/* ─────────── the two drawers under the wall ─────────── */
/* the live site drove these off a button, aria-expanded and a grid-rows
   transition in site.js. Native <details> is the same interaction with no
   script at all, so the breakdown is open-able with JS off. */
.drawers { display: grid; gap: 0; }
.drawer { border-bottom: 1px solid var(--hair); }
.drawer > summary { list-style: none; cursor: pointer; display: flex; align-items: center;
       justify-content: space-between; gap: 14px; padding: 15px 0; min-height: 48px;
       font-family: var(--label); text-transform: uppercase; font-weight: 700; font-size: 19px;
       letter-spacing: 0.02em; color: var(--ink); max-width: 78ch; }
.drawer > summary::-webkit-details-marker { display: none; }
.drawer > summary:hover { color: var(--ox); }
.drawer > summary .i { color: var(--ox); font-size: 20px; transition: transform 240ms var(--ease-out); }
.drawer[open] > summary .i { transform: rotate(180deg); }
.drawer .d-body { padding: 2px 0 20px; max-width: 74ch; }
.drawer .d-lead { font-family: var(--code); font-size: 11px; letter-spacing: 0.07em;
       text-transform: uppercase; color: var(--meta); margin-bottom: 10px; }
.drawer .sd-item { display: flex; justify-content: space-between; align-items: baseline;
       gap: 18px; padding: 10px 0; border-top: 1px solid var(--hair); font-size: 15.5px; }
.drawer .sd-item b { color: var(--ink); font-weight: 600; }
.drawer .sd-item span:last-child { font-family: var(--code); font-size: 11.5px; color: var(--meta);
       text-align: right; letter-spacing: 0.03em; line-height: 1.7; }
.drawer p { font-size: 15.5px; color: var(--body); }
.drawer p b { color: var(--ink); }
@media (max-width: 560px) {
  .drawer .sd-item { flex-direction: column; gap: 4px; }
  .drawer .sd-item span:last-child { text-align: left; }
}

/* ─────────── coverage map: family summary and the two strands ─────────── */
.type-summary { display: flex; flex-wrap: wrap; border: 1px solid var(--hair-2);
       background: var(--surface); margin: clamp(22px,3vw,30px) 0 18px; }
.ts-item { flex: 1 1 128px; padding: 14px 16px; border-right: 1px solid var(--hair); }
.ts-item:last-child { border-right: none; }
.ts-item .n { display: block; font-family: var(--display); font-size: 27px; line-height: 1;
       color: var(--ink); letter-spacing: 0.014em; font-variant-numeric: tabular-nums; }
.ts-item .t { display: flex; align-items: center; gap: 6px; margin-top: 5px;
       font-family: var(--code); font-size: 10.5px; text-transform: uppercase;
       letter-spacing: 0.05em; color: var(--meta); line-height: 1.5; }
.tdot { width: 10px; height: 10px; border-radius: 50%; flex: none; background: var(--stone); }
/* the seven APM families. The live site carried these as hexes in
   coverage.json and set them inline, four of them from the retired palette.
   They are classes now, so the palette lives here with everything else.
   Every mark clears 3:1 on the white ground. */
.tdot.ty-a2a      { background: var(--ox); }
.tdot.ty-wallet   { background: var(--slate-blue); }
.tdot.ty-bnpl     { background: var(--ox-bright); }
.tdot.ty-evoucher { background: var(--ochre); }
.tdot.ty-dd       { background: var(--stone); }
.tdot.ty-lcs      { background: var(--ink); }
.tdot.ty-scheme   { background: var(--meta); }

/* The two strands and the section lede run the FULL width of the wrap. They
   were capped at 88ch and 52ch respectively, which stopped both well short of
   the rule above them on a desktop and read as clipped rather than composed.
   The type steps up a little as the measure grows so a longer line still reads
   as deliberate, and everything reflows normally as the screen narrows. */
.strand { font-size: clamp(15px, 0.34vw + 12.5px, 17.5px); color: var(--body);
         max-width: none; margin: 0 0 12px; line-height: 1.6; }
#coverage .rule-head .lede { max-width: none;
         font-size: clamp(16px, 0.42vw + 12.5px, 19.5px); line-height: 1.55; }

/* THE STAT WALL'S COLUMNS ARE NOT ALL THE SAME WIDTH, because their contents
   are not. "BILLIONS" is eight characters of Anton at 72px and needs roughly
   half again what ">$35M" or "M&A" needs, and on equal columns it ran straight
   into the M&A tile beside it. The extra room is taken from the two tiles whose
   figures are shortest. Below 1000px this drops away and the shared auto-fit
   rule takes over, because at that width the wall is already wrapping. */
@media (min-width: 1000px) {
  .stats { grid-template-columns: 0.94fr 0.8fr 1.02fr 1.42fr 0.82fr; }
}
.strand b { color: var(--ink); font-weight: 700; }

/* ─────────── map shell ─────────── */
.map-shell { border: var(--frame) solid var(--ink); background: var(--surface);
       margin-top: clamp(18px,2.4vw,26px); }
.map-topbar { display: flex; justify-content: space-between; align-items: center; gap: 14px;
       flex-wrap: wrap; padding: 12px 18px; border-bottom: 1px solid var(--hair); }
.crumbs { display: flex; align-items: center; gap: 8px; font-family: var(--code);
       font-size: 11.5px; letter-spacing: 0.05em; text-transform: uppercase; }
.crumbs button { font: inherit; background: none; border: none; padding: 2px; cursor: pointer;
       color: var(--ox); font-weight: 700; min-height: 32px; border-bottom: 1.5px solid transparent;
       transition: border-color 160ms var(--ease-out); }
@media (hover: hover) and (pointer: fine) { .crumbs button:hover { border-bottom-color: var(--ox); } }
.crumbs .cur { color: var(--ink); font-weight: 700; }
.crumbs .sep { color: var(--meta); }
/* the top bar carries the zoom group as well as the key, so they travel
   together when the bar wraps rather than splitting across two lines */
.map-tools { display: flex; align-items: center; gap: clamp(12px,1.8vw,22px); flex-wrap: wrap; }

/* ─────────── the zoom group ─────────── */
/* Vishwanath's review: the map could only be magnified by pinching, so a
   trackpad or a keyboard had no way in. Three real buttons, so they are in the
   tab order without a tabindex and answer Enter and Space without a handler.
   Every glyph is a sprite symbol (#i-zi, #i-zo, #i-rs); a text "+" and "-" is
   not available, U+2212 being absent from Barlow Condensed and JetBrains Mono.
   44px targets, matching .backbtn and the panel list. */
.zoomer { display: flex; align-items: stretch; flex: none; background: var(--bg);
       border: 1px solid var(--hair-2); }
.zbtn { display: inline-flex; align-items: center; justify-content: center; gap: 7px;
       min-width: 44px; min-height: 44px; padding: 0 10px; cursor: pointer; background: none;
       border: none; border-left: 1px solid var(--hair-2); color: var(--ink);
       font-family: var(--code); font-size: 10.5px; font-weight: 700; letter-spacing: 0.07em;
       text-transform: uppercase;
       transition: background 160ms var(--ease-out), color 160ms var(--ease-out); }
.zbtn:first-child { border-left: none; }
.zbtn .i { font-size: 18px; }
.zbtn.wide { padding: 0 13px; }
.zbtn.wide .i { font-size: 14px; }
@media (hover: hover) and (pointer: fine) {
  .zbtn:not(.is-off):hover { background: var(--ink); color: var(--surface); }
}
/* At a stop the button keeps its box and its place in the tab order: it is
   aria-disabled, not disabled, so the group never changes shape under a keyboard
   user mid-interaction. The quietened word is --meta (5.2:1 on --bg, so the
   RESET label still clears 4.5:1 even switched off) and only the GLYPH drops to
   --stone, which is the token's sanctioned icon use. --hair-2 is a hairline
   token and carries no text anywhere on this page. */
.zbtn.is-off { color: var(--meta); cursor: default; }
.zbtn.is-off .i { color: var(--stone); }

.map-key { display: flex; gap: 16px; flex-wrap: wrap; font-family: var(--code);
       font-size: 10.5px; letter-spacing: 0.04em; color: var(--meta); }
.map-key span { display: flex; align-items: center; gap: 6px; }
.kd { width: 11px; height: 11px; flex: none; }
.kd.delivery  { background: var(--ox); }
.kd.expertise { background: var(--slate-blue); }
.kd.regional  { background: var(--ox-on-dark); }

.map-grid { display: grid; grid-template-columns: minmax(0,1fr) 292px; align-items: stretch; }
@media (max-width: 860px) { .map-grid { grid-template-columns: minmax(0,1fr); } }
.map-stage { position: relative; overflow: hidden;
       background: radial-gradient(ellipse 85% 75% at 50% 38%, var(--surface) 0%, var(--sunk) 100%); }
svg.map { display: block; width: 100%; height: auto; position: relative; z-index: 2; }
/* above 860px the panel sits beside the map rather than under it, so the stage
   gets a taller floor and the SVG fills it. preserveAspectRatio defaults to
   "meet", so this still scales uniformly. Must follow the base rule above for
   the height override to win the cascade. */
@media (min-width: 861px) {
  .map-stage { min-height: 560px; }
  svg.map { height: 100%; }
}
.ocean-dots { position: absolute; inset: 0; opacity: 0.5; z-index: 1; pointer-events: none; }

.land { fill: var(--sunk); stroke: var(--surface); stroke-width: 0.7px; }
/* transform only: a land mass whose animation never runs is still drawn */
.land-reveal { animation: landRise 640ms var(--ease-out) both; }
@keyframes landRise { from { transform: translateY(1.6px); } to { transform: none; } }

.mk { stroke: var(--surface); stroke-width: 0.7px; cursor: pointer; transform-box: fill-box;
       transform-origin: center; transition: fill 220ms var(--ease-out), filter 220ms var(--ease-out); }
.mk.delivery  { fill: var(--ox); }
.mk.expertise { fill: var(--slate-blue); }
.mk.regional  { fill: var(--ox-on-dark); }
@media (hover: hover) and (pointer: fine) {
  .mk:hover { fill: var(--ox-bright);
       filter: drop-shadow(0 0 5px rgba(168,60,38,0.6)) drop-shadow(0 0 1px rgba(168,60,38,0.9)); }
}
.mk.sel { fill: var(--ink); }
.mk:focus { outline: none; }
.mk:focus-visible { outline: none; stroke: var(--ochre); stroke-width: 2px; }
.small-pt { fill: var(--slate-blue); stroke: var(--surface); stroke-width: 0.8px; pointer-events: none; }
.small-pt-hit { fill: transparent; cursor: pointer; }
.small-pt-hit:focus { outline: none; }
.small-pt-hit:focus-visible { outline: none; stroke: var(--ochre); stroke-width: 2px;
       fill: rgba(176,117,42,0.10); }
@media (hover: hover) and (pointer: fine) {
  .small-pt-hit:hover, .small-pt-hit:hover ~ .small-pt { fill: rgba(138,46,29,0.14); }
}
/* Country names. The type size is set in coverage-map.js from the stage's
   measured width, so a name is the same apparent size at every zoom level and
   every screen width; it was pinned to a 950px stage before, which put it at
   4.2 CSS px on a phone. The halo is em-relative for the same reason: a fixed
   0.4px stroke was a heavy outline on a region zoom and invisible at world
   level, and the halo is what keeps a name legible where it crosses an oxblood
   or ink-filled market. */
.map-label { font-family: var(--code); text-transform: uppercase; letter-spacing: 0.05em;
       fill: var(--ink); pointer-events: none; text-anchor: middle;
       paint-order: stroke; stroke: var(--bg); stroke-width: 0.16em;
       stroke-linejoin: round; }
/* the selected country's outline. Static: the site has exactly one pulsing
   element, the header brand dot. */
.contour { fill: none; stroke: var(--ox-bright); stroke-width: 2.6px; pointer-events: none;
       stroke-linejoin: round; stroke-linecap: round; }
/* one-shot ripple at the point of contact when a market is clicked */
.click-ripple { fill: none; stroke: var(--ox); stroke-width: 2; opacity: 0.7; transform-box: fill-box;
       transform-origin: center; animation: clickRipple 620ms var(--ease-out) forwards;
       pointer-events: none; }
@keyframes clickRipple { from { opacity: 0.7; transform: scale(0.2); } to { opacity: 0; transform: scale(3.2); } }

.zoom-hint { position: absolute; left: 14px; bottom: 12px; z-index: 3; padding: 5px 9px;
       font-family: var(--code); font-size: 10.5px; letter-spacing: 0.04em; color: var(--meta);
       background: rgba(244,242,241,0.9); }
.backbtn { position: absolute; top: 12px; left: 14px; z-index: 3; display: none; align-items: center;
       gap: 7px; min-height: 44px; padding: 8px 13px; cursor: pointer; color: var(--ink);
       background: var(--bg); border: 1px solid var(--hair-2); font-family: var(--code);
       font-size: 11px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
       transition: background 160ms ease, color 160ms ease, border-color 160ms ease; }
.backbtn .i { transform: scaleX(-1); }
@media (hover: hover) and (pointer: fine) {
  .backbtn:hover { background: var(--ink); color: var(--surface); border-color: var(--ink); }
}
/* cursor-following tooltip: the market name before the reader commits to a click */
.map-tip { position: absolute; z-index: 5; pointer-events: none; white-space: nowrap;
       background: var(--ink); color: var(--bg); font-family: var(--code); font-size: 11px;
       letter-spacing: 0.03em; padding: 5px 9px; opacity: 0;
       transform: translate(-50%, calc(-100% - 10px)) scale(0.96);
       transition: opacity 140ms ease, transform 140ms ease; }
.map-tip.show { opacity: 1; transform: translate(-50%, calc(-100% - 10px)) scale(1); }
.map-tip::after { content: ''; position: absolute; left: 50%; top: 100%; transform: translateX(-50%);
       border: 5px solid transparent; border-top-color: var(--ink); }

/* ─────────── the panel beside the map ─────────── */
.map-panel { border-left: 1px solid var(--hair); padding: 20px; min-height: 420px;
       display: flex; flex-direction: column; position: relative; overflow: hidden; }
@media (max-width: 860px) {
  .map-panel { border-left: none; border-top: 1px solid var(--hair); min-height: 0; }
}
/* transform only, so panel content is readable even if the animation is lost */
.panel-inner { display: flex; flex-direction: column; flex: 1;
       animation: panelIn 320ms var(--ease-out) both; }
@keyframes panelIn { from { transform: translateY(6px); } to { transform: none; } }
.p-kicker { font-family: var(--code); font-size: 10px; font-weight: 700; letter-spacing: 0.11em;
       text-transform: uppercase; color: var(--ox); margin-bottom: 7px; }
.p-title { font-family: var(--label); text-transform: uppercase; font-weight: 700; font-size: 25px;
       line-height: 1.04; color: var(--ink); letter-spacing: 0.012em; margin: 0; }
.p-role { font-family: var(--code); font-size: 10.5px; text-transform: uppercase;
       letter-spacing: 0.05em; color: var(--meta); margin: 6px 0 12px; line-height: 1.6; }
.p-note { font-size: 14.5px; color: var(--body); line-height: 1.6; margin: 0 0 14px; }
.p-note b { color: var(--ink); font-weight: 700; }
.apm-chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 2px 0 14px; }
.apm { display: inline-flex; flex-wrap: wrap; align-items: center; max-width: 100%; gap: 8px;
       padding: 6px 11px 6px 7px; font-size: 13px; background: var(--surface);
       border: 1px solid var(--hair-2); transform: translateY(4px);
       transition: border-color 160ms ease, transform 260ms var(--ease-out); }
.apm.in { transform: none; }
.apm .mono { width: 22px; height: 22px; border-radius: 3px; flex: none; display: inline-flex;
       align-items: center; justify-content: center; background: var(--ink); color: var(--surface);
       font-size: 9px; font-weight: 700; letter-spacing: 0.04em; }
/* ─────────── the scheme marks ─────────── */
/* Vishwanath's review: the marks rendered at wildly inconsistent sizes, and he
   wants them large and one family. They were a flat height:20px + width:auto on
   each file's DECLARED box, which is why mada.svg (its mark fills 29% of its
   file's height) and oxxo.svg (18%) came out at a third of the size of a tight
   file like wero.svg next to them, and why the max-width:74px cap silently
   letterboxed the wider wordmarks smaller still.
   Every mark is now normalised to equal optical AREA on its MEASURED ink and
   cropped to that ink, landing 22 to 38px tall. coverage-map.js computes the
   slot and the image geometry per file and writes them inline: those numbers are
   per-file measurements rather than design values, and there is nowhere else
   they could live. The slot keeps its own --surface ground, so a brand mark is
   never tinted by the chip. */
.apm .logo { position: relative; display: block; flex: none; overflow: hidden;
       background: var(--surface); }
/* max-width:none overrides the global img cap, which would otherwise fight the
   computed geometry on the wide wordmarks */
.apm .logo img { position: absolute; display: block; max-width: none; }
.apm .ty { font-family: var(--code); font-size: 9.5px; text-transform: uppercase;
       letter-spacing: 0.04em; color: var(--meta); border-left: 1px solid var(--hair);
       padding-left: 8px; margin-left: 2px; }
.mlist { list-style: none; margin: 0; padding: 0; }
.mlist li { border-bottom: 1px solid var(--hair); }
.mlist button { width: 100%; min-height: 44px; display: flex; align-items: center;
       justify-content: space-between; gap: 10px; padding: 10px 4px; cursor: pointer;
       background: none; border: none; font: inherit; color: inherit; text-align: left;
       transition: background 160ms ease; }
@media (hover: hover) and (pointer: fine) { .mlist button:hover { background: var(--ox-pale); } }
.mlist .nm { font-weight: 600; font-size: 15px; color: var(--ink); }
.mlist .ct { display: inline-flex; align-items: center; gap: 7px; font-family: var(--code);
       font-size: 10px; letter-spacing: 0.04em; color: var(--meta); white-space: nowrap; }
.mlist .ct .i { color: var(--ox); font-size: 13px; }
.p-foot { margin-top: auto; padding-top: 14px; border-top: 1px solid var(--hair);
       font-size: 12.5px; color: var(--meta); line-height: 1.55; }

/* ─────────── the narrative strip under the map ─────────── */
.map-narrative { display: grid; grid-template-columns: 1fr 1fr; gap: 24px;
       padding: 18px clamp(16px,2.2vw,22px); border-top: 1px solid var(--hair); background: var(--sunk); }
@media (max-width: 860px) { .map-narrative { grid-template-columns: 1fr; gap: 16px; } }
.mn h4 { font-family: var(--label); text-transform: uppercase; font-weight: 700; font-size: 17px;
       letter-spacing: 0.02em; color: var(--ink); margin: 0 0 5px; }
.mn p { font-size: 14px; color: var(--body); line-height: 1.6; margin: 0; }
@media (max-width: 480px) {
  .map-topbar { padding: 10px 14px; }
  /* the key repeats what the panel copy says at this width */
  .map-key { display: none; }
}

/* progressive enhancement: with JS off no geometry is fetched, so the SVG
   stays empty. Hide the blank stage and its controls, show the notice, and
   leave every word of the panel, the family counts and the narrative in
   place. Nothing on this page is hidden by the absence of JS except the
   interactive layer itself. */
.map-noscript { display: none; padding: 34px 24px; text-align: center; color: var(--body);
       font-size: 14.5px; }
html:not(.js) svg.map, html:not(.js) .zoom-hint,
html:not(.js) .backbtn, html:not(.js) .map-tip,
/* a zoom control with no map to zoom is worse than no control at all */
html:not(.js) .zoomer { display: none; }
html:not(.js) .map-noscript { display: block; }
/* the stage carries one line of notice rather than a map, so it does not need
   the tall floor the interactive version does */
html:not(.js) .map-stage { min-height: 0; }
/* a <noscript> is a real element once scripting is off, and it would otherwise
   hold the seven family counts in a single narrow column inside the flex row */
.type-summary > noscript { display: flex; flex-wrap: wrap; width: 100%; }

/* ─────────── institution and company monograms ─────────── */
/* Vishwanath's review asked for iconography on Education and on the career
   journey. THERE IS NO LICENSED LOGO FILE FOR ANY OF THESE ORGANISATIONS and
   none was fetched, so these are designed monograms in the page's own faces and
   not an approximation of anybody's mark. See the MONO_CO comment in
   build/page_experience.py for the licence position and the initials rule.
   One family: one box, one radius, one ground, one type size per letter count,
   aligned down the left of every row in both sections. The chips carry no
   chroma at all, so a chip cannot pull the eye off the oxblood; --body on
   --sunk is 10.1:1, measured, not assumed.

   A REAL LOGO FILE DROPS STRAIGHT IN WITHOUT TOUCHING LAYOUT. The box is what
   is sized, never its contents: add "has-img" to the chip and put an <img>
   inside in place of the <span class="mg">. The two rules below already size,
   pad and centre it in exactly the same box, on --surface instead of --sunk. */
.org-chip { flex: none; display: inline-flex; align-items: center; justify-content: center;
       width: 40px; height: 40px; border-radius: 6px; background: var(--sunk);
       border: 1px solid var(--hair-2); overflow: hidden; }
.org-chip .mg { font-family: var(--label); font-weight: 700; font-size: 17px; line-height: 1;
       letter-spacing: 0.02em; text-transform: uppercase; color: var(--body); }
.org-chip.n1 .mg { font-size: 23px; }
.org-chip.n3 .mg { font-size: 14px; }
/* A real mark is height-banded with a width cap instead of being squeezed into
   the monogram's square: a 5:1 wordmark and a 1:1 crest cannot share a square and
   both stay legible. object-fit does the letterboxing. */
.org-chip.has-img { background: var(--surface); padding: 4px 7px; width: auto;
       min-width: 40px; max-width: 118px; }
.org-chip.has-img img { display: block; width: auto; height: auto;
       max-width: 100%; max-height: 32px; object-fit: contain; }
@media (max-width: 480px) {
  .org-chip { width: 34px; height: 34px; border-radius: 5px; }
  .org-chip.has-img { width: auto; min-width: 34px; max-width: 96px; padding: 3px 6px; }
  .org-chip.has-img img { max-height: 26px; }
  .edu.deflist dd .org-chip,
  .edu.deflist dd .org-chip.has-img { width: 66px; max-width: 66px; }
  .edu.deflist dd { gap: 10px; }
  .org-chip .mg { font-size: 15px; }
  .org-chip.n1 .mg { font-size: 20px; }
  .org-chip.n3 .mg { font-size: 12.5px; }
}

/* ─────────── career journey ─────────── */
.roles { border-top: 2px solid var(--ink); }
/* the first column carries the chip beside the company name now, so it takes
   the chip's width and gutter on top of what it held before */
.role { display: grid; grid-template-columns: 232px minmax(0,1fr); gap: clamp(18px,2.6vw,36px);
       padding: 26px 0; border-bottom: 1px solid var(--hair); }
.role .r-when { position: relative; padding-left: 22px; display: flex;
       flex-direction: column; align-items: flex-start; gap: 10px; }
.role .r-who { min-width: 0; }
.role .r-when .dot { position: absolute; left: 0; top: 7px; width: 11px; height: 11px;
       border-radius: 50%; background: var(--ox); }
.role .company { display: block; font-family: var(--label); text-transform: uppercase;
       font-weight: 700; font-size: 21px; line-height: 1.05; color: var(--ink); letter-spacing: 0.012em; }
.role .dates { display: block; font-family: var(--code); font-size: 11px; letter-spacing: 0.07em;
       color: var(--meta); margin-top: 7px; line-height: 1.7; }
.role .note { display: block; font-size: 13.5px; color: var(--meta); margin-top: 8px; line-height: 1.5; }
.role h3 { font-family: var(--label); text-transform: uppercase; font-weight: 700; font-size: 25px;
       line-height: 1.05; color: var(--ink); letter-spacing: 0.012em; }
.role .r-stat { display: block; font-family: var(--display); font-size: clamp(24px,2.6vw,31px);
       line-height: 1.05; color: var(--ox); letter-spacing: 0.014em; margin: 11px 0 4px;
       font-variant-numeric: tabular-nums; }
.role ul { list-style: none; padding-left: 0; margin-top: 10px; }
.role li { position: relative; padding-left: 20px; margin-top: 0.5em; font-size: 15.5px;
       color: var(--body); line-height: 1.5; }
.role li::before { content: ''; position: absolute; left: 2px; top: 0.6em; width: 6px; height: 6px;
       border-radius: 50%; background: var(--hair-2); }
@media (max-width: 760px) {
  .role { grid-template-columns: minmax(0,1fr); gap: 12px; }
  .role h3 { font-size: 23px; }
}

/* ─────────── education, awards, languages ─────────── */
.edu.deflist dt { font-family: var(--code); font-size: 12px; font-weight: 700; letter-spacing: 0.06em;
       text-transform: uppercase; color: var(--meta); padding-top: 3px; }
/* the chip sits at the left of the row, in the same family and the same box as
   the career chips */
.edu.deflist dd { display: flex; align-items: flex-start; gap: 14px; }
/* the logo slot is a fixed width and the mark centres inside it, so six logos of
   six different aspect ratios still leave the school names on one left edge.
   Without this the titles step in and out by up to 60px down the list. */
.edu.deflist dd .org-chip,
.edu.deflist dd .org-chip.has-img { flex: none; width: 96px; max-width: 96px; }
.edu.deflist dd .edu-txt { display: block; min-width: 0; }
.edu.deflist dd .inst { display: block; font-family: var(--label); text-transform: uppercase;
       font-weight: 700; font-size: 21px; line-height: 1.08; color: var(--ink); letter-spacing: 0.012em; }
.edu.deflist dd .detail { display: block; color: var(--body); font-size: 15.5px; margin-top: 4px;
       line-height: 1.5; }
/* four awards, so the column count steps 4 / 2 / 1 and a row is never part
   filled. The cell that ends a row drops its right border. */
.awards { display: grid; grid-template-columns: repeat(4, minmax(0,1fr)); gap: 0;
       border-top: 1px solid var(--hair); margin-top: 14px; }
.awards .aw { padding: 15px 18px 15px 0; border-bottom: 1px solid var(--hair);
       border-right: 1px solid var(--hair); }
.awards .aw:nth-child(4n) { border-right: none; }
@media (max-width: 900px) {
  .awards { grid-template-columns: repeat(2, minmax(0,1fr)); }
  .awards .aw:nth-child(2n) { border-right: none; }
}
@media (max-width: 460px) {
  .awards { grid-template-columns: minmax(0,1fr); }
  .awards .aw { border-right: none; }
}
.awards .aw b { display: block; font-family: var(--label); text-transform: uppercase;
       font-weight: 700; font-size: 20px; line-height: 1.05; color: var(--ink); letter-spacing: 0.012em; }
.awards .aw span { display: block; font-family: var(--code); font-size: 10.5px; letter-spacing: 0.07em;
       text-transform: uppercase; color: var(--meta); margin-top: 6px; }
.langs { display: flex; gap: clamp(26px,5vw,56px); flex-wrap: wrap; margin-top: 14px; }
.langs .l-name { font-family: var(--label); text-transform: uppercase; font-weight: 700;
       font-size: 20px; line-height: 1.05; color: var(--ink); letter-spacing: 0.012em; }
.langs .l-level { font-family: var(--code); font-size: 10.5px; letter-spacing: 0.07em;
       text-transform: uppercase; color: var(--meta); margin-top: 5px; }
.cv-sub-lbl { margin-top: clamp(30px,4vw,44px); display: inline-flex; }

/* ─────────── reduced motion: everything renders finished ─────────── */
@media (prefers-reduced-motion: reduce) {
  .land-reveal, .panel-inner, .apm, .click-ripple { animation: none !important; transform: none !important; }
  .apm { transition: none; }
  .drawer > summary .i { transition: none; }
  /* the zoom buttons still work: coverage-map.js snaps the viewBox instead of
     easing it under reduced motion, and only the hover tint is dropped here */
  .zbtn { transition: none; }
}
