/*
 * Site stylesheet.
 *
 * One serif family on warm paper, set in one centered column of about 65
 * characters. The palette follows Anthropic's (ivory paper, slate ink, a clay
 * accent used sparingly); the typography follows book design: small capitals
 * for labels and dates, italic subtitles, quiet underlined links, and headings
 * set apart by weight and space more than by size.
 */

/*
 * Fonts: Source Serif 4, self-hosted variable fonts (SIL OFL, licenses in
 * ../fonts/). Chinese is set in Noto Serif SC (Source Han Serif), whose
 * @font-face the build appends to this file, cut down to the characters the
 * site uses (lib/fonts.js).
 */
@font-face {
  font-family: "Source Serif 4";
  font-style: normal;
  font-weight: 200 900;
  font-display: swap;
  src: url("../fonts/source-serif-4-latin-wght-normal.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: "Source Serif 4";
  font-style: normal;
  font-weight: 200 900;
  font-display: swap;
  src: url("../fonts/source-serif-4-latin-ext-wght-normal.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-20C0, U+2113, U+2C60-2C7F,
    U+A720-A7FF;
}
@font-face {
  font-family: "Source Serif 4";
  font-style: italic;
  font-weight: 200 900;
  font-display: swap;
  src: url("../fonts/source-serif-4-latin-wght-italic.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: "Source Serif 4";
  font-style: italic;
  font-weight: 200 900;
  font-display: swap;
  src: url("../fonts/source-serif-4-latin-ext-wght-italic.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-20C0, U+2113, U+2C60-2C7F,
    U+A720-A7FF;
}

/* Tokens. light-dark() picks a value from the active color scheme. */
:root {
  color-scheme: light dark;

  --bg: light-dark(#f0eee6, #1f1e1d);
  --bg-raised: light-dark(#f8f7f3, #292826);
  --text: light-dark(#141413, #e8e6dc);
  --text-muted: light-dark(#5e5d59, #a3a19a);
  --line: light-dark(#d6d3c8, #3a3936);
  --clay: #d97757;
  --clay-ink: light-dark(#a84a29, #e8a58c);
  --underline: light-dark(rgb(217 119 87 / 0.5), rgb(217 119 87 / 0.55));
  --selection: light-dark(rgb(217 119 87 / 0.22), rgb(217 119 87 / 0.35));
  --focus: light-dark(#c15f3c, #d97757);

  --font-serif:
    "Source Serif 4", "Noto Serif SC Subset", "Source Serif Pro", Georgia, Cambria,
    "Times New Roman", "Noto Serif SC", "Noto Serif CJK SC", "Source Han Serif SC", "Songti SC",
    serif;
  --font-mono:
    ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;

  --size-body: clamp(1.125rem, 1.05rem + 0.35vw, 1.25rem);
  --size-title: clamp(2.125rem, 1.6rem + 2vw, 2.75rem);

  --measure: 38rem;
  --gutter: clamp(1.25rem, 5vw, 2rem);
  --motion: 0.15s;
}

:root[data-theme="light"] {
  color-scheme: light;
}

:root[data-theme="dark"] {
  color-scheme: dark;
}

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

[hidden] {
  /* biome-ignore lint/complexity/noImportantStyles: no author display rule may un-hide [hidden] elements (the BibTeX buttons and panels) */
  display: none !important;
}

/*
 * Every page keeps its scrollbar, even one too short to scroll, so the column
 * does not shift sideways when moving between short and long pages. (Overlay
 * scrollbars, as on phones and by default on macOS, take no room either way.)
 */
html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  overflow-y: scroll;
}

body {
  display: flex;
  flex-direction: column;
  min-height: 100svh;
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-serif);
  font-size: var(--size-body);
  line-height: 1.55;
  /* Faux italics look broken, and Chinese has no italics: keep such text upright. */
  font-synthesis: weight;
  hanging-punctuation: first;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

::selection {
  background: var(--selection);
}

:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
  border-radius: 2px;
}

a {
  color: inherit;
  text-decoration-line: underline;
  text-decoration-thickness: max(1px, 0.05em);
  text-decoration-color: var(--underline);
  text-underline-offset: 0.2em;
  transition:
    color var(--motion) ease,
    text-decoration-color var(--motion) ease;
}

a:hover {
  text-decoration-color: var(--clay);
}

h1,
h2,
h3,
h4 {
  font-weight: 600;
  text-wrap: balance;
}

p,
li {
  text-wrap: pretty;
}

/*
 * Text marked as Chinese puts the Chinese font first, so the punctuation it
 * shares with English (“ ” — …) takes Chinese shapes; elsewhere Chinese
 * characters still come from that font, after Source Serif.
 */
[lang|="zh"] {
  font-family: "Noto Serif SC Subset", var(--font-serif);
}

/*
 * Small capitals for labels, dates, and navigation. The font files carry no
 * true small caps, so these are capitals a size smaller, a little heavier to
 * match the color of the text around them, and letterspaced as capitals need.
 */
.site-nav a,
.section__title,
.section__more,
.row__date,
.entry__meta,
.post-meta,
.pub__links,
.label,
.back-link,
.site-footer,
.copy-button,
.prose cite {
  font-size: var(--caps-size, 0.78em);
  font-weight: 540;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.skip-link {
  position: absolute;
  top: 0.75rem;
  left: 0.75rem;
  z-index: 10;
  padding: 0.5rem 0.875rem;
  border-radius: 4px;
  background: var(--text);
  color: var(--bg);
  font-size: 1rem;
  text-decoration: none;
  transform: translateY(-200%);
}

.skip-link:focus {
  transform: none;
}

/* Layout: every page is one centered column. */
.wrap {
  width: 100%;
  max-width: calc(var(--measure) + 2 * var(--gutter));
  margin-inline: auto;
  padding-inline: var(--gutter);
}

main {
  flex: 1;
  padding-block: clamp(3rem, 9vw, 5rem) clamp(4rem, 10vw, 6rem);
}

/* Header */
.site-header {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.25rem 1.5rem;
  padding-top: clamp(1.5rem, 5vw, 2.75rem);
}

.wordmark {
  margin: 0;
  font-size: 1.5em;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.005em;
  text-decoration: none;
}

.wordmark a {
  text-decoration: none;
}

.site-nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 1.35em;
}

.site-nav a {
  padding-block: 0.5em;
  color: var(--text-muted);
  text-decoration-color: transparent;
  text-underline-offset: 0.35em;
}

.site-nav a:hover,
.site-nav a[aria-current] {
  color: var(--text);
}

.site-nav a[aria-current] {
  text-decoration-color: var(--clay);
}

.theme-toggle {
  display: grid;
  place-items: center;
  width: 2.25rem;
  height: 2.25rem;
  margin: 0 -0.5rem 0 -0.25rem;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  transition:
    background-color var(--motion) ease,
    color var(--motion) ease;
}

.theme-toggle:hover {
  background: var(--bg-raised);
  color: var(--text);
}

/* Footer */
.site-footer {
  padding-bottom: clamp(2rem, 6vw, 3rem);
  color: var(--text-muted);
}

.site-footer p {
  margin: 0;
  padding-top: 1.25rem;
  border-top: 1px solid var(--line);
}

.sep {
  margin-inline: 0.25em;
  color: var(--text-muted);
}

/* Page headers */
.page-header {
  margin-bottom: clamp(2.25rem, 6vw, 3.25rem);
}

.page-title,
.post-title {
  margin: 0;
  font-size: var(--size-title);
  line-height: 1.08;
  letter-spacing: -0.012em;
}

.lead,
.post-subtitle {
  font-size: 1.2em;
  font-style: italic;
  line-height: 1.4;
  color: var(--text-muted);
}

.lead {
  margin: 0.9rem 0 0;
}

.tag-list {
  margin: 1.25rem 0 0;
  color: var(--text-muted);
}

.tag-list .label {
  margin-right: 0.6em;
}

.empty {
  color: var(--text-muted);
  font-style: italic;
}

time,
.post-meta a,
.entry__meta a {
  white-space: nowrap;
}

.back-link {
  margin: 3rem 0 0;
  color: var(--text-muted);
}

.back-link a {
  text-decoration-color: transparent;
}

.back-link a:hover {
  color: var(--text);
  text-decoration-color: var(--clay);
}

.back-link a::before {
  content: "← " / "";
}

.page-header .back-link {
  margin-top: 1.25rem;
}

/* Home */
.prose--lead {
  font-size: 1.2em;
  line-height: 1.5;
}

.contact {
  margin: 1.5rem 0 0;
}

.contact__note {
  display: block;
  color: var(--text-muted);
  font-style: italic;
}

.contact a {
  white-space: nowrap;
}

/*
 * The raccoon (static/assets/js/buddy.js) at the right of its own line, with its
 * speech bubble to the left, level with its face. Every sentence is also laid
 * out there invisibly, stacked under the bubble, so the line is always as tall
 * as the longest one at the current width: the bubble never covers other text,
 * and nothing moves when the raccoon speaks.
 */
.buddy {
  --fur: light-dark(#76746e, #9c9a93);
  --mask: light-dark(#2b2a28, #e8e6dc);
  --tail-light: light-dark(#bcb9b0, #55534f);
  display: flex;
  align-items: start;
  gap: 0.6rem;
  margin-top: 0.5rem;
}

.buddy__speech {
  display: grid;
  flex: 1;
  min-width: 0;
  place-items: start end;
  container: buddy-speech / inline-size;
}

.buddy__speech > * {
  grid-area: 1 / 1;
}

.buddy__bubble,
.buddy__sizer {
  max-width: min(24rem, 100%);
  margin: 0;
  padding: 0.4em 0.8em 0.45em;
  border: 1px solid var(--text);
  border-radius: 0.8em;
  font: italic 400 0.9em / 1.35 var(--font-serif);
  text-wrap: balance;
  /* A word too long for the bubble breaks rather than pushing into the raccoon. */
  overflow-wrap: anywhere;
}

/*
 * Chinese has no italics, so it stands upright among the italic English. At
 * the same size and weight its thin strokes look larger and paler than the
 * italic, so it is set a little smaller and heavier to match.
 */
.buddy__bubble [lang|="zh"],
.buddy__sizer [lang|="zh"] {
  font-size: 0.92em;
  font-style: normal;
  font-weight: 500;
}

.buddy__sizer {
  visibility: hidden;
}

/*
 * With too little room beside it (very narrow screens), the raccoon only
 * cheers and sends up a heart: its bubble and the room kept for it go away,
 * and the sentence is left for screen readers alone.
 */
@container buddy-speech (width < 8rem) {
  .buddy__sizer {
    display: none;
  }

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

.buddy__bubble {
  position: relative;
  background: var(--bg-raised);
  color: var(--text);
  pointer-events: none;
  opacity: 0;
  transform: translateY(0.25em);
  transition:
    opacity var(--motion) ease,
    transform var(--motion) ease;
}

.buddy__bubble.is-shown {
  opacity: 1;
  transform: none;
}

/* The bubble's tail points right, at the raccoon's face. */
.buddy__bubble::after {
  content: "";
  position: absolute;
  top: 1em;
  right: 0;
  width: 0.6em;
  height: 0.6em;
  border-right: 1px solid var(--text);
  border-bottom: 1px solid var(--text);
  background: inherit;
  transform: translateX(50%) rotate(-45deg);
}

/*
 * The raccoon's box is sized in the art's own units, 14 columns by 4 lines, and
 * stays invisible until the script draws into it and wakes it: nothing moves
 * when it appears, and without the script there is no button that does nothing.
 */
.buddy__sprite {
  position: relative;
  flex: none;
  width: 14ch;
  height: 4lh;
  padding: 0;
  border: 0;
  background: none;
  color: var(--fur);
  font: 600 0.85em / 1.15 var(--font-mono);
  cursor: pointer;
  /* Taps answer with the raccoon's own cheer: no zoom, highlight, or selection. */
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  -webkit-user-select: none;
  user-select: none;
  visibility: hidden;
}

.buddy.is-awake .buddy__sprite {
  visibility: visible;
}

.buddy__art {
  margin: 0;
  padding: 0;
  overflow: visible;
  border: 0;
  border-radius: 0;
  background: none;
  font: inherit;
}

.buddy__mask {
  border-radius: 0.6em;
  background: var(--mask);
  color: var(--bg);
}

.buddy__mouth {
  color: var(--text);
}

.buddy__tail-dark {
  color: var(--mask);
}

.buddy__tail-light {
  color: var(--tail-light);
}

.buddy__heart {
  position: absolute;
  top: -0.25em;
  left: 10ch;
  color: var(--clay);
  font-size: 1.25em;
  pointer-events: none;
}

/* Sections: a small-capital label over a rule, with an optional link to more. */
.section {
  margin-top: clamp(3.5rem, 9vw, 5rem);
}

.page-header + .section {
  margin-top: 0;
}

.section__header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--text);
}

/* The section's name outranks its "All …" link: larger and heavier. */
.section__title {
  --caps-size: 0.95em;
  margin: 0;
  font-weight: 680;
}

.section__more {
  --caps-size: 0.7em;
  color: var(--text-muted);
  text-decoration-color: transparent;
}

.section__more:hover {
  color: var(--text);
  text-decoration-color: var(--clay);
}

/* Dated rows: news, and the latest posts on the home page */
.rows,
.entries {
  margin: 0;
  padding: 0;
  list-style: none;
}

.row {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0.125rem 1.25rem;
  align-items: baseline;
  padding-block: 0.875rem;
}

/* Rules go between items only; the last one is closed by what follows it. */
.row + .row {
  border-top: 1px solid var(--line);
}

@media (min-width: 36rem) {
  .row {
    grid-template-columns: 6.5em minmax(0, 1fr);
  }
}

.row__date {
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

.row__text {
  margin: 0;
}

/* A list that opens a page starts with the same rule as a section. */
.page-header + .rows,
.page-header + .entries {
  border-top: 1px solid var(--text);
}

/* Post entries: title, description, and a line of details, like a post's header. */
.entry {
  padding-block: 1.5rem;
}

.entry + .entry {
  border-top: 1px solid var(--line);
}

.entry__title {
  margin: 0;
  font-size: 1.2em;
  line-height: 1.3;
}

.entry__title a {
  text-decoration-color: transparent;
}

.entry__title a:hover {
  text-decoration-color: var(--clay);
}

.entry__description {
  margin: 0.3rem 0 0;
  color: var(--text-muted);
  font-style: italic;
}

.entry__meta {
  margin: 0.6rem 0 0;
  color: var(--text-muted);
}

/* Posts */
.post-header {
  margin-bottom: clamp(2.25rem, 6vw, 3rem);
  padding-bottom: 1.25rem;
  border-bottom: 1px solid var(--line);
}

.post-subtitle {
  margin: 1rem 0 0;
}

.post-meta {
  margin: 1.75rem 0 0;
  color: var(--text-muted);
}

/* Long-form text */
.prose > * {
  margin-block: 0;
}

.prose > * + * {
  margin-top: 1em;
}

.prose h2 {
  margin-top: 2em;
  font-size: 1.35em;
  line-height: 1.25;
}

.prose h3 {
  margin-top: 1.75em;
  font-size: 1.1em;
  line-height: 1.3;
}

.prose h2 + *,
.prose h3 + * {
  margin-top: 0.5em;
}

.prose ul,
.prose ol {
  padding-left: 1.25em;
}

/* Where the margins allow, bullets and numbers hang outside the text. */
@media (min-width: 48rem) {
  .prose ul,
  .prose ol {
    padding-left: 0;
  }
}

.prose li + li,
.prose li > ul,
.prose li > ol {
  margin-top: 0.4em;
}

.prose li::marker {
  color: var(--text-muted);
}

.prose blockquote {
  margin-inline: 0;
  padding-left: 1.25em;
  border-left: 2px solid var(--clay);
  font-style: italic;
}

.prose blockquote > * {
  margin: 0;
}

.prose blockquote > * + * {
  margin-top: 0.6em;
}

.prose cite {
  display: block;
  font-style: normal;
  color: var(--text-muted);
}

/* A section break is a centered row of asterisks, as in books. */
.prose hr {
  margin-block: 1.75em;
  border: 0;
  color: var(--text-muted);
  line-height: 1;
  text-align: center;
}

.prose hr::before {
  content: "*\2003*\2003*";
}

.prose img {
  display: block;
  max-width: 100%;
  height: auto;
  border-radius: 4px;
}

.prose table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9em;
  font-variant-numeric: tabular-nums;
}

.prose th,
.prose td {
  padding: 0.5em 0.75em;
  border-bottom: 1px solid var(--line);
  text-align: left;
}

.prose th {
  border-bottom-color: var(--text);
  font-weight: 600;
}

/* Narrow columns rag badly without hyphenation. */
@media (max-width: 40rem) {
  .prose p,
  .prose li {
    hyphens: auto;
    hyphenate-limit-chars: 7 3 3;
  }
}

code,
pre {
  font-family: var(--font-mono);
}

.prose code {
  padding: 0.1em 0.3em;
  border-radius: 3px;
  background: var(--bg-raised);
  font-size: 0.82em;
}

pre {
  margin: 0;
  padding: 1em 1.25em;
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: var(--bg-raised);
  font-size: 0.75em;
  line-height: 1.6;
  tab-size: 2;
}

.prose pre code {
  padding: 0;
  background: none;
  font-size: inherit;
}

.code-block {
  position: relative;
}

.copy-button {
  --caps-size: 0.6875rem;
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  padding: 0.4em 0.7em;
  border: 1px solid var(--line);
  border-radius: 3px;
  background: var(--bg);
  color: var(--text-muted);
  font-family: inherit;
  cursor: pointer;
  opacity: 0;
  transition:
    opacity var(--motion) ease,
    color var(--motion) ease;
}

.copy-button:hover {
  color: var(--text);
}

.code-block:hover .copy-button,
.copy-button:focus-visible {
  opacity: 1;
}

@media (hover: none) {
  .copy-button {
    opacity: 1;
  }
}

/* Math is MathML rendered at build time; browsers draw it natively. */
math {
  font-family: "STIX Two Math", "Cambria Math", math;
  font-size: 1.05em;
}

math.tml-display {
  display: block;
  overflow-x: auto;
  overflow-y: hidden;
}

/* Publications */
.pub-year + .pub-year {
  margin-top: 2.5rem;
}

.pubs {
  margin: 0;
  padding: 0;
  list-style: none;
}

.pub {
  padding-block: 1.25rem;
}

.pub + .pub {
  border-top: 1px solid var(--line);
}

/* Title, then authors, then venue: each a step quieter than the one above. */
.pub__title {
  margin: 0;
  font-size: 1.1em;
  font-weight: 600;
  line-height: 1.3;
}

/* A title links to the paper's PDF, if it has one, underlined only on hover. */
.pub__title a {
  text-decoration-color: transparent;
}

.pub__title a:hover {
  text-decoration-color: var(--clay);
}

.pub__authors {
  margin: 0.3rem 0 0;
  font-size: 0.94em;
}

/* Every coauthor is a link; full-strength underlines would stripe the line. */
.pub__authors a {
  text-decoration-color: var(--line);
}

.pub__authors a:hover {
  text-decoration-color: var(--clay);
}

.pub__authors .self {
  font-weight: 600;
}

.pub__venue {
  margin: 0.1rem 0 0;
  color: var(--text-muted);
  font-size: 0.9em;
  font-style: italic;
}

.pub__links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1.5em;
  margin-top: 0.75rem;
}

.pub__links a {
  text-decoration-color: var(--underline);
}

.text-button {
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  text-decoration-line: underline;
  text-decoration-thickness: max(1px, 0.05em);
  text-decoration-color: var(--underline);
  text-underline-offset: 0.2em;
  cursor: pointer;
  transition: text-decoration-color var(--motion) ease;
}

.text-button:hover,
.text-button[aria-expanded="true"] {
  text-decoration-color: var(--clay);
}

.bibtex {
  margin-top: 0.875rem;
}

.bibtex pre {
  font-size: 0.7em;
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --motion: 0s;
  }
}

/* Chinese: Noto Serif SC, cut down by the build to the characters the site uses. */
@font-face {
  font-family: "Noto Serif SC Subset";
  font-style: normal;
  font-weight: 200 900;
  font-display: swap;
  src: url("../fonts/noto-serif-sc-de7fbff346.woff2") format("woff2");
  unicode-range: U+B7, U+2014, U+2018-2019, U+201C-201D, U+2026, U+3002, U+4E2A, U+4E5F, U+5065, U+592B, U+59CB, U+5B50, U+5DE5, U+5E84, U+6211, U+6253, U+6709, U+672A, U+6E0A, U+7ED9, U+7FBF, U+8005, U+80E1, U+9E23, U+FF0C;
}
