:root {
  --bg: #fff;
  --fg: #0a0a0a;
  --muted: #6b6b6b;
  --faint: #a1a1a1;
  --line: #ededed;
  --hover: #f4f4f4;
  --img-edge: rgb(0 0 0 / 0.06);
  --measure: 680px;
  --sans: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
  --ink: #262626;
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
}
@media (prefers-color-scheme: dark) {
  :root { --bg: #0a0a0a; --fg: #ededed; --muted: #8f8f8f; --faint: #5c5c5c; --line: #1f1f1f; --hover: #161616; --img-edge: rgb(255 255 255 / 0.08); --ink: #d6d6d6; }
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font: 400 16px/1.65 var(--sans);
  font-optical-sizing: auto;
  letter-spacing: -0.011em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}
img { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; -webkit-tap-highlight-color: transparent; }
p { text-wrap: pretty; }
h1, h2 { text-wrap: balance; }
::selection { background: var(--fg); color: var(--bg); }
:focus-visible { outline: 2px solid var(--fg); outline-offset: 3px; border-radius: 6px; }

.wrap { max-width: var(--measure); margin: 0 auto; padding: 0 24px; }

/* Top bar */
.bar { padding: 24px 0 0; view-transition-name: bar; }
.bar .wrap { display: flex; align-items: center; justify-content: space-between; gap: 16px 24px; flex-wrap: wrap; }
.brand { display: flex; align-items: center; gap: 10px; font-weight: 500; letter-spacing: -0.015em; }
.brand img { width: 30px; height: 30px; border-radius: 8px; object-fit: cover; }

nav { display: flex; gap: 2px; margin-left: auto; }
nav a {
  position: relative;
  isolation: isolate;
  padding: 5px 12px;
  border-radius: 999px;
  font-size: 14.5px;
  color: var(--muted);
  transition: color 200ms ease, background-color 200ms ease, transform 160ms var(--ease-out);
}
nav a:active { transform: scale(0.97); }
nav a[aria-current] { color: var(--bg); }
/* The active pill is its own element so it can glide between tabs on page change */
nav .pill { position: absolute; inset: 0; z-index: -1; border-radius: inherit; background: var(--fg); }
/* Shared between the homepage hero and the top bar, so About <-> other pages morph instead of jumping */
nav { view-transition-name: nav; }
nav .pill { view-transition-name: pill; }
.avatar, .brand img { view-transition-name: avatar; }

/* XP mode: a quiet grey flag at rest that picks up its colours on hover */
.xp { display: inline-flex; align-items: center; gap: 7px; color: var(--muted); transition: color 200ms ease, background-color 200ms ease, border-color 200ms ease, transform 160ms var(--ease-out); }
.xp:active { transform: scale(0.96); }
.flag { width: 16px; height: 16px; flex-shrink: 0; overflow: visible; }
.flag g { transform-origin: 50% 50%; transition: transform 450ms var(--ease-out); }
.flag path { fill: currentColor; transition: fill 300ms ease; }
.icons a.xp-hero { display: inline-flex; width: auto; height: 36px; margin-left: 10px; padding: 0 13px 0 11px; border: 1px solid var(--line); border-radius: 999px; font-size: 14px; letter-spacing: -0.01em; }
.xp-bar { display: grid; place-items: center; width: 32px; height: 32px; margin-right: -8px; border-radius: 9px; }
.xp-bar .flag { width: 17px; height: 17px; }
.xp-foot { gap: 6px; color: inherit; }
.xp-foot .flag { width: 13px; height: 13px; }

/* Page */
main { padding: 72px 0 104px; view-transition-name: page; }
main nav { margin: 0 0 48px -12px; width: fit-content; justify-content: flex-start; flex-wrap: wrap; }
.hero { margin-bottom: 44px; }
.avatar { width: 80px; height: 80px; border-radius: 20px; object-fit: cover; object-position: 50% 20%; margin-bottom: 28px; }
h1 { font-size: 30px; line-height: 1.15; font-weight: 600; letter-spacing: -0.028em; margin: 0 0 12px; }
.sub { color: var(--muted); font-size: 18.5px; line-height: 1.5; letter-spacing: -0.012em; margin: 0; max-width: 32em; }
.icons { display: flex; gap: 6px; margin: 22px 0 0 -8px; }
.icons a {
  display: grid; place-items: center; width: 36px; height: 36px; border-radius: 10px;
  color: var(--muted);
  transition: color 200ms ease, background-color 200ms ease, transform 160ms var(--ease-out);
}
.icons a:active { transform: scale(0.94); }
.icons svg { width: 18px; height: 18px; }
.row svg { width: 20px; height: 20px; }

.page-head { margin-bottom: 40px; }
.page-head p { color: var(--muted); margin: 0; font-size: 17.5px; letter-spacing: -0.01em; max-width: 32em; }

.prose p { margin: 0 0 20px; }
.prose p:last-child { margin-bottom: 0; }
.prose a, .link {
  text-decoration: underline; text-decoration-thickness: 1px; text-decoration-color: var(--faint); text-underline-offset: 4px;
  transition: text-decoration-color 200ms ease;
}

/* Rows */
.rows { list-style: none; margin: 0; padding: 0; }
.row { display: flex; align-items: baseline; justify-content: space-between; gap: 8px 24px; padding: 18px 0; border-top: 1px solid var(--line); }
.rows li:last-child .row { border-bottom: 1px solid var(--line); }
a.row { transition: opacity 250ms ease; }
.row .main { min-width: 0; }
.row .t { font-weight: 500; letter-spacing: -0.012em; display: block; text-wrap: balance; }
.row .d { color: var(--muted); font-size: 15px; display: block; margin-top: 3px; text-wrap: pretty; }
.row .k { display: block; margin-bottom: 3px; color: var(--faint); font-size: 11.5px; font-weight: 500; text-transform: uppercase; letter-spacing: .06em; }
.row .m { color: var(--muted); font-size: 14px; white-space: nowrap; flex-shrink: 0; text-align: right; font-variant-numeric: tabular-nums; }
.row .m small { display: block; color: var(--faint); font-size: 13px; margin-top: 2px; }
.row .ext { display: inline-block; color: var(--faint); margin-left: 5px; transition: transform 250ms var(--ease-out), color 200ms ease; }
.row.icon { align-items: center; justify-content: flex-start; gap: 16px; }
.row.icon .m { margin-left: auto; }

/* Press: the outlet's wordmark sits where the small label was, drawn as a mask so it takes the theme's grey */
.pmark {
  display: block; margin-bottom: 10px; background-color: var(--muted);
  -webkit-mask: var(--src) left center / contain no-repeat; mask: var(--src) left center / contain no-repeat;
  transition: background-color 200ms ease;
}

/* Builds & Press: logo tile | text | meta. Logos rest in greyscale and pick up colour on hover */
.row.lrow { display: grid; grid-template-columns: 40px minmax(0, 1fr) auto; column-gap: 16px; align-items: center; }
.row.lrow.build { align-items: start; }
.lrow .logo {
  display: grid; place-items: center; width: 40px; height: 40px; border-radius: 10px; overflow: hidden;
  background: #fff; outline: 1px solid var(--img-edge); outline-offset: -1px;
}
.lrow.build .logo { margin-top: 2px; }
.lrow .logo img { display: block; width: 100%; height: 100%; transition: filter 300ms ease, opacity 300ms ease; }
.logo.mono { background: var(--hover); color: var(--muted); font-size: 13px; font-weight: 600; letter-spacing: -0.01em; }

/* Talks: flag | title + talk | role badge. Mouse: gliding highlight + tilted photo card; touch: thumbnails */
.talks { position: relative; isolation: isolate; }
.row.talk {
  display: grid; grid-template-columns: 20px minmax(0, 1fr) auto; column-gap: 16px; align-items: center;
  transition: opacity 250ms ease; cursor: default;
}
.cflag {
  width: 20px; height: 14px; align-self: start; margin-top: 6px; border-radius: 3px; object-fit: cover;
  outline: 1px solid var(--img-edge); outline-offset: -1px;
}
.badge {
  display: inline-flex; align-items: center; gap: 6px; padding: 5px 10px 5px 8px;
  border: 1px solid var(--line); border-radius: 999px; background: transparent;
  font-size: 12.5px; line-height: 1; color: var(--muted); white-space: nowrap;
  transition: color 200ms ease, background-color 200ms ease, border-color 200ms ease, box-shadow 200ms ease;
}
.badge svg { width: 13px; height: 13px; flex-shrink: 0; }
.talk .thumb {
  grid-column: 3; grid-row: 1 / span 2; width: 76px; aspect-ratio: 4 / 3; height: auto; object-fit: cover;
  border-radius: 8px; outline: 1px solid var(--img-edge); outline-offset: -1px; background: var(--hover);
}
.thumb.tall { object-position: 50% 22%; }
.peek img.tall { object-position: 50% 30%; }

/* The highlight is one element that glides to whichever row is hovered */
.talks .hl {
  position: absolute; left: -14px; right: -14px; top: 0; height: 0; z-index: -1; pointer-events: none;
  border-radius: 12px; background: var(--hover); opacity: 0;
  transition: transform 340ms var(--ease-out), height 340ms var(--ease-out), opacity 200ms ease;
}
.talks .hl.on { opacity: 1; }

/* Hover photo: a tilted card that opens like an iris (inset clip + blur clearing) and exits quicker than it enters */
.peek {
  position: fixed; left: 0; top: 0; z-index: 50; pointer-events: none;
  border-radius: 14px; box-shadow: 0 1px 2px rgb(0 0 0 / .1), 0 24px 48px -16px rgb(0 0 0 / .45);
  opacity: 0; scale: .94; filter: blur(6px);
  transition: opacity 150ms ease, scale 200ms var(--ease-out), filter 150ms ease;
  will-change: transform;
}
.peek.on { opacity: 1; scale: 1; filter: blur(0); transition: opacity 220ms ease, scale 460ms var(--ease-out), filter 320ms ease; }
/* The frame takes each photo's shape (landscape or portrait) and morphs between them as you move down the list */
.peek .frame {
  position: relative; width: 288px; height: 216px; border-radius: 14px; overflow: hidden; background: #111;
  clip-path: inset(14% 10% round 14px);
  transition: clip-path 180ms var(--ease-out), width 480ms var(--ease-out), height 480ms var(--ease-out);
}
.peek .frame.tall { width: 228px; height: 304px; }
.peek.on .frame { clip-path: inset(0 round 14px); transition: clip-path 560ms var(--ease-out), width 480ms var(--ease-out), height 480ms var(--ease-out); }
.peek .frame img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

.note { margin-top: 56px; padding-top: 24px; border-top: 1px solid var(--line); color: var(--muted); }
.note strong { color: var(--fg); font-weight: 500; display: block; margin-bottom: 4px; }

/* Essay */
.back { display: inline-flex; gap: 6px; color: var(--muted); font-size: 14.5px; margin-bottom: 40px; transition: color 200ms ease; }
.back span { display: inline-block; transition: transform 250ms var(--ease-out); }
/* One clean sans throughout; hierarchy comes from size, weight and colour rather than a second typeface */
.essay h1 {
  font-size: clamp(30px, 5.5vw, 42px); line-height: 1.12; font-weight: 600;
  letter-spacing: -0.032em; margin-bottom: 16px;
}
.essay .meta { color: var(--muted); font-size: 14px; font-variant-numeric: tabular-nums; }
.essay .meta span { margin: 0 6px; color: var(--faint); }
.essay .body {
  margin-top: 44px; font-size: 17.5px; line-height: 1.78; letter-spacing: -0.012em;
  color: var(--ink);
}
.essay .body p { margin: 0 0 1.3em; }
.essay .body .lead { font-size: 21px; line-height: 1.5; letter-spacing: -0.018em; color: var(--fg); margin-bottom: 1.2em; }
.essay .body h2 {
  font-size: 20px; line-height: 1.35; font-weight: 600; letter-spacing: -0.022em;
  color: var(--fg); margin: 2.2em 0 .6em;
}
.essay .body ul { margin: 0 0 1.15em; padding-left: 1.2em; }
.essay .body li { margin-bottom: .4em; padding-left: .2em; }
.essay .body li::marker { color: var(--faint); }
.essay .body strong { font-weight: 600; color: var(--fg); }
.essay .body pre {
  margin: 0 0 1.3em; padding: 14px 18px; overflow-x: auto; border-radius: 10px;
  background: var(--hover); border: 1px solid var(--line);
  font: 14.5px/1.6 ui-monospace, "SF Mono", "Cascadia Code", Consolas, monospace; color: var(--fg); letter-spacing: 0;
}
.essay .body a {
  text-decoration: underline; text-decoration-thickness: 1px; text-decoration-color: var(--faint); text-underline-offset: 4px;
  transition: text-decoration-color 200ms ease;
}
.essay .end { margin: 56px 0 0; text-align: center; color: var(--faint); letter-spacing: .5em; font-size: 14px; }
.pager { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; margin-top: 48px; padding-top: 24px; border-top: 1px solid var(--line); }
.pager a { display: block; transition: opacity 250ms ease; }
.pager a:last-child { text-align: right; }
.pager small { display: block; color: var(--faint); font-size: 11.5px; font-weight: 500; text-transform: uppercase; letter-spacing: .06em; margin-bottom: 4px; }
.pager span { display: block; line-height: 1.4; font-weight: 500; letter-spacing: -0.014em; }

/* Reading progress: a hairline across the top that fills as you scroll (scroll-driven; hidden where unsupported) */
.progress { display: none; }
@supports (animation-timeline: scroll()) {
  .progress {
    display: block; position: fixed; inset: 0 0 auto; height: 2px; z-index: 60; background: var(--fg);
    transform-origin: 0 50%; transform: scaleX(0);
    animation: read linear both; animation-timeline: scroll(root);
  }
  @keyframes read { to { transform: scaleX(1); } }
}

/* Footer */
footer { padding: 0 0 40px; color: var(--faint); font-size: 13.5px; }
footer .wrap { display: flex; justify-content: space-between; gap: 16px; padding-top: 24px; border-top: 1px solid var(--line); margin-top: 0; }
footer a { transition: color 200ms ease; }

/* Hover only where a real pointer exists, so taps don't leave sticky states */
@media (hover: hover) and (pointer: fine) {
  nav a:not([aria-current]):hover { color: var(--fg); background: var(--hover); }
  .icons a:hover { color: var(--fg); background: var(--hover); }
  .prose a:hover, .link:hover, .essay .body a:hover { text-decoration-color: var(--fg); }
  .rows:has(a.row:hover) a.row:not(:hover) { opacity: .42; }
  .row.press:hover .pmark { background-color: var(--fg); }
  .lrow .logo img { filter: grayscale(1); opacity: .8; }
  .lrow:hover .logo img { filter: none; opacity: 1; }
  .talks:has(.talk:hover) .talk:not(:hover) { opacity: .55; }
  .talk .thumb { display: none; }
  .talk:hover .badge { color: var(--fg); background: var(--bg); border-color: transparent; box-shadow: 0 1px 2px rgb(0 0 0 / .08); }
  a.row:hover .ext { color: var(--fg); transform: translate(2px, -2px); }
  .back:hover { color: var(--fg); }
  .back:hover span { transform: translateX(-3px); }
  .pager:has(a:hover) a:not(:hover) { opacity: .42; }
  footer a:hover { color: var(--fg); }
  .xp:hover { color: var(--fg); }
  .xp-bar:hover, .icons a.xp-hero:hover { background: var(--hover); }
  .icons a.xp-hero:hover { border-color: transparent; }
  .xp:hover .flag g { transform: rotate(-8deg) scale(1.08); }
  .xp:hover .flag .r { fill: #f25022; }
  .xp:hover .flag .g { fill: #7fba00; }
  .xp:hover .flag .b { fill: #00a4ef; }
  .xp:hover .flag .y { fill: #ffb900; }
}
/* Touch: thumbnail on the right, role badge drops under the description */
@media (hover: none) {
  .row.talk { grid-template-columns: 20px minmax(0, 1fr) 76px; }
  .row.talk .badge { grid-column: 2; grid-row: 2; justify-self: start; margin-top: 10px; }
}
/* Touch screens get the coloured flag all the time, since there is no hover to reveal it */
@media (hover: none) {
  .flag .r { fill: #f25022; } .flag .g { fill: #7fba00; } .flag .b { fill: #00a4ef; } .flag .y { fill: #ffb900; }
}

/* Page-to-page transitions (cross-document view transitions) */
@view-transition { navigation: auto; }
::view-transition-group(root), ::view-transition-group(page), ::view-transition-group(bar) { animation-duration: 0s; }
::view-transition-old(root), ::view-transition-old(page) { animation: vt-out 140ms ease both; }
::view-transition-new(root) { animation: vt-in 260ms var(--ease-out) both; }
::view-transition-new(page) { animation: vt-rise 360ms var(--ease-out) 40ms both; }
/* The bar only exists on inner pages: fade it in/out when coming from or going to About */
::view-transition-new(bar):only-child { animation: vt-in 300ms var(--ease-out) 80ms both; }
::view-transition-old(bar):only-child { animation: vt-out 140ms ease both; }
/* Photo, nav and pill all travel on one curve so they read as a single movement */
::view-transition-group(avatar), ::view-transition-group(nav), ::view-transition-group(pill) {
  animation-duration: 460ms; animation-timing-function: cubic-bezier(0.65, 0, 0.2, 1);
}
/* Going to or from About the nav flies across the page, so hold the new content back until it has mostly landed */
:root:active-view-transition-type(hero)::view-transition-old(page) { animation-duration: 120ms; }
:root:active-view-transition-type(hero)::view-transition-new(page) { animation-delay: 260ms; animation-duration: 340ms; }
/* Same photo and same links on both sides, so the browser's default crossfade keeps them solid while they move */
::view-transition-old(avatar), ::view-transition-new(avatar) { height: 100%; }
/* The pill is a separate layer; keep the nav's labels painted above it so the active label stays readable */
::view-transition-group(pill) { z-index: 1; }
::view-transition-group(nav) { z-index: 2; }
::view-transition-old(pill), ::view-transition-new(pill) { height: 100%; animation: none; }
::view-transition-old(pill) { opacity: 0; }
@keyframes vt-out { to { opacity: 0; } }
@keyframes vt-in { from { opacity: 0; } }
@keyframes vt-rise { from { opacity: 0; transform: translateY(8px); filter: blur(2px); } }

/* First-load entrance; skipped when a view transition is already animating the page in */
@keyframes rise { from { opacity: 0; transform: translateY(8px); filter: blur(3px); } }
main .wrap > :not(.rows):not(script):not(.essay):not(.progress), .rows > li, .essay > * { animation: rise 520ms var(--ease-out) both; }
main .wrap > :nth-child(2) { animation-delay: 70ms; }
main .wrap > :nth-child(3) { animation-delay: 140ms; }
.rows > li:nth-child(1) { animation-delay: 80ms; }
.rows > li:nth-child(2) { animation-delay: 115ms; }
.rows > li:nth-child(3) { animation-delay: 150ms; }
.rows > li:nth-child(4) { animation-delay: 185ms; }
.rows > li:nth-child(5) { animation-delay: 220ms; }
.rows > li:nth-child(6) { animation-delay: 255ms; }
.rows > li:nth-child(7) { animation-delay: 290ms; }
.rows > li:nth-child(n+8) { animation-delay: 320ms; }
.essay > :nth-child(2) { animation-delay: 50ms; }
.essay > :nth-child(3) { animation-delay: 90ms; }
.essay > :nth-child(n+4) { animation-delay: 140ms; }
.vt main * { animation: none !important; }

@media (max-width: 560px) {
  .wrap { padding: 0 20px; }
  main { padding-top: 48px; }
  .bar .xp-bar { order: 1; margin-left: auto; }
  .bar nav { order: 2; }
  nav { margin-left: -9px; width: calc(100% + 18px); justify-content: space-between; }
  nav a { padding: 5px 9px; font-size: 14px; }
  main nav { margin-left: -9px; width: calc(100% + 18px); justify-content: space-between; flex-wrap: nowrap; }
  .brand { margin-bottom: 4px; }
  h1 { font-size: 28px; }
  .sub { font-size: 17.5px; }
  .row { flex-direction: column; gap: 4px; }
  .row.talk { gap: 0 14px; }
  .row.lrow { gap: 0 14px; }
  .row.lrow .m { grid-column: 2; margin-top: 8px; }
  .row .m { text-align: left; white-space: normal; }
  .row.icon { flex-direction: row; }
  .row.icon .m { margin-left: auto; }
  .essay .body { font-size: 17px; }
  .essay .body .lead { font-size: 19.5px; }
  .pager { grid-template-columns: 1fr; }
  .pager a:last-child { text-align: left; }
}

/* Reduced motion: keep fades, drop movement and blur */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  @keyframes rise { from { opacity: 0; } }
  @keyframes vt-rise { from { opacity: 0; } }
  ::view-transition-group(pill), ::view-transition-group(avatar), ::view-transition-group(nav) { animation-duration: 0s; }
  .row .ext, .back span, .flag g { transition: none; }
  nav a:active, .icons a:active, .xp:active { transform: none; }
  .xp:hover .flag g { transform: none; }
  .peek, .peek.on { scale: 1; filter: none; }
  .peek .frame, .peek.on .frame { clip-path: inset(0 round 14px); transition: none; }
  .talks .hl { transition: opacity 200ms ease; }
}
