.prose {
  --prose-body: var(--color-text-day);
  --prose-headings: var(--color-text-day);
  --prose-lead: rgba(25, 24, 22, 0.7);
  --prose-links: var(--color-text-day);
  --prose-bold: var(--color-text-day);
  --prose-counters: rgba(25, 24, 22, 0.5);
  --prose-bullets: rgba(25, 24, 22, 0.35);
  --prose-hr: rgba(39, 37, 34, 0.18);
  --prose-quotes: var(--color-text-day);
  --prose-quote-borders: rgba(39, 37, 34, 0.18);
  --prose-captions: rgba(25, 24, 22, 0.6);
  --prose-kbd: var(--color-text-day);
  --prose-kbd-shadows: rgb(28 27 26 / 10%);
  --prose-code: var(--color-text-day);
  --prose-pre-code: rgba(244, 242, 238, 0.9);
  --prose-pre-bg: #1c1b1a;
  --prose-code-muted: rgba(25, 24, 22, 0.55);
  --prose-th-borders: rgba(39, 37, 34, 0.3);
  --prose-td-borders: rgba(39, 37, 34, 0.14);

  color: var(--prose-body);
  line-height: var(--leading-body, 1.6);
}

.theme-night .prose {
  --prose-body: rgba(240, 240, 240, 0.8);
  --prose-headings: #fff;
  --prose-lead: rgba(240, 240, 240, 0.6);
  --prose-links: #fff;
  --prose-bold: #fff;
  --prose-counters: rgba(240, 240, 240, 0.5);
  --prose-bullets: rgba(240, 240, 240, 0.3);
  --prose-hr: rgba(244, 242, 238, 0.18);
  --prose-quotes: rgba(240, 240, 240, 0.9);
  --prose-quote-borders: rgba(244, 242, 238, 0.18);
  --prose-captions: rgba(240, 240, 240, 0.6);
  --prose-kbd: #fff;
  --prose-kbd-shadows: rgb(255 255 255 / 10%);
  --prose-code: #fff;
  --prose-pre-code: rgba(240, 240, 240, 0.8);
  --prose-pre-bg: rgb(0 0 0 / 50%);
  --prose-code-muted: rgba(240, 240, 240, 0.5);
  --prose-th-borders: rgba(244, 242, 238, 0.3);
  --prose-td-borders: rgba(244, 242, 238, 0.14);
}

/* --- Inline -------------------------------------------------------------- */

.prose p {
  margin-top: 1.25em;
  margin-bottom: 1.25em;
}

.prose [class~="lead"] {
  color: var(--prose-lead);
  font-size: var(--font-size-xl, 1.25rem);
  line-height: var(--leading-body, 1.6);
  margin-top: 1.2em;
  margin-bottom: 1.2em;
}

.prose a {
  color: var(--prose-links);
  text-decoration: underline;
  font-weight: 500;
}

/* Keep footnotes, but hide their return links. */
.prose .footnote-backref {
  display: none;
}

.prose strong {
  color: var(--prose-bold);
  font-weight: 600;
}

.prose a strong,
.prose blockquote strong,
.prose thead th strong {
  color: inherit;
}

/* --- Build-time math ----------------------------------------------------- */

.math-inline,
.math-block {
  direction: ltr;
  unicode-bidi: isolate;
}

.prose .math-inline .katex,
.prose .math-block .katex {
  font-size: 1em;
}

.math-block {
  max-width: 100%;
  margin-block: 1.5em;
  padding-block: 0.4em 0.55em;
  overflow-x: auto;
  overflow-y: hidden;
}

.math-block .katex-display {
  margin: 0;
}

/* Keep long equations reachable from the left edge on narrow screens. */
.math-block .katex-display > .katex {
  width: max-content;
  min-width: 100%;
}

/* --- Lists --------------------------------------------------------------- */

.prose ol {
  list-style-type: decimal;
  margin-top: 1.25em;
  margin-bottom: 1.25em;
  padding-inline-start: 1.625em;
}

.prose ol[type="A"],
.prose ol[type="A" s] {
  list-style-type: upper-alpha;
}

.prose ol[type="a"],
.prose ol[type="a" s] {
  list-style-type: lower-alpha;
}

.prose ol[type="I"],
.prose ol[type="I" s] {
  list-style-type: upper-roman;
}

.prose ol[type="i"],
.prose ol[type="i" s] {
  list-style-type: lower-roman;
}

.prose ol[type="1"] {
  list-style-type: decimal;
}

.prose ul {
  list-style-type: disc;
  margin-top: 1.25em;
  margin-bottom: 1.25em;
  padding-inline-start: 1.625em;
}

.prose ol > li::marker {
  font-weight: 400;
  color: var(--prose-counters);
}

.prose ul > li::marker {
  color: var(--prose-bullets);
}

/* The site's legacy letter lists use a custom "•" ::before; prose uses
   native markers instead, so the pseudo-bullet must be suppressed. */
.prose li::before {
  content: none;
}

.prose li {
  margin-top: 0.5em;
  margin-bottom: 0.5em;
}

.prose ol > li,
.prose ul > li {
  padding-inline-start: 0.375em;
}

.prose > ul > li p {
  margin-top: 0.75em;
  margin-bottom: 0.75em;
}

.prose > ul > li > p:first-child,
.prose > ol > li > p:first-child {
  margin-top: 1.25em;
}

.prose > ul > li > p:last-child,
.prose > ol > li > p:last-child {
  margin-bottom: 1.25em;
}

.prose :is(ul ul, ul ol, ol ul, ol ol) {
  margin-top: 0.75em;
  margin-bottom: 0.75em;
}

.prose dl {
  margin-top: 1.25em;
  margin-bottom: 1.25em;
}

.prose dt {
  color: var(--prose-headings);
  font-weight: 600;
  margin-top: 1.25em;
}

.prose dd {
  margin-top: 0.5em;
  padding-inline-start: 1.625em;
}

/* --- Rules & quotes ------------------------------------------------------ */

.prose hr {
  margin-top: 3em;
  margin-bottom: 3em;
  border: 0;
  border-top: 1px solid var(--prose-hr);
}

.prose blockquote {
  font-weight: 500;
  font-style: italic;
  color: var(--prose-quotes);
  border-inline-start: 0.25rem solid var(--prose-quote-borders);
  quotes: "\201C""\201D""\2018""\2019";
  margin-top: 1.6em;
  margin-bottom: 1.6em;
  padding-inline-start: 1em;
}

.prose blockquote p:first-of-type::before {
  content: open-quote;
}

.prose blockquote p:last-of-type::after {
  content: close-quote;
}

/* --- Headings ------------------------------------------------------------ */

.prose h1 {
  color: var(--prose-headings);
  font-weight: 800;
  font-size: var(--font-size-3xl, 2rem);
  margin-top: 0;
  margin-bottom: 0.8888889em;
  line-height: 1.1111111;
}

.prose h1 strong {
  font-weight: 900;
  color: inherit;
}

.prose h2 {
  color: var(--prose-headings);
  font-weight: 700;
  font-size: var(--font-size-2xl, 1.5rem);
  margin-top: 2em;
  margin-bottom: 1em;
  line-height: 1.3333333;
}

.prose h2 strong {
  font-weight: 800;
  color: inherit;
}

.prose h3 {
  color: var(--prose-headings);
  font-weight: 600;
  font-size: var(--font-size-xl, 1.25rem);
  margin-top: 1.6em;
  margin-bottom: 0.6em;
  line-height: 1.6;
}

.prose h3 strong {
  font-weight: 700;
  color: inherit;
}

.prose h4 {
  color: var(--prose-headings);
  font-weight: 600;
  font-size: var(--font-size-lg, 1.125rem);
  margin-top: 1.5em;
  margin-bottom: 0.5em;
  line-height: 1.5;
}

.prose h4 strong {
  font-weight: 700;
  color: inherit;
}

/* --- Media --------------------------------------------------------------- */

.prose img,
.prose video {
  margin-top: 2em;
  margin-bottom: 2em;
}

.prose picture {
  display: block;
  margin-top: 2em;
  margin-bottom: 2em;
}

.prose picture > img {
  margin-top: 0;
  margin-bottom: 0;
}

.prose figure {
  margin-top: 2em;
  margin-bottom: 2em;
}

.prose figure > * {
  margin-top: 0;
  margin-bottom: 0;
}

.prose figcaption {
  color: var(--prose-captions);
  font-size: 0.875em;
  line-height: 1.4285714;
  margin-top: 0.8571429em;
}

/* --- Code ---------------------------------------------------------------- */

.prose kbd {
  font-weight: 500;
  font-family: inherit;
  color: var(--prose-kbd);
  box-shadow:
    0 0 0 1px var(--prose-kbd-shadows),
    0 3px 0 var(--prose-kbd-shadows);
  font-size: 0.875em;
  border-radius: 0.3125rem;
  padding-top: 0.1875em;
  padding-inline-end: 0.375em;
  padding-bottom: 0.1875em;
  padding-inline-start: 0.375em;
}

.prose code {
  color: var(--prose-code);
  font-weight: 600;
  font-size: var(--text-meta, 0.9375rem);
  font-family: var(--mono-font);
}

.prose code::before {
  content: "`";
}

.prose code::after {
  content: "`";
}

.prose a code,
.prose h1 code,
.prose h2 code,
.prose h3 code,
.prose h4 code,
.prose blockquote code,
.prose thead th code {
  color: inherit;
}

.prose h2 code {
  font-size: 0.875em;
}

.prose h3 code {
  font-size: 0.9em;
}

.prose pre {
  color: var(--prose-body);
  background: transparent;
  overflow-x: auto;
  scrollbar-width: thin;
  font-weight: 400;
  /* Departure Mono is drawn on an 11px pixel grid (50 of 550 units per em),
     so 13px is slightly soft. We accept that for readability; the line
     height is still a whole number of pixels to avoid extra vertical blur. */
  font-size: 13px;
  line-height: 24px;
  font-family: var(--mono-font);
  margin-top: 1.625rem;
  margin-bottom: 1.625rem;
  padding-block: 1.5rem;
  padding-inline: 0;
  border-block: 1px solid var(--prose-hr);
  border-radius: 0;
}

.prose pre::-webkit-scrollbar {
  height: 4px;
}

.prose pre::-webkit-scrollbar-track {
  background: transparent;
}

.prose pre::-webkit-scrollbar-thumb {
  background: var(--prose-hr);
}

.prose pre code {
  background-color: transparent;
  border-width: 0;
  border-radius: 0;
  padding: 0;
  font-weight: inherit;
  color: inherit;
  font-size: inherit;
  font-family: inherit;
  line-height: inherit;
}

.prose pre code::before,
.prose pre code::after {
  content: none;
}

/* --- Syntax highlighting ------------------------------------------------- */

/* Rendered at build time (see build.py). Intentionally minimal: text color,
   bold, italic, and a single gray. Comments are gray italic, literals gray,
   keywords bold. */

.prose pre .hl-c {
  color: var(--prose-code-muted);
  font-style: italic;
}

.prose pre .hl-s {
  color: var(--prose-code-muted);
}

/* Departure Mono has no bold cut, and the browser's synthetic bold is a
   sub-pixel smear that shows up on some words and not others. Thicken the
   strokes by one device pixel on 2x screens instead; anything near a full
   font pixel fills the one-pixel counters of m and w. */
.prose pre .hl-k {
  text-shadow: 0.5px 0 0 currentColor;
}

/* --- Marked code reveals ------------------------------------------------- */

/* A fenced code block containing ◊ markers is rendered with this class.
   Its presentation matches ordinary prose code; only the viewport-triggered
   reveal differs. */

.code-reveal__step {
  opacity: 1;
}

.code-reveal.is-reveal-ready {
  opacity: 0;
}

.code-reveal.is-reveal-ready .code-reveal__step {
  opacity: 0;
}

.code-reveal.is-reveal-ready.is-revealed {
  opacity: 1;
  transition: opacity 540ms ease-out;
}

/* Each ◊-delimited chunk appears as a unit. The build step assigns the delay;
   there is no typewriter timer mutating the code one character at a time. */
.code-reveal.is-revealed .code-reveal__step {
  opacity: 1;
  transition: opacity 1ms steps(1, end) var(--reveal-delay);
}

@media print, (prefers-reduced-motion: reduce) {
  .code-reveal.is-reveal-ready,
  .code-reveal.is-reveal-ready .code-reveal__step {
    opacity: 1;
    transition: none;
  }
}

/* --- Pi session replays ------------------------------------------------- */

/* A terminal-like panel replaying a Pi session (see script.js). The colors
   are Pi's own light and dark TUI themes, so the replay reads like Pi. The
   chat area has a fixed height and scrolls like a terminal, so the page does
   not shift while the replay grows. */

.pi-replay {
  --pi-bg: #f7f6f6;
  --pi-text: #3b3f41;
  --pi-muted: #677176;
  --pi-dim: #879095;
  --pi-accent: #7459b4;
  --pi-success: #337e58;
  --pi-warning: #8f6802;
  --pi-border: #a2b7e0;
  --pi-user-bg: #dfe7ec;
  --pi-tool-pending-bg: #e4e5e6;
  --pi-tool-success-bg: #dee9e1;
  --pi-md-code: #7459b4;
  --pi-syn-keyword: #2f7899;
  --pi-syn-function: #8f6802;
  --pi-syn-string: #a45417;
  --pi-syn-number: #337e58;
  --pi-syn-comment: #677176;
  --pi-syn-punctuation: #677176;
}

.theme-night .pi-replay {
  --pi-bg: #21252c;
  --pi-text: #dee0e1;
  --pi-muted: #9da5a9;
  --pi-dim: #7e888e;
  --pi-accent: #a798d7;
  --pi-success: #68b78d;
  --pi-warning: #cd9a22;
  --pi-border: #6185cc;
  --pi-user-bg: #213b49;
  --pi-tool-pending-bg: #34383a;
  --pi-tool-success-bg: #254131;
  --pi-md-code: #a798d7;
  --pi-syn-keyword: #69add0;
  --pi-syn-function: #cd9a22;
  --pi-syn-string: #de8d5a;
  --pi-syn-number: #68b78d;
  --pi-syn-comment: #9da5a9;
  --pi-syn-punctuation: #9da5a9;
}

.prose .pi-replay__fallback {
  white-space: pre-wrap;
}

.pi-replay__terminal {
  display: flex;
  flex-direction: column;
  padding: 12px 14px 10px;
  border: 1px solid var(--prose-hr);
  border-radius: 4px;
  background: var(--pi-bg);
  color: var(--pi-text);
  font-family: var(--mono-font);
  font-size: 0.75rem;
  line-height: 1.5;
  text-align: left;
}

.pi-replay__chat {
  height: 30rem;
  max-height: 70vh;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--pi-dim) transparent;
}

.pi-replay__chat > * + * {
  margin-top: 1.5em;
}

.pi-replay__user {
  padding: 0.75em 1ch;
  background: var(--pi-user-bg);
}

.pi-replay__assistant {
  padding: 0 1ch;
}

.pi-replay__tool {
  padding: 0.75em 1ch;
  background: var(--pi-tool-pending-bg);
  transition: background-color 400ms ease-out;
}

.pi-replay__tool.is-success {
  background: var(--pi-tool-success-bg);
}

.pi-replay__tool-title {
  font-weight: 700;
}

.prose .pi-replay__code,
.prose .pi-replay__output {
  margin: 0;
  padding: 0;
  border: 0;
  overflow: visible;
  color: inherit;
  font-size: inherit;
  line-height: inherit;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.prose .pi-replay__output {
  margin-top: 1.5em;
  color: var(--pi-muted);
}

.pi-replay__calls {
  margin-top: 1.5em;
  overflow-wrap: anywhere;
}

.pi-replay__call {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.pi-replay__muted { color: var(--pi-muted); }
.pi-replay__dim { color: var(--pi-dim); }
.pi-replay__ok { color: var(--pi-success); }
.pi-replay__running { color: var(--pi-warning); }
.pi-replay__syn-k { color: var(--pi-syn-keyword); }
.pi-replay__syn-f { color: var(--pi-syn-function); }
.pi-replay__syn-s { color: var(--pi-syn-string); }
.pi-replay__syn-n { color: var(--pi-syn-number); }
.pi-replay__syn-c { color: var(--pi-syn-comment); }
.pi-replay__syn-p { color: var(--pi-syn-punctuation); }

.prose .pi-replay__answer :where(p, ul) {
  margin: 0;
}

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

.prose .pi-replay__answer ul {
  padding-inline-start: 2ch;
  list-style: none;
}

.prose .pi-replay__answer li {
  position: relative;
  margin: 0;
  padding: 0;
}

.prose .pi-replay__answer li::before {
  content: "-";
  position: absolute;
  left: -2ch;
  color: var(--pi-accent);
}

.prose .pi-replay__answer b {
  font-weight: 700;
}

.prose .pi-replay__answer code {
  color: var(--pi-md-code);
  font-size: inherit;
  font-weight: inherit;
}

.prose .pi-replay__answer code::before,
.prose .pi-replay__answer code::after {
  content: none;
}

.pi-replay__status {
  margin-top: 0.75em;
  padding: 0 1ch;
  visibility: hidden;
}

.pi-replay__status.is-active {
  visibility: visible;
}

.pi-replay__spinner {
  color: var(--pi-accent);
}

.pi-replay__editor {
  margin-top: 0.75em;
  padding: 0.25em 1ch;
  border-block: 1px solid var(--pi-border);
  min-height: 1.5em;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.pi-replay__cursor {
  background: var(--pi-text);
  animation: pi-replay-blink 1s steps(1, end) infinite;
}

@keyframes pi-replay-blink {
  50% { background: transparent; }
}

.pi-replay__footer {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0 2ch;
  margin-top: 0.5em;
  color: var(--pi-dim);
}

.pi-replay__button {
  margin-inline-start: 1ch;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-decoration: underline;
  cursor: pointer;
}

@media (max-width: 520px) {
  .pi-replay__terminal {
    padding-inline: 10px;
    font-size: 0.6875rem;
  }

  .pi-replay__chat {
    height: 26rem;
  }
}

@media print, (prefers-reduced-motion: reduce) {
  .pi-replay__cursor {
    animation: none;
  }
}

/* --- Tables -------------------------------------------------------------- */

.prose table {
  width: 100%;
  table-layout: auto;
  border-collapse: collapse;
  margin-top: 2em;
  margin-bottom: 2em;
  font-size: 0.875em;
  line-height: 1.7142857;
}

.prose thead {
  border-bottom: 1px solid var(--prose-th-borders);
}

.prose thead th {
  color: var(--prose-headings);
  font-weight: 600;
  vertical-align: bottom;
  padding-inline-end: 0.5714286em;
  padding-bottom: 0.5714286em;
  padding-inline-start: 0.5714286em;
}

.prose thead th:first-child {
  padding-inline-start: 0;
}

.prose thead th:last-child {
  padding-inline-end: 0;
}

.prose tbody tr {
  border-bottom: 1px solid var(--prose-td-borders);
}

.prose tbody tr:last-child {
  border-bottom-width: 0;
}

.prose tbody td {
  vertical-align: baseline;
}

.prose tbody td,
.prose tfoot td {
  padding-top: 0.5714286em;
  padding-inline-end: 0.5714286em;
  padding-bottom: 0.5714286em;
  padding-inline-start: 0.5714286em;
}

.prose tbody td:first-child,
.prose tfoot td:first-child {
  padding-inline-start: 0;
}

.prose tbody td:last-child,
.prose tfoot td:last-child {
  padding-inline-end: 0;
}

.prose tfoot {
  border-top: 1px solid var(--prose-th-borders);
}

.prose tfoot td {
  vertical-align: top;
}

.prose :is(th, td) {
  text-align: start;
}

/* --- Terminal recordings ------------------------------------------------ */

/* asciinema recordings embedded as <figure data-asciicast> (see script.js).
   The chapter list is the no-JS fallback; the enhanced figure shows the
   player and a caption for the current chapter instead. Recordings use Pi's
   dark TUI theme, so the terminal stays dark in both site themes, with
   Ghostty's Rapture colors for the terminal itself. */

@font-face {
  font-family: 'Commit Mono';
  src: url('https://earendil.com/static/fonts/CommitMono-400-Regular.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Commit Mono';
  src: url('https://earendil.com/static/fonts/CommitMono-400-Italic.woff2') format('woff2');
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}

@font-face {
  font-family: 'Commit Mono';
  src: url('https://earendil.com/static/fonts/CommitMono-700-Regular.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Commit Mono';
  src: url('https://earendil.com/static/fonts/CommitMono-700-Italic.woff2') format('woff2');
  font-weight: 700;
  font-style: italic;
  font-display: swap;
}

.ap-player.asciinema-player-theme-pi {
  /* Ghostty's "Rapture" theme. Two classes to beat the player's own
     .ap-player defaults, which load later. */
  --term-color-foreground: #c0c9e5;
  --term-color-background: #111e2a;
  --term-color-0: #000000;
  --term-color-1: #fc644d;
  --term-color-2: #7afde1;
  --term-color-3: #fff09b;
  --term-color-4: #6c9bf5;
  --term-color-5: #ff4fa1;
  --term-color-6: #64e0ff;
  --term-color-7: #c0c9e5;
  --term-color-8: #304b66;
  --term-color-9: #fc644d;
  --term-color-10: #7afde1;
  --term-color-11: #fff09b;
  --term-color-12: #6c9bf5;
  --term-color-13: #ff4fa1;
  --term-color-14: #64e0ff;
  --term-color-15: #ffffff;
}

.asciicast.is-enhanced .asciicast__chapters {
  display: none;
}

/* Reserve the 80x24 terminal's shape while the player loads. */
.asciicast__player {
  min-height: 2rem;
  border-radius: 4px;
  overflow: hidden;
  background: #111e2a;
}

.asciicast__player:empty {
  aspect-ratio: 80 / 40;
}

.asciicast__player .ap-wrapper,
.asciicast__player .ap-player {
  border-radius: 0;
}

/* Room for two lines, so a longer caption does not move the page. */
.page--post-detail .post-figure .asciicast__caption {
  min-height: 2.7em;
  margin-top: 10px;
}

/* Shown while playback holds at a chapter: a short bar that fills to the
   right until playback continues. */
.asciicast__countdown {
  display: inline-block;
  position: relative;
  width: 2em;
  height: 2px;
  margin-inline-start: 0.6em;
  vertical-align: middle;
  overflow: hidden;
  background: var(--prose-hr);
  visibility: hidden;
}

.asciicast__countdown::after {
  content: "";
  position: absolute;
  inset: 0;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left center;
}

.asciicast.is-counting-down .asciicast__countdown {
  visibility: visible;
}

.asciicast.is-counting-down .asciicast__countdown::after {
  animation: asciicast-countdown var(--asciicast-pause, 2500ms) linear forwards;
}

@keyframes asciicast-countdown {
  to {
    transform: scaleX(1);
  }
}

@media (prefers-reduced-motion: reduce) {
  .asciicast.is-counting-down .asciicast__countdown::after {
    animation: none;
    transform: scaleX(1);
  }
}

/* --- Rhythm guards --------------------------------------------------------
   Collapse double spacing: nothing above the first child, nothing below
   the last, and no top margin on whatever follows a heading or rule. */

.prose > :first-child {
  margin-top: 0;
}

.prose > :last-child {
  margin-bottom: 0;
}

.prose :is(hr, h2, h3, h4) + * {
  margin-top: 0;
}
