/* artofandyxiao.com
   Palette sampled from the 2008–2024 site: the oxblood bars, the brick bevel on the nav,
   the orange email envelope and the silver content well. */

/* The two typefaces, self-hosted (assets/fonts, from Google Fonts; SIL Open Font License, texts beside them).
   Atkinson Hyperlegible Next is one variable font for both weights. Latin and Latin Extended only. */
@font-face {
  font-family: "Atkinson Hyperlegible Next";
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url("../fonts/atkinson-hyperlegible-next-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Atkinson Hyperlegible Next";
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url("../fonts/atkinson-hyperlegible-next-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Atkinson Hyperlegible Next";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/atkinson-hyperlegible-next-italic-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Atkinson Hyperlegible Next";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/atkinson-hyperlegible-next-italic-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Spectral SC";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("../fonts/spectral-sc-500-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Spectral SC";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("../fonts/spectral-sc-500-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  --oxblood: #511e1e;
  --brick: #a84040;
  --amber: #f2a024;
  --silver: #c8c8c8;
  --paper: #f8f8f7;
  --ink: #241616;

  --cream: #fff3c4;     /* nav and band text; the old site's #ffffcc links */
  --well: #e6e4e3;      /* the silver well, lightened for long reading */
  --ink-soft: #5a4646;

  --display: "Spectral SC", Georgia, serif;
  --text: "Atkinson Hyperlegible Next", Tahoma, Verdana, sans-serif;
  --mono: ui-monospace, "Cascadia Mono", Consolas, monospace;

  --wrap: 75rem;
  --gutter: clamp(1rem, 3.5vw, 2.5rem);
  --gap: clamp(0.75rem, 1.8vw, 1.25rem);
}

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

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 400 1.0625rem/1.6 var(--text);
  -webkit-font-smoothing: antialiased;
}

img, svg { display: block; max-width: 100%; height: auto; }

a { color: var(--oxblood); text-decoration-thickness: 1px; text-underline-offset: 0.2em; }
a:hover { color: var(--brick); }

:focus-visible { outline: 3px solid var(--brick); outline-offset: 3px; }
main:focus { outline: none; }

code { font: 0.9em/1 var(--mono); background: var(--well); padding: 0.15em 0.35em; }

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

.skip {
  position: absolute; left: var(--gutter); top: -4rem; z-index: 10;
  background: var(--oxblood); color: var(--cream); padding: 0.5rem 1rem;
}
.skip:focus { top: 0.5rem; }

.defs { position: absolute; width: 0; height: 0; overflow: hidden; }

/* ---- Header ---------------------------------------------------------------- */

.masthead {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: clamp(1.5rem, 4vw, 2.75rem) var(--gutter) 0.55rem;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.25rem 1.5rem;
}

.wordmark {
  font: 500 clamp(2.4rem, 6vw, 3.75rem)/1 var(--display);
  letter-spacing: 0.02em;
  color: var(--oxblood);
  text-decoration: none;
}
.wordmark:hover { color: var(--oxblood); }

.role {
  margin: 0;
  font: 500 clamp(1rem, 1.6vw, 1.2rem)/1.2 var(--display);
  letter-spacing: 0.09em;
}

.navband {
  background: var(--oxblood);
  border-top: 3px solid var(--brick);
}

.navband__inner {
  position: relative;
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 0 var(--gutter);
  display: flex;
  align-items: center;
}

.navband ul {
  display: flex;
  gap: clamp(1.25rem, 4vw, 2.75rem);
  margin: 0;
  padding: 0;
  list-style: none;
}

.navband ul a {
  display: block;
  padding: 0.55rem 0 0.5rem;
  color: var(--cream);
  font-weight: 600;
  font-size: 0.975rem;
  text-decoration: none;
}
.navband ul a:hover,
.navband ul a[aria-current="page"] {
  color: #fff;
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 0.4em;
}
.navband :focus-visible { outline-color: var(--cream); }

/* The envelope hangs off the band's right end, tilted, as it did in 2008. */
.mail {
  position: absolute;
  right: var(--gutter);
  top: 50%;
  transform: translateY(-62%) rotate(-14deg);
  transition: transform 0.2s ease;
}
.mail:hover, .mail:focus-visible { transform: translateY(-70%) rotate(0deg); }
.mail svg { filter: drop-shadow(0 3px 0 rgb(81 30 30 / 0.25)); }

/* ---- Page frame ------------------------------------------------------------ */

main {
  display: block;
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 0 var(--gutter);
}

.intro {
  max-width: 46rem;
  padding: clamp(2rem, 6vw, 3.75rem) 0 clamp(1.75rem, 4.5vw, 2.75rem);
}
.intro p { margin: 0 0 1rem; }
.intro .lede { font-size: clamp(1.2rem, 2.3vw, 1.45rem); line-height: 1.5; }

.links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
  margin: 1.25rem 0 0;
  padding: 0;
  list-style: none;
  font-weight: 600;
}

/* Section band: the old site's maroon bars, now carrying the section's years. */
.band {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: baseline;
  gap: 0 1rem;
  margin: 0;
  padding: 0.5rem 1rem 0.45rem;
  background: var(--oxblood);
  color: var(--cream);
}
.band h2 {
  margin: 0;
  font: 500 1.3rem/1.25 var(--display);
  letter-spacing: 0.04em;
}
.band p { margin: 0; font-size: 0.9375rem; }

.well {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: var(--gap);
  margin: 0 0 clamp(2.5rem, 6vw, 4rem);
  padding: var(--gap);
  background: var(--well);
}

/* ---- Tiles ----------------------------------------------------------------- */

.tile {
  grid-column: span 4;
  display: flex;
  flex-direction: column;
  background: var(--paper);
  color: var(--ink);
  text-decoration: none;
}
.tile--hero { grid-column: span 8; }
.tile--side { grid-column: span 4; }
.tile--half { grid-column: span 6; }
.tile--third { grid-column: span 4; }

.tile__media {
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: #2b2b2b;
}
.tile--hero .tile__media { aspect-ratio: 16 / 10; }
.tile--side .tile__media { flex: 1; aspect-ratio: auto; min-height: 14rem; }
.tile--half .tile__media, .tile--third .tile__media { aspect-ratio: 16 / 9; }
.tile--short .tile__media { aspect-ratio: 16 / 9; }
/* A video tile isn't a link itself: the player inside it is. */
.tile--video .tile__media { aspect-ratio: 16 / 9; }
.tile--video .yt, .tile--video .yt-pending,
.tile--video .hosted-video, .tile--video .hosted-video__player { height: 100%; }

.tile__body { padding: 0.8rem 1rem 1.05rem; }

.tile__title {
  margin: 0 0 0.2rem;
  font: 500 1.5rem/1.15 var(--display);
  letter-spacing: 0.01em;
}
.tile--hero .tile__title { font-size: 1.85rem; }

.tile__meta { margin: 0; color: var(--ink-soft); font-size: 0.9375rem; line-height: 1.45; }

.tile:hover .tile__title,
.tile:focus-visible .tile__title { color: var(--brick); }

.lock { display: inline-flex; align-items: center; gap: 0.35em; }
.lock svg { width: 0.85em; height: auto; flex: none; }

/* A logo on plain white, with the same 25%-to-full color fade as the pictures. */
.tile__media--logo { display: grid; place-items: center; flex: 1; padding: 18%; background: #fff; }
.tile--side .tile__media--logo { padding: 8%; }
.tile__media--logo img { width: 100%; height: auto; filter: saturate(0.25); transition: filter 0.45s ease; }
a:hover .tile__media--logo img,
a:focus-visible .tile__media--logo img { filter: none; }

/* ---- Desaturated to color -------------------------------------------------------
   Two copies of the same picture: one at 25% saturation underneath, the color copy fading in on hover. */

.duo { position: relative; display: block; width: 100%; height: 100%; }
.duo img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.duo > img:first-child { filter: saturate(0.25) contrast(1.05); }
.duo__color { opacity: 0; transition: opacity 0.45s ease; }
a:hover .duo__color,
a:focus-visible .duo__color { opacity: 1; }

/* ---- Work pages -------------------------------------------------------------- */

.page-head { max-width: 48rem; padding: clamp(1.75rem, 5vw, 3.25rem) 0 clamp(1.25rem, 3vw, 2rem); }
.backlink { font-size: 0.9375rem; }

h1 {
  margin: 0.4rem 0 0.6rem;
  font: 500 clamp(2.4rem, 5.5vw, 3.75rem)/1.05 var(--display);
  letter-spacing: 0.01em;
  color: var(--oxblood);
}
.page-meta { margin: 0 0 1.25rem; color: var(--ink-soft); }
/* Roles held at one company, one per line under the location. */
.page-meta:has(+ .roles) { margin-bottom: 0.3rem; }
.roles { margin: 0 0 1.25rem; padding-left: 1.1rem; color: var(--ink-soft); list-style: square; }
.roles li { margin-bottom: 0.15rem; }
.roles li::marker, .credits li::marker { color: var(--brick); }
/* Releases shipped, under a page's lede. */
.credits { margin: 1rem 0 0; padding-left: 1.1rem; list-style: square; }
.credits li { margin-bottom: 0.25rem; }
.lede { font-size: clamp(1.15rem, 2vw, 1.3rem); line-height: 1.55; }
.page-head .lede { margin: 0; }

.section { padding: clamp(1.5rem, 4vw, 2.5rem) 0; border-top: 1px solid var(--silver); }
.section > h2, .prose h2 {
  margin: 0 0 0.75rem;
  font: 500 1.75rem/1.2 var(--display);
  color: var(--oxblood);
}
.prose { max-width: 42rem; }
.section.prose { max-width: none; }
.section.prose > * { max-width: 42rem; }
.prose p { margin: 0 0 1rem; }
.prose ul, .did { margin: 0 0 1rem; padding-left: 1.15rem; list-style: square; }
.prose li, .did li { margin-bottom: 0.4rem; }
.prose li::marker, .did li::marker { color: var(--brick); }
/* A labelled item whose points are listed under it rather than run together. */
.prose li > ul, .did li > ul, .cv-item li > ul { margin: 0.3rem 0 0; padding-left: 1.1rem; list-style: disc; }

.split {
  display: grid;
  grid-template-columns: minmax(0, 6fr) minmax(0, 5fr);
  gap: clamp(1.25rem, 3.5vw, 3rem);
  align-items: start;
}

/* One video, one story. */
.entry {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  gap: clamp(1.25rem, 3vw, 2.5rem);
  align-items: start;
  padding: clamp(1.5rem, 4vw, 2.5rem) 0;
  border-top: 1px solid var(--silver);
}
.entry h3, .section h3 {
  margin: 0 0 0.5rem;
  font: 500 1.5rem/1.2 var(--display);
}
.entry p { margin: 0 0 0.85rem; }
.entry .when { color: var(--ink-soft); font-size: 0.9375rem; margin-bottom: 0.5rem; }
.did { font-size: 0.975rem; }
.did-label { margin: 0 0 0.35rem; font-weight: 600; }

figure { margin: 0; }
figcaption { margin-top: 0.5rem; color: var(--ink-soft); font-size: 0.9rem; line-height: 1.45; }

/* Video facade: nothing loads from YouTube until it's clicked. */
.yt {
  position: relative;
  display: block;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: #2b2b2b;
  color: var(--cream);
  text-decoration: none;
}
.yt__play {
  position: absolute;
  left: 0;
  bottom: 0;
  padding: 0.55rem 1rem 0.55rem 2.25rem;
  background: var(--oxblood);
  color: var(--cream);
  font-weight: 600;
  font-size: 0.9375rem;
}
.yt__play::before {
  content: "";
  position: absolute;
  left: 0.95rem;
  top: 50%;
  width: 0.7rem;
  height: 0.8rem;
  background: currentColor;
  clip-path: polygon(0 0, 100% 50%, 0 100%);
  transform: translateY(-50%);
}
.yt:hover .yt__play, .yt:focus-visible .yt__play { background: var(--brick); color: #fff; }
.yt-pending { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; background: #2b2b2b; }
/* A still standing in for a video that isn't uploaded yet: same desaturated-to-color treatment. */
.yt-pending { filter: saturate(0.25) contrast(1.05); transition: filter 0.45s ease; }
.yt-pending:hover, .tile--video:hover .yt-pending { filter: none; }
.yt__frame { display: block; width: 100%; aspect-ratio: 16 / 9; border: 0; background: #000; }
/* A self-hosted video on a private page: the same facade, as a button, until it's clicked. */
.hosted-video__play { width: 100%; padding: 0; border: 0; font: inherit; cursor: pointer; }
.hosted-video__play:hover .yt-pending, .hosted-video__play:focus-visible .yt-pending { filter: none; }
.hosted-video__player { display: block; width: 100%; aspect-ratio: 16 / 9; background: #000; }
/* Private pages: no long-press save menu on phones, no dragging images out (with initPrivateMedia in site.js). */
[data-private] img, [data-private] a[data-lightbox] { -webkit-touch-callout: none; -webkit-user-drag: none; user-select: none; }
/* A silent loop shown like an animated image (<x-loop>), with its own Pause button */
.loop { position: relative; }
.loop video { display: block; width: 100%; height: auto; }
.loop__toggle {
  position: absolute;
  right: 0.5rem;
  bottom: 0.5rem;
  padding: 0.25rem 0.65rem;
  border: 0;
  background: rgb(36 22 22 / 0.72);
  color: var(--cream);
  font: 600 0.8125rem/1.3 var(--text);
  cursor: pointer;
}
.loop__toggle:hover { background: var(--brick); color: #fff; }
.reel { margin: 0 0 clamp(1.5rem, 4vw, 2.5rem); }
.video-row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--gap); margin: 1.25rem 0; }
.video-row--two { grid-template-columns: repeat(2, minmax(0, 1fr)); }
/* Two videos for one entry, one above the other. */
.video-stack { display: grid; gap: var(--gap); align-content: start; }
.video-stack figure { margin: 0; }

.callout {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem 2rem;
  margin: clamp(1.5rem, 4vw, 2.5rem) 0;
  padding: 1.25rem clamp(1rem, 3vw, 1.75rem);
  background: var(--well);
  border-left: 6px solid var(--oxblood);
}
.callout p { margin: 0; max-width: 46ch; }
.case-link { margin: clamp(1.5rem, 4vw, 2.5rem) 0 0; }

/* The case-study request: the lock button opens a short form under it. */
.request { margin: clamp(1.5rem, 4vw, 2.5rem) 0 0; }
.request > summary { width: fit-content; list-style: none; }
.request > summary::-webkit-details-marker { display: none; }
.request__form { display: grid; gap: 0.35rem; max-width: 28rem; margin-top: 1rem; }
.request__form[hidden] { display: none; }
.request__form label { margin-top: 0.4rem; font-weight: 600; }
.request__optional { color: var(--ink-soft); font-weight: 400; }
.request__form input, .request__form textarea {
  padding: 0.5rem 0.6rem;
  border: 1px solid var(--silver);
  background: #fff;
  color: var(--ink);
  font: inherit;
}
.request__form textarea { resize: vertical; }
.request__form .button { justify-self: start; margin-top: 0.6rem; }
.request__check:empty { display: none; }
.request__status { margin: 0.75rem 0 0; font-weight: 600; }
.request__status:empty { display: none; }

.button {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  padding: 0.65rem 1.1rem;
  border: 0;
  background: var(--oxblood);
  color: var(--cream);
  font: 600 1rem/1.2 var(--text);
  text-decoration: none;
  cursor: pointer;
}
.button:hover { background: var(--brick); color: #fff; }
.button[disabled] { opacity: 0.6; cursor: progress; }

.next {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.5rem 0 0;
  font-weight: 600;
}

/* Archive: one band per game, text, then pictures. */
.block { margin: 0 0 clamp(2.5rem, 6vw, 4rem); }
.block__text { padding: 1.25rem 0 0.25rem; }
.block .gallery { margin-bottom: 0.5rem; }
.band + .entry { border-top: 0; }
.section > h2 + .entry { border-top: 0; padding-top: 0.5rem; }

/* ---- Pictures ------------------------------------------------------------------ */

.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  gap: 0.75rem;
  margin: 1.25rem 0 0;
  padding: 0;
  list-style: none;
}
.gallery a { display: block; aspect-ratio: 4 / 3; overflow: hidden; background: var(--well); }
.gallery img { width: 100%; height: 100%; object-fit: cover; }
.gallery a:hover img, .gallery a:focus-visible img { outline: 4px solid var(--brick); outline-offset: -4px; }

.gallery--two { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.gallery--three { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.gallery--two a { aspect-ratio: 16 / 9; }
/* Whole images (texture sheets), not cropped to the frame */
.gallery--contain a { background: #262626; }
.gallery--contain img { object-fit: contain; }

.gallery--medals { grid-template-columns: repeat(auto-fill, minmax(min(100%, 9.5rem), 1fr)); }
.gallery--medals a { aspect-ratio: 1; background: #303030; }
.gallery--medals img { object-fit: contain; }

.gallery--frames { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1rem; }
.gallery--frames a { aspect-ratio: 1; }
.gallery--frames img { width: 100%; aspect-ratio: 1; object-fit: cover; background: #000; }
.gallery--four { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.gallery--pair { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.gallery--frames figcaption { margin-top: 0.4rem; }
.section > .prose { margin: 0 0 0.25rem; }
.gallery + .page-meta, .resolutions + .page-meta { margin-top: 1.25rem; }

.strip { display: block; width: 100%; height: auto; margin-top: 1.25rem; background: #303030; }

/* Images side by side, uncropped. Each figure's share of the row is set inline: its width in pixels keeps one
   scale (Mememage's resolutions), its aspect ratio keeps one height (the agent's renders). */
.resolutions { display: flex; align-items: flex-end; gap: 0.75rem; margin-top: 1.25rem; }
.resolutions figure { min-width: 0; }
.resolutions img { width: 100%; height: auto; }
.resolutions figcaption { font-size: 0.85rem; line-height: 1.35; }
.resolutions + .resolutions { margin-top: 0.75rem; }
.resolutions + .prose { margin-top: 1.5rem; }

/* Mememage's bar, revealed: the image as anyone sees it, then a zoom into each anchor, then the whole bar. */
.bar-reveal {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  gap: clamp(1.25rem, 3vw, 2.5rem);
  align-items: start;
  margin: 0 0 clamp(1.5rem, 4vw, 2.5rem);
}
.bar-reveal__view {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 1;
  padding: 0;
  overflow: hidden;
  border: 0;
  background: #111;
  cursor: zoom-in;
}
.bar-reveal[data-stage="bar"] .bar-reveal__view { cursor: zoom-out; }
.bar-reveal__img { position: absolute; inset: 0; width: 100%; height: 100%; transition: filter 0.5s ease; }
/* Each corner (64x64 source pixels) starts shrunk to exactly cover its corner of the image, then grows to fill the
   frame. It reads as a zoom, but the browser only ever paints a frame-sized layer. */
.bar-reveal__lens {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  image-rendering: pixelated;
  opacity: 0;
  transform: scale(0.0625);
  transition: transform 0.9s cubic-bezier(0.2, 0.7, 0.2, 1), opacity 0.2s ease 0.7s;
}
.bar-reveal__lens--start { transform-origin: 0% 100%; }
.bar-reveal__lens--end { transform-origin: 100% 100%; }
.bar-reveal[data-stage="start"] .bar-reveal__lens--start,
.bar-reveal[data-stage="end"] .bar-reveal__lens--end { opacity: 1; transform: none; transition: transform 0.9s cubic-bezier(0.2, 0.7, 0.2, 1), opacity 0.15s ease; }
.bar-reveal[data-stage="bar"] .bar-reveal__img { filter: brightness(0.4); }
/* Outline around the anchor bands once the zoom settles: three 8px bands are 24 of the 64 source pixels, and the
   bar is the bottom 2 of 64 rows. */
.bar-reveal__mark {
  position: absolute;
  bottom: 0;
  width: 37.5%;
  height: 3.125%;
  outline: 3px solid #fff;
  outline-offset: 3px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s ease;
}
.bar-reveal__mark--start { left: 0; }
.bar-reveal__mark--end { right: 0; }
.bar-reveal__mark span {
  position: absolute;
  bottom: calc(100% + 12px);
  padding: 0.25rem 0.55rem;
  background: #fff;
  color: var(--ink);
  font: 600 0.9rem/1.2 var(--text);
  white-space: nowrap;
}
.bar-reveal__mark--start span { left: -3px; }
.bar-reveal__mark--end span { right: -3px; }
.bar-reveal[data-stage="start"] .bar-reveal__mark--start,
.bar-reveal[data-stage="end"] .bar-reveal__mark--end { opacity: 1; transition: opacity 0.3s ease 0.8s; }
.bar-reveal__strip {
  position: absolute;
  left: 0;
  bottom: 6%;
  width: 100%;
  height: 7%;
  image-rendering: pixelated;
  opacity: 0;
  transform: translateY(160%);
  transition: transform 0.6s cubic-bezier(0.2, 0.7, 0.2, 1), opacity 0.4s ease;
  box-shadow: 0 0 0 2px #fff;
}
.bar-reveal[data-stage="bar"] .bar-reveal__strip { opacity: 1; transform: none; }
.bar-reveal__side h2 { margin: 0 0 0.9rem; font: 500 1.75rem/1.2 var(--display); color: var(--oxblood); }
.bar-reveal__controls { display: flex; flex-wrap: wrap; gap: 0.4rem; margin: 0 0 1rem; }
.bar-reveal__controls button {
  padding: 0.5rem 0.85rem;
  border: 2px solid var(--oxblood);
  background: transparent;
  color: var(--oxblood);
  font: 600 0.95rem/1.2 var(--text);
  cursor: pointer;
}
.bar-reveal__controls button:hover { background: var(--well); }
.bar-reveal__controls button[aria-pressed="true"] { background: var(--oxblood); color: var(--cream); }
.bar-reveal__caption { min-height: 6.5em; margin: 0; }
.bar-reveal noscript img { width: 100%; height: auto; margin-bottom: 0.5rem; image-rendering: pixelated; }

.screenshot img { width: 100%; height: auto; border: 1px solid var(--silver); }
.prose .screenshot { margin: 0 0 1.25rem; }

/* A prompt context and the model's reply, as text. */
.prompts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--gap); }
.prompt { margin: 0; }
.prompt__label { margin: 0 0 0.3rem; font-size: 0.85rem; font-weight: 600; color: var(--ink-soft); }
.prompt pre {
  margin: 0 0 0.9rem;
  padding: 0.85rem 1rem;
  background: var(--well);
  font: 0.8125rem/1.55 var(--mono);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.prompt .prompt__reply { background: transparent; border-left: 3px solid var(--brick); }

/* The agent platform, drawn as what runs where. */
.stack {
  display: grid;
  gap: 0.75rem;
  padding: 1rem;
  border: 2px solid var(--oxblood);
  background: var(--paper);
  font-size: 0.95rem;
}
.stack__label { margin: -0.25rem 0 0.25rem; font: 500 1.15rem/1.2 var(--display); color: var(--oxblood); }
.stack__row { display: grid; grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); gap: 0.75rem; }
.stack__box { padding: 0.65rem 0.8rem; background: var(--well); border-top: 3px solid var(--brick); }
.stack__box strong { display: block; }
.stack__box span { color: var(--ink-soft); }
.stack__box--core { background: var(--oxblood); color: var(--cream); border-top-color: var(--amber); }
.stack__box--core span { color: var(--cream); opacity: 0.85; }

/* Measured results: a plain table, numbers aligned, the better column in bold. */
.data { width: 100%; margin: 0.75rem 0 1rem; border-collapse: collapse; font-size: 0.95rem; }
.data th, .data td { padding: 0.45rem 0.6rem; border-bottom: 1px solid var(--silver); text-align: left; vertical-align: top; }
.data thead th { border-bottom: 2px solid var(--oxblood); font-weight: 600; }
.data tbody th { font-weight: 400; }
.data td { font-variant-numeric: tabular-nums; white-space: nowrap; }
.data--text td { white-space: normal; }

/* ---- Resume -------------------------------------------------------------------- */

.cv-section { padding: clamp(1.25rem, 3vw, 2rem) 0 0.5rem; }
.cv-item {
  display: grid;
  grid-template-columns: 10.5rem minmax(0, 1fr);
  gap: 0.25rem clamp(1rem, 3vw, 2.5rem);
  padding: 1.1rem 0;
  border-top: 1px solid var(--silver);
}
.cv-when { color: var(--ink-soft); font-size: 0.9375rem; font-variant-numeric: tabular-nums; padding-top: 0.2rem; }
.cv-item h3 { margin: 0 0 0.15rem; font: 500 1.4rem/1.2 var(--display); }
.cv-item h4 { margin: 0.9rem 0 0.2rem; font-size: 1rem; }
.cv-item p { margin: 0 0 0.6rem; }
.cv-item ul { margin: 0.25rem 0 0.5rem; padding-left: 1.15rem; list-style: square; max-width: 46rem; }
.cv-item li { margin-bottom: 0.35rem; }
.cv-item li::marker { color: var(--brick); }
.cv-sub { color: var(--ink-soft); }
.cv-item .roles { margin: 0 0 0.6rem; color: var(--ink-soft); }
.skills { display: grid; gap: 0; margin: 0; }
.skills div { display: grid; grid-template-columns: 10.5rem minmax(0, 1fr); gap: clamp(1rem, 3vw, 2.5rem); padding: 0.6rem 0; border-top: 1px solid var(--silver); }
.skills dt { font-weight: 600; }
.skills dd { margin: 0; }

/* ---- Lightbox ------------------------------------------------------------------- */

/* A fixed overlay rather than a modal dialog: the top layer would cover browser extensions'
   own overlays (the Mememage extension marks bars on the image), and make them unclickable. */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 1000;
  width: auto;
  height: auto;
  max-width: none;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  background: rgb(36 22 22 / 0.88);
}
.lightbox[open] { display: grid; place-items: center; }
.lightbox__panel {
  width: min(96vw, 80rem);
  max-height: 94vh;
  background: #1c1111;
  color: var(--cream);
  animation: lb-in 0.18s ease-out;
}
@keyframes lb-in { from { opacity: 0; transform: scale(0.985); } }
.overlay-open { overflow: hidden; }
.lightbox figure { display: grid; place-items: center; padding: 1rem 1rem 0; }
.lightbox img { max-height: calc(94vh - 7.5rem); width: auto; object-fit: contain; }
.lightbox figcaption { color: var(--cream); font-size: 0.95rem; text-align: center; max-width: 60ch; }
.lightbox__bar { display: flex; align-items: center; gap: 0.5rem; padding: 0.75rem 1rem 1rem; }
.lightbox__count { margin-right: auto; font-size: 0.9rem; opacity: 0.85; font-variant-numeric: tabular-nums; }
.lightbox button {
  padding: 0.5rem 0.9rem;
  border: 1px solid rgb(255 243 196 / 0.4);
  background: transparent;
  color: var(--cream);
  font: 600 0.95rem/1.2 var(--text);
  cursor: pointer;
}
.lightbox button:hover { background: var(--brick); border-color: var(--brick); color: #fff; }
.lightbox :focus-visible { outline-color: var(--amber); }

/* ---- Hall of Medals (Halo: Reach) ------------------------------------------------
   Medals hang on a dark wall, each in its own pool of light over a brass plaque. Spree medals stand in
   cases, one per spree, tiers side by side. site.js tilts a medal toward the pointer (--rx, --ry), moves
   its glint (--gx, --gy, masked by --medal) and opens the medal viewer. */

.hall {
  margin: 1.5rem 0 0;
  padding: clamp(1rem, 3vw, 2rem) clamp(0.75rem, 3vw, 2rem) clamp(1.25rem, 3vw, 2rem);
  background: linear-gradient(#2a1f1f, #1a1212 75%);
  color: var(--cream);
}
.hall :focus-visible { outline-color: var(--amber); }
.hall__head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 0.25rem 1rem; }
.hall__title { margin: 0; font: 500 clamp(1.6rem, 3.2vw, 2.1rem)/1.2 var(--display); letter-spacing: 0.04em; }
.hall__seen { margin: 0; color: var(--amber); font-size: 0.9375rem; font-weight: 600; font-variant-numeric: tabular-nums; }
.hall__plan { display: flex; flex-wrap: wrap; gap: 0.4rem; margin: 0.85rem 0 0; padding: 0; list-style: none; }
.hall__plan a {
  display: block;
  padding: 0.3rem 0.75rem;
  border: 1px solid rgb(255 243 196 / 0.3);
  color: var(--cream);
  font-size: 0.9375rem;
  text-decoration: none;
}
.hall__plan a:hover { background: var(--brick); border-color: var(--brick); color: #fff; }
.hall__foot { margin: clamp(1.75rem, 4vw, 2.5rem) 0 0; color: rgb(255 243 196 / 0.75); font-size: 0.875rem; text-align: center; }
.hall__foot a { color: var(--cream); }
.hall__foot a:hover { color: var(--amber); }

.room { padding-top: clamp(1.75rem, 4vw, 2.75rem); scroll-margin-top: 1rem; }
.room__title {
  margin: 0 0 1rem;
  padding-bottom: 0.45rem;
  border-bottom: 1px solid rgb(255 243 196 / 0.18);
  font: 500 1.35rem/1.2 var(--display);
  letter-spacing: 0.04em;
}
.room__no { margin-right: 0.3rem; color: var(--amber); font-size: 0.85em; }
.room__wall { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.5rem 0.75rem; margin: 0; padding: 0; list-style: none; }
.room__wall--cases { gap: 1rem; }

.exhibit { flex: 0 1 10.5rem; min-width: 0; }
.exhibit a {
  position: relative;
  isolation: isolate;
  display: grid;
  justify-items: center;
  gap: 0.6rem;
  padding: 1.25rem 0.4rem 0.75rem;
  color: inherit;
  text-decoration: none;
}
/* The pool of light on the wall */
.exhibit a::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: radial-gradient(55% 48% at 50% 40%, rgb(255 226 170 / 0.2), transparent 72%);
  opacity: 0.55;
  transition: opacity 0.3s ease;
}
.exhibit a:focus-visible::before { opacity: 1; }
.exhibit .medal { width: min(100%, 8.75rem); }
.exhibit a:focus-visible .medal { --lift: -0.3rem; }
/* Hover only with a mouse: on a touch screen a tapped medal would stay lifted */
@media (hover: hover) {
  .exhibit a:hover::before { opacity: 1; }
  .exhibit a:hover .medal { --lift: -0.3rem; }
}

.medal {
  position: relative;
  display: block;
  transform: perspective(40rem) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)) translateY(var(--lift, 0));
  transition: transform 0.5s cubic-bezier(0.2, 0.7, 0.2, 1);
  filter: drop-shadow(0 0.7rem 0.55rem rgb(0 0 0 / 0.6));
}
.medal.is-tilted { transition-duration: 0.12s; }
.medal img { width: 100%; height: auto; }
.medal__glint {
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at var(--gx, 30%) var(--gy, 22%), rgb(255 248 230 / 0.4), transparent 60%);
  mix-blend-mode: screen;
  -webkit-mask: var(--medal) center / 100% 100% no-repeat;
  mask: var(--medal) center / 100% 100% no-repeat;
  opacity: 0;
  transition: opacity 0.3s ease;
}
.exhibit a:hover .has-glint .medal__glint { opacity: 0.55; }

.plaque {
  display: grid;
  justify-items: center;
  min-width: min(100%, 7.5rem);
  max-width: 100%;
  padding: 0.3rem 0.6rem 0.35rem;
  background: linear-gradient(#d2b47c, #a3804a);
  color: #2b1d0e;
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.4), inset 0 -1px 0 rgb(0 0 0 / 0.25), 0 2px 4px rgb(0 0 0 / 0.5);
  text-align: center;
}
.plaque__no { font: 600 0.6875rem/1.3 var(--text); letter-spacing: 0.1em; opacity: 0.8; }
.plaque__name { font: 500 0.95rem/1.15 var(--display); letter-spacing: 0.02em; }
.is-seen .plaque__no::after { content: " \2713" / ""; }

.case {
  flex: 1 1 19rem;
  min-width: 0;
  max-width: 26rem;
  padding: 0.65rem 0.4rem 0.35rem;
  border: 1px solid rgb(255 243 196 / 0.14);
  background: linear-gradient(rgb(255 243 196 / 0.05), rgb(255 243 196 / 0.015));
  box-shadow: inset 0 0 2rem rgb(0 0 0 / 0.35);
}
.case__label { margin: 0; color: var(--amber); font: 500 1.05rem/1.2 var(--display); letter-spacing: 0.05em; text-align: center; }
.case__shelf { display: flex; justify-content: center; margin: 0; padding: 0; list-style: none; }
.case .exhibit { flex: 1 1 0; max-width: 8.5rem; }
.case .exhibit a { height: 100%; grid-template-rows: auto 1fr; padding: 0.9rem 0.2rem 0.5rem; }
.case .plaque { align-content: center; min-width: 0; width: 100%; padding-inline: 0.3rem; }
.case .plaque__name { font-size: 0.85rem; }

/* ---- Avatar rig (Broadcasting and VTubing) ------------------------------------------
   The VTuber avatar put together from its texture parts, each where the Live2D model has it (positions from
   tools/catmemes-rig.py, as percentages of the stage; the head's eyes and mouths as percentages of the head).
   site.js (initRig) greys out all but the chosen part, which then moves the way the rig moves it, and pulls
   the parts apart. Unchosen, the avatar idles: breathing and a tail sway. Explode offsets use translate,
   the motions rotate and scale, so they combine. */

.rig { display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); gap: 1rem 2rem; align-items: center; margin: clamp(1.5rem, 4vw, 2.5rem) 0 0; }
.rig figcaption { grid-column: 1 / -1; }
.rig__stage { position: relative; aspect-ratio: 1071 / 1044; overflow: hidden; background: rgb(250 251 237); }
.rig__stage img, .rig__head { position: absolute; display: block; height: auto; }
.rig__stage [data-group] { transition: translate 0.7s cubic-bezier(0.2, 0.7, 0.2, 1), opacity 0.3s ease, filter 0.3s ease; }
.rig__head { aspect-ratio: 438 / 379; }
.rig [data-group="eyes"], .rig [data-group="mouth"] { opacity: 0; }

.rig [data-group="body"] { animation: rig-breathe 3.4s ease-in-out infinite; }
.rig [data-group="tail"] { animation: rig-sway 2.8s ease-in-out infinite; }
@keyframes rig-breathe { 50% { scale: 1 1.012; } }
@keyframes rig-sway { 0%, 100% { rotate: -3deg; } 50% { rotate: 4deg; } }

/* A chosen part, and the parts it isn't */
.rig__stage[data-active] [data-group]:not(.is-on) { opacity: 0.28; filter: grayscale(1); }
.rig__stage[data-active] [data-group="eyes"]:not(.is-on),
.rig__stage[data-active] [data-group="mouth"]:not(.is-on) { opacity: 0; }
.rig [data-group="head"].is-on:not(.is-context) { animation: rig-tilt 2.4s ease-in-out infinite; }
.rig [data-group="eyes"].is-on { animation: rig-blink 2.2s infinite; }
.rig [data-group="mouth"].is-on { animation: rig-mouth 1.5s infinite; animation-delay: calc(var(--i) * -0.3s); }
.rig [data-group="paws"].is-on { animation: rig-press 0.9s ease-in-out infinite alternate; }
.rig [data-part="paw-left"].is-on { animation-delay: -0.45s; }
.rig [data-group="tail"].is-on { animation: rig-sway-wide 1.8s ease-in-out infinite; }
.rig [data-group="body"].is-on { animation: rig-breathe-deep 2.2s ease-in-out infinite; }
@keyframes rig-tilt { 0%, 100% { rotate: -7deg; } 50% { rotate: 7deg; } }
@keyframes rig-blink { 0%, 38%, 50%, 100% { opacity: 0; } 40%, 48% { opacity: 1; } }
@keyframes rig-mouth { 0%, 19.9% { opacity: 1; } 20%, 100% { opacity: 0; } }
@keyframes rig-press { from { rotate: -6deg; } to { rotate: 6deg; } }
@keyframes rig-sway-wide { 0%, 100% { rotate: -9deg; } 50% { rotate: 11deg; } }
@keyframes rig-breathe-deep { 50% { scale: 1 1.035; } }

/* Pulled apart */
.rig__stage.is-apart [data-group="head"] { translate: 0 -16%; }
.rig__stage.is-apart [data-part="paw-right"] { translate: -95% -35%; }
.rig__stage.is-apart [data-part="paw-left"] { translate: 100% -35%; }
.rig__stage.is-apart [data-group="tail"] { translate: 60% 4%; }

.rig__parts { display: grid; gap: 0.4rem; margin: 0 0 1rem; padding: 0; list-style: none; }
.rig__parts button {
  display: grid;
  width: 100%;
  padding: 0.5rem 0.8rem;
  border: 1px solid var(--silver);
  background: var(--paper);
  color: var(--ink);
  font: 600 1rem/1.3 var(--text);
  text-align: left;
  cursor: pointer;
}
.rig__parts button span { color: var(--ink-soft); font-size: 0.875rem; font-weight: 400; }
.rig__parts button:hover { border-color: var(--brick); }
.rig__parts button[aria-pressed="true"] { background: var(--oxblood); border-color: var(--oxblood); color: var(--cream); }
.rig__parts button[aria-pressed="true"] span { color: var(--cream); opacity: 0.85; }
.rig__apart[aria-pressed="true"] { background: var(--brick); }
@media (max-width: 44rem) { .rig { grid-template-columns: minmax(0, 1fr); } }

/* The medal viewer: the lightbox, with a stage for the medal and its plaque beside it. */
.medal-view .lightbox__panel { width: min(96vw, 56rem); overflow: auto; }
.medal-view__body {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
  align-items: center;
  gap: 1rem 1.75rem;
  padding: 1.25rem 1.5rem 0;
}
.medal-view__stage {
  display: grid;
  place-items: center;
  padding: 1rem 0.5rem;
  background: radial-gradient(55% 55% at 50% 45%, rgb(255 226 170 / 0.16), transparent 75%);
  touch-action: pan-y;
}
/* No larger than the 582x500 source, and short enough to leave room for the bar */
.medal-view .medal { width: min(100%, 36.375rem, (94vh - 10rem) * 1.164); }
.medal-view img { max-height: none; }
.medal-view .has-glint .medal__glint { opacity: 0.45; }
.medal-view__no { margin: 0; color: var(--amber); font-size: 0.875rem; font-weight: 600; letter-spacing: 0.1em; }
.medal-view__name { margin: 0.15rem 0 0.5rem; font: 500 clamp(1.6rem, 3.5vw, 2.25rem)/1.15 var(--display); }
.medal-view__where, .medal-view__note { margin: 0 0 0.3rem; font-size: 0.95rem; }
.medal-view__note:empty { display: none; }
.medal-view__tiers { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 1.1rem 0 0; padding: 0; list-style: none; }
.medal-view__tiers:empty { display: none; }
.medal-view__tiers button {
  display: grid;
  justify-items: center;
  gap: 0.2rem;
  width: 5.75rem;
  height: 100%;
  padding: 0.4rem 0.3rem;
  font: 400 0.75rem/1.2 var(--text);
}
.medal-view__tiers button[aria-pressed="true"] { border-color: var(--amber); background: rgb(242 160 36 / 0.14); }
.medal-view__tiers img { width: 100%; height: auto; }
@media (max-width: 44rem) {
  .medal-view__body { grid-template-columns: minmax(0, 1fr); padding-inline: 1rem; }
  .medal-view .medal { width: min(100%, 36.375rem, (94vh - 20rem) * 1.164); }
}

/* ---- Footer -------------------------------------------------------------------- */

.site-footer { margin-top: clamp(3rem, 8vw, 5rem); border-top: 3px solid var(--oxblood); }
.site-footer__inner {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 1.25rem var(--gutter) 2rem;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.75rem 2rem;
  color: var(--ink-soft);
  font-size: 0.9375rem;
}
.site-footer p { margin: 0; }
.site-footer ul { display: flex; flex-wrap: wrap; gap: 0.5rem 1.5rem; margin: 0; padding: 0; list-style: none; }

/* ---- Small screens ----------------------------------------------------------------- */

@media (max-width: 60rem) {
  .tile, .tile--hero, .tile--side, .tile--half, .tile--third { grid-column: span 6; }
  .tile--hero { grid-column: span 12; }
  .entry, .split, .bar-reveal, .prompts, .video-row { grid-template-columns: minmax(0, 1fr); }
  .resolutions { flex-wrap: wrap; align-items: flex-start; }
  .resolutions figure { flex: 1 1 40% !important; }
  .gallery--frames { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .gallery--three { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 40rem) {
  .tile, .tile--hero, .tile--side, .tile--half, .tile--third { grid-column: span 12; }
  .cv-item, .skills div { grid-template-columns: minmax(0, 1fr); }
  .gallery--two, .gallery--three { grid-template-columns: minmax(0, 1fr); }
  .mail { right: calc(var(--gutter) - 0.25rem); }
  .mail svg { width: 40px; height: auto; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; animation: none !important; }
}

@media print {
  .navband, .site-footer ul, .skip, .callout .button, .case-link { display: none; }
  body { background: #fff; }
}

/* A game's objects, each with all its views (inFAMOUS 2): two cards to a row. */
.groups-head { margin: clamp(1.75rem, 4vw, 2.5rem) 0 0; padding-top: 1rem; border-top: 1px solid var(--silver); font: 500 1.5rem/1.2 var(--display); }
.groups { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(1.75rem, 3vw, 2.5rem) clamp(1.25rem, 3vw, 2.5rem); margin: 1rem 0 0; }
.band + .groups-head { margin-top: 1rem; padding-top: 0; border-top: 0; }
.group h3, .group h4 { margin: 0 0 0.35rem; font: 600 1.05rem/1.3 var(--text); }
.group .hosted-video { margin-top: 0.75rem; }
.group .did { margin: 0; padding-left: 1.1rem; }
.gallery--thumbs { grid-template-columns: repeat(auto-fill, minmax(min(100%, 7.5rem), 1fr)); gap: 0.5rem; margin-top: 0.75rem; }
@media (max-width: 52rem) { .groups { grid-template-columns: minmax(0, 1fr); } }
