/* Notebook look for the Blogs list and every post. Loaded after theme.css. */
body.paper {
  background-color: var(--paper);
  background-image: linear-gradient(var(--grid) 1px, transparent 1px), linear-gradient(90deg, var(--grid) 1px, transparent 1px);
  background-size: 32px 32px;
  color: var(--ink);
}
.page { max-width: var(--page-max); margin: 0 auto; padding: 0 clamp(1rem, 4vw, var(--pad-r)) 4rem clamp(1.25rem, 6vw, var(--pad-l)); position: relative; }
/* The post shell. Wide enough for the three columns and their gaps and not a
   millimetre wider, and with the padding held at the tokens rather than left on vw,
   so that above the breakpoint the content group is exactly the page's content box:
   the contents list starts where the header starts and the margin column ends where
   it ends, at every width, with the spare space even on both sides. */
@media (min-width: 88rem) {
  body.post .page {
    max-width: var(--page-post);
    padding-left: var(--pad-l); padding-right: var(--pad-r);
  }
}
.page::before { content: ""; position: absolute; top: 0; bottom: 0; left: clamp(0.5rem, 3vw, 3rem); width: 2px; background: var(--burgundy); opacity: var(--margin-line-opacity); }
body.paper .top .brand, body.paper .top nav a { color: var(--ink); }

/* ---------- Blogs list ---------- */
.list-head h1 { font: 700 clamp(2.5rem, 7vw, 4.5rem)/1 var(--serif); letter-spacing: -0.02em; margin: 0.5rem 0 0.75rem; color: var(--ink); }
.list-head p { margin: 0 0 1.25rem; color: var(--soft); max-width: 56ch; font-family: var(--serif); font-size: 1.125rem; }
/* Eleven chips, which is every category any post uses, so the row has to be
   compact enough to read at a glance: two lines on a laptop, no more than four on a
   phone. The saving is horizontal, in the padding and the gap, because that is what
   decides how many fit on a line. The vertical padding is left alone and the box is
   given a slightly larger hit area than it paints, so a smaller chip is not a
   smaller thing to hit; the row gap is wider than that reach, so no two chips ever
   claim the same pixel. */
.chips { display: flex; flex-wrap: wrap; gap: 0.4rem 0.35rem; margin: 0 0 1.5rem; padding: 0; list-style: none; }
.chip { font: 500 0.875rem var(--sans); padding: 0.2rem 0.45rem; border: 1.5px solid var(--soft); background: transparent; color: var(--ink); cursor: pointer; position: relative; }
.chip::before { content: ""; position: absolute; inset: -3px -1px; }
/* Selected. The highlighter fill alone is only 1.8:1 against the page, which is not
   enough on its own to say which chips are on, so the border goes to the body colour
   as well: fill and edge both change, and the edge is the one that carries. */
.chip[aria-pressed="true"] { background: var(--mark); border-color: var(--ink); color: var(--ink); }
.chip:hover { border-color: var(--burgundy); }
.posts { list-style: none; padding: 0; margin: 0; border-top: 2px solid var(--ink); }
.post-row { display: grid; grid-template-columns: 9rem minmax(0, 1fr); gap: 0.25rem 1.5rem; padding: 1.25rem 0; border-bottom: 1px solid var(--rule); background: color-mix(in srgb, var(--paper) 88%, transparent); }
/* The date is optional, so the row cannot rely on counting its children: both cells
   are placed by name. A row with no date leaves the first column empty rather than
   moving into it, so every title on the list starts on the same line down the page,
   dated or not, and nothing is printed where the date would have been. */
.post-row time { grid-column: 1; grid-row: 1; font: 500 0.9375rem var(--sans); color: var(--soft); font-variant-numeric: tabular-nums; padding-top: 0.25rem; }
.post-row-body { grid-column: 2; grid-row: 1; }
/* Written, not typeset: this is the one number on the row that somebody noted down.
   calc rather than em, because the date is set smaller than the row it sits in and
   an em here would measure against the row. */
.post-row time { font-family: var(--hand); font-weight: 400; font-size: calc(0.9375rem * var(--hand-grow-ui)); }
.post-row h2 { font: 600 1.5rem/1.25 var(--serif); margin: 0; }
.post-row h2 a { color: var(--ink); text-decoration: none; }
.post-row h2 a:hover { background: var(--mark); }
.post-row .cats { margin: 0.35rem 0 0; display: flex; flex-wrap: wrap; gap: 0.25rem 0.75rem; font: 500 0.875rem var(--sans); color: var(--burgundy); }

/* ---------- Post ---------- */
/* The head is not in the column grid below it, so it is moved across to start
   where the article starts. Left at the page's own edge it would sit across the
   contents column and the article both and line up with neither. */
.post-head { padding: 1rem 0 1.5rem; max-width: var(--article); margin-left: calc(var(--toc-col) + var(--gap)); }
.post-head h1 { font: 700 clamp(2.25rem, 6vw, 3.75rem)/1.05 var(--serif); letter-spacing: -0.02em; margin: 0 0 0.75rem; color: var(--ink); text-wrap: balance; }
.meta { font: 500 0.9375rem var(--sans); color: var(--soft); display: flex; flex-wrap: wrap; gap: 0.25rem 1.25rem; }
.meta .cats { color: var(--burgundy); }

/* Three columns: the contents list, the article, the margin notes. Each has one of
   its own, so the list never has to be moved out of a note's way and every post is
   laid out the same whether it has notes or not. Both cells are placed by name
   rather than by order, because the article is the middle column even on a post
   with no headings, where the first column is simply empty.
   The list's rule is on its inner edge, facing the article, which is the edge a
   margin note rules too: the two side columns are a pair, and the page's own pink
   line is already doing the ruling on the outside. */
.post-layout { display: grid; grid-template-columns: var(--toc-col) minmax(0, var(--article)) var(--margin-col); gap: 0 var(--gap); align-items: start; }
.toc { grid-column: 1; grid-row: 1; position: sticky; top: 1rem; font: 400 0.9375rem/1.4 var(--sans); border-right: 2px solid var(--burgundy); padding-right: 0.75rem; }
.toc strong { display: block; font-weight: 600; margin-bottom: 0.4rem; color: var(--ink); }
.toc ol { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.35rem; }
.toc a { color: var(--soft); text-decoration: none; }
.toc a:hover, .toc a[aria-current] { color: var(--ink); text-decoration: underline; text-decoration-color: var(--accent-line); text-decoration-thickness: 2px; }

.article { grid-column: 2; grid-row: 1; font: 400 1.1875rem/1.7 var(--serif); color: var(--ink); min-width: 0; }
.article > :first-child { margin-top: 0; }
.article h2 { font: 600 1.75rem/1.25 var(--serif); margin: 2.5rem 0 0.75rem; color: var(--ink); text-wrap: balance; }
.article h3 { font: 600 1.375rem/1.3 var(--serif); margin: 2rem 0 0.5rem; color: var(--ink); }
.article p { margin: 0 0 1.1rem; max-width: var(--measure); }
.article a { color: var(--primary); }
.article a:hover { background: var(--mark); color: var(--ink); }
.article ul, .article ol { max-width: var(--measure); padding-left: 1.4rem; margin: 0 0 1.1rem; }
.article li { margin-bottom: 0.3rem; }
.article code { font: 0.9em var(--mono); background: color-mix(in srgb, var(--primary) 12%, transparent); padding: 0.1em 0.3em; }
.article blockquote { margin: 1.25rem 0; padding: 0 0 0 1rem; border-left: 3px solid var(--soft); color: var(--soft); max-width: var(--measure); }
.article img { max-width: 100%; height: auto; }
.article table { border-collapse: collapse; font: 0.9375rem var(--sans); margin: 0 0 1.25rem; }
.article th, .article td { border-bottom: 1px solid var(--rule); padding: 0.4rem 0.9rem 0.4rem 0; text-align: left; }
.table-wrap { overflow-x: auto; max-width: 100%; }

/* Display and inline maths (rendered by KaTeX in the real build) */
.math-display { overflow-x: auto; padding: 0.25rem 0; margin: 0 0 1.1rem; font-size: 1.15em; }

/* Margin notes: into the margin column on wide screens, inline blocks below that.
   The note's right edge lines up with the right edge of the margin column, so the
   negative margin is the column plus the gap, and its top is pulled up slightly to
   sit level with the end of the paragraph it annotates rather than below it. */
.margin {
  float: right; clear: right; width: var(--margin-col);
  margin: -0.4rem calc(-1 * (var(--margin-col) + var(--gap))) 1rem 1rem;
  font: 400 1rem/1.55 var(--serif); color: var(--burgundy);
  border-left: 2px solid var(--burgundy); padding-left: 0.75rem;
}
/* A note in the margin is the clearest case of a hand on the page: it is not part
   of the text, it is somebody writing beside it. The slope replaces the italic the
   serif note used to carry, which the hand has no cut for anyway and which a browser
   would otherwise fake by shearing it. The leading is a notch looser than the serif
   note's, because this face descends further than Spectral does.
   The tilt is a transform, so it moves nothing: the note still floats level with the
   paragraph it annotates and still ends at the right edge of the margin column. */
.margin {
  font-family: var(--hand); font-size: calc(1rem * var(--hand-grow));
  letter-spacing: var(--track-small);
  transform: rotate(var(--hand-tilt));
}
.margin :first-child { margin-top: 0; }
.margin :last-child { margin-bottom: 0; }

/* Callouts (Quarto's callout-note and friends).
   The box takes the serif measure and the sentences inside it take the sans one, so
   the lines are the right length and a display equation in a callout still has most
   of the article column to fit itself into. */
.callout { margin: 1.5rem 0; padding: 0.9rem 1.1rem; border-left: 4px solid var(--accent-line); background: color-mix(in srgb, var(--panel) 85%, transparent); max-width: var(--measure); font-family: var(--sans); font-size: 1rem; line-height: 1.55; }
.callout > strong { display: block; margin-bottom: 0.25rem; font-weight: 600; }
.callout p { margin: 0 0 0.5rem; max-width: var(--measure-ui); }
.callout p:last-child { margin: 0; }

/* Code cells */
.cell { margin: 1.5rem 0; max-width: 100%; }
.cell pre { margin: 0; padding: 0.9rem 1rem; overflow-x: auto; background: var(--panel); border: 1px solid var(--rule); border-left: 4px solid var(--primary); font: 0.875rem/1.55 var(--mono); color: var(--ink); }
.cell pre code { background: none; padding: 0; font: inherit; }
.cell .out { margin: 0; padding: 0.75rem 1rem; overflow-x: auto; font: 0.8125rem/1.5 var(--mono); color: var(--soft); border-left: 4px solid var(--rule); background: transparent; white-space: pre-wrap; }
.tok-kw { color: var(--burgundy); font-weight: 600; }
.tok-fn { color: var(--primary); }
.tok-str { color: var(--tok-str); }
.tok-num { color: var(--tok-num); }
.tok-com { color: var(--soft); font-style: italic; }

/* Figures, including Plotly */
figure.plot { margin: 1.75rem 0; max-width: 100%; }
figure.plot .plotly-host { width: 100%; min-height: 320px; }
figure.plot figcaption { font: 400 0.9375rem/1.5 var(--sans); color: var(--soft); margin-top: 0.4rem; }
.plot-fallback { font: 0.9375rem var(--sans); color: var(--soft); }

.footnotes { font: 400 0.9375rem/1.5 var(--sans); color: var(--soft); border-top: 1px solid var(--rule); margin-top: 3rem; padding-top: 1rem; max-width: var(--measure-ui); }
.pager { display: flex; justify-content: space-between; gap: 1rem; margin: 3rem 0 0; font: 500 1rem var(--sans); max-width: var(--article); }

/* One column below 88rem (1408px), which is where the three columns stop fitting:
   the arithmetic is against --page-post in theme.css. The contents list becomes a
   disclosure above the article, closed, and a note drops in under the paragraph it
   annotates. There is no width in between where the margin column is narrower than
   --margin-col, because the article column is the one that gives way first. */
@media (max-width: 87.9375rem) {
  /* Still capped at --article, not 1fr: a reading column that grew to the full
     width of a 1024px window would put the maths and the code on a longer line
     than the same post shows on a 1440px one. */
  .post-layout { grid-template-columns: minmax(0, var(--article)); }
  .post-head { margin-left: 0; }
  .toc {
    grid-column: 1; grid-row: auto; position: static; margin-bottom: 1.5rem;
    border-right: 0; padding-right: 0;
    border-left: 2px solid var(--burgundy); padding-left: 0.75rem;
  }
  .article { grid-column: 1; grid-row: auto; }
  .margin { float: none; clear: none; width: auto; margin: 0.5rem 0 1.25rem; }
}
@media (max-width: 640px) {
  .post-row { grid-template-columns: minmax(0, 1fr); }
  .post-row time, .post-row-body { grid-column: 1; grid-row: auto; }
}

/* ======================================================================
   Everything below is for the elements the build produces that the
   reference page does not show by hand: deeper headings, folded code,
   saved notebook images, the table of contents control, the pager, the
   filter on the Blogs list, and KaTeX. The reference above still decides
   the look; this only carries it to the rest of the page.
   ====================================================================== */

/* ---------- Type ----------
   Tracking is a function of size. Headings tighten as they grow, serif body copy
   sits at zero, and the small sans interface text opens up a little so it stays
   legible at 0.9rem. */
.article { letter-spacing: var(--track-body); }
/* A shell command or a URL written inline has no spaces to break at, so on a phone
   it would push the whole page sideways. It wraps instead; only the display maths
   and the code blocks scroll, and they scroll inside their own box. */
.article code, .article a { overflow-wrap: break-word; }
.article h2 { letter-spacing: -0.01em; }
.article h3 { letter-spacing: -0.005em; }
.article h4 { font: 600 1.1875rem/1.35 var(--serif); letter-spacing: var(--track-head); margin: 1.75rem 0 0.4rem; color: var(--ink); }
.article h5 { font: 600 1.0625rem/1.4 var(--sans); letter-spacing: var(--track-head); margin: 1.5rem 0 0.35rem; color: var(--ink); }
.article h6 { font: 600 0.9375rem/1.4 var(--sans); letter-spacing: var(--track-small); margin: 1.25rem 0 0.35rem; color: var(--soft); text-transform: uppercase; }
.meta, .toc, .post-row time, .chip, figure.plot figcaption, .article figcaption,
.footnotes, .pager, .post-filter { letter-spacing: var(--track-small); }

.article hr { border: 0; border-top: 1px solid var(--rule); margin: 2rem 0; max-width: var(--measure); }
.article dl { max-width: var(--measure); }
.article dt { font-weight: 600; margin-top: 0.75rem; }
.article dd { margin: 0 0 0.5rem 1.4rem; }
.article li > p { margin-bottom: 0.5rem; }
.article .contains-task-list { list-style: none; padding-left: 0.25rem; }
.article .task-list-item input { margin-right: 0.5rem; }
.article sup { line-height: 0; }

/* ---------- Callouts ----------
   The kind is carried by the left rule, because colour alone should not be the
   only thing that tells a warning from a note. */
.callout-note { border-left-color: var(--primary); }
.callout-tip { border-left-color: var(--burgundy); }
.callout-warning, .callout-caution { border-left-color: var(--accent-line); }
.callout-important { border-left-color: var(--mark); }
/* The title of a callout is the label somebody wrote on the box, so it is written
   too. No tilt: a heading that sits straight above its own paragraphs is a label,
   and tilting it would make the box look knocked rather than annotated. Patrick Hand
   has no bold, so the weight goes back to 400 instead of being faked, and the title
   earns its place in the size instead. */
.callout > strong {
  font-family: var(--hand); font-weight: 400;
  font-size: calc(1em * var(--hand-grow-ui));
  letter-spacing: var(--track-small); line-height: 1.4;
}
.callout .math-display { margin-bottom: 0; }

/* ---------- Tables ----------
   Notebook tables are wide, so the wrapper scrolls rather than the page. */
.table-wrap { overflow-x: auto; max-width: 100%; margin: 0 0 1.25rem; }
.table-wrap table { margin: 0; min-width: min(100%, 24rem); }
.article thead th { border-bottom: 2px solid var(--ink); font-weight: 600; white-space: nowrap; }
.article tbody tr:last-child td { border-bottom: 0; }
.article td, .article th { font-variant-numeric: tabular-nums; }

/* ---------- Code cells ----------
   A cell holds its input and its outputs together, so the left rules line up and
   read as one unit. */
.cell > * + * { margin-top: 0; }
.cell details.code-fold { margin: 0; }
.cell details.code-fold > summary {
  font: 500 0.875rem/1.5 var(--sans); letter-spacing: var(--track-small);
  color: var(--soft); cursor: pointer; padding: 0.3rem 0 0.3rem 0.75rem;
  border-left: 4px solid var(--rule); list-style: none;
}
.cell details.code-fold > summary::-webkit-details-marker { display: none; }
.cell details.code-fold > summary::before { content: "\25B8\00a0"; display: inline-block; transition: transform 140ms ease-out; }
.cell details.code-fold[open] > summary::before { transform: rotate(90deg); }
.cell details.code-fold > summary:hover { color: var(--ink); border-left-color: var(--burgundy); }
/* The panel grows from nothing rather than appearing: short enough to interrupt. */
.cell details.code-fold[open] > pre { animation: unfold 140ms ease-out; }
@keyframes unfold { from { opacity: 0; transform: translateY(-2px); } to { opacity: 1; transform: none; } }
.cell .out + .out { border-top: 1px solid var(--rule); }

/* ---------- Saved outputs ----------
   Matplotlib draws on white, so in dark mode the figure sits on its own white
   panel instead of glowing against the page. */
.output-img { display: block; max-width: 100%; height: auto; margin: 0.75rem 0; }
.output-svg { overflow-x: auto; }
:root[data-theme="dark"] .output-img { background: #FFFFFF; padding: 0.5rem; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .output-img { background: #FFFFFF; padding: 0.5rem; } }
.article figure { margin: 1.5rem 0; max-width: 100%; }
.article figcaption { font: 400 0.9375rem/1.5 var(--sans); color: var(--soft); margin-top: 0.4rem; }

/* ---------- Maths ----------
   An equation gets the whole article column, and three things happen in order so
   that it is never cut off. It wraps where KaTeX allows a break. What cannot wrap
   is scaled down to the column by math.js, which sets the size inline and never
   goes below three quarters of normal. Only what is still too wide at that size
   scrolls, inside its own box, never the page. No transition on any of it: the
   size is a fact about the column, not a change to animate. */
.math-display { overflow-x: auto; overflow-y: hidden; padding: 0.35rem 0.1rem; max-width: 100%; }
.math-display .katex-display { margin: 0; transition: none; }
.math-display .katex-display > .katex { white-space: normal; }
.katex { font-size: 1.05em; }
.math-inline { white-space: nowrap; }
.katex-error { color: var(--burgundy); }

/* An equation that has to scroll, which should be rare.
   KaTeX centres display maths, so a centred equation that overflows puts the start
   of the line out of reach on the left: left-align it the moment it scrolls. The
   fade says there is more in the direction it fades, and math.js turns each edge on
   and off as the box is scrolled, so a box scrolled to the end is not pretending it
   has more to show. */
.math-display.scrolls .katex-display,
.math-display.scrolls .katex-display > .katex { text-align: left; }
.math-display.scrolls[data-edge~="right"] {
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 2.5rem), transparent);
  mask-image: linear-gradient(to right, #000 calc(100% - 2.5rem), transparent);
}
.math-display.scrolls[data-edge~="left"] {
  -webkit-mask-image: linear-gradient(to right, transparent, #000 2.5rem);
  mask-image: linear-gradient(to right, transparent, #000 2.5rem);
}
.math-display.scrolls[data-edge~="left"][data-edge~="right"] {
  -webkit-mask-image: linear-gradient(to right, transparent, #000 2.5rem, #000 calc(100% - 2.5rem), transparent);
  mask-image: linear-gradient(to right, transparent, #000 2.5rem, #000 calc(100% - 2.5rem), transparent);
}
/* It takes the keyboard, because a box only a pointer can scroll hides its right
   hand side from anyone not using one. */
.math-display.scrolls:focus-visible { outline: 3px solid var(--burgundy); outline-offset: 1px; }

/* ---------- Table of contents ----------
   A sticky column left of the article above the breakpoint; a disclosure above the
   article below it. post.js sets `open` to match the viewport. */
.toc-panel > summary {
  font: 600 0.9375rem/1.4 var(--sans); color: var(--ink); cursor: pointer;
  list-style: none; padding: 0.15rem 0; display: block;
}
.toc-panel > summary::-webkit-details-marker { display: none; }
/* However long the post, the sticky list is never taller than the window: past
   that it scrolls inside itself, and post.js keeps the entry for the section being
   read inside the part of it you can see. The scroll stops at the list rather than
   handing what is left of it to the page behind. */
.toc { max-height: calc(100vh - 2rem); overflow-y: auto; overscroll-behavior: contain; scrollbar-width: thin; }
.toc ol { margin-top: 0.4rem; }
.toc .toc-l3 a { padding-left: 0.85rem; font-size: 0.9em; }
.toc a { display: block; padding: 0.05rem 0; }
.toc a[aria-current="true"] { color: var(--ink); text-decoration: underline; text-decoration-color: var(--accent-line); text-decoration-thickness: 2px; }
.toc a:active { color: var(--ink); }
/* Beside the article the list needs no handle: it is simply there, and the one line
   of it that is not a heading of the post goes away. The markup ships closed, so a
   reader with no JavaScript gets the handle in either layout and nothing is left
   hidden behind a script that did not run. */
.toc-panel[open] > summary { display: none; }

/* The breakpoint a second time, for the rules just above: the columns are set at
   the top of this file, and these are the list's own. A disclosure above the
   article has no window to fit into and nothing to scroll inside, and it keeps the
   handle it is opened by. Opening it is the one piece of motion on the list: the
   entries arrive with the same nudge the folded code uses, and closing it again
   part way through simply takes them away. */
@media (max-width: 87.9375rem) {
  .toc { max-height: none; overflow: visible; }
  .toc-panel[open] > summary { display: block; }
  .toc-panel[open] > ol { animation: unfold 140ms ease-out; }
}

/* ---------- Pager ---------- */
.pager { align-items: stretch; border-top: 1px solid var(--rule); padding-top: 1rem; }
.pager a { text-decoration: none; color: var(--ink); max-width: 15rem; display: block; padding: 0.35rem 0.5rem; border: 1.5px solid transparent; }
.pager a span { display: block; font: 500 0.8125rem var(--sans); letter-spacing: var(--track-small); color: var(--soft); text-transform: uppercase; }
.pager a:hover { border-color: var(--burgundy); }
.pager .pager-next { text-align: right; }
.pager .pager-all { align-self: center; color: var(--primary); }
.pager-gap { flex: 0 0 1rem; }
.pager a { transition: transform 100ms ease-out, border-color 100ms ease-out, background-color 100ms ease-out; }
.pager a:active { transform: scale(0.97); border-color: var(--burgundy); background: color-mix(in srgb, var(--mark) 35%, transparent); }

/* ---------- Blogs list ---------- */
.post-filter { display: flex; align-items: baseline; gap: 0.6rem; margin: 0 0 1rem; }
.post-filter label { font: 500 0.875rem var(--sans); color: var(--soft); }
.post-filter input {
  font: 400 0.9375rem var(--sans); color: var(--ink); background: transparent;
  border: 0; border-bottom: 1.5px solid var(--soft); padding: 0.2rem 0.1rem;
  min-width: 12rem; max-width: 20rem; flex: 1 1 auto;
}
.post-filter input:focus { outline: none; border-bottom-color: var(--burgundy); border-bottom-width: 2px; }
.post-filter input:focus-visible { outline: 3px solid var(--burgundy); outline-offset: 3px; }
.chip-count { color: var(--soft); font-weight: 400; }
.chip[aria-pressed="true"] .chip-count { color: inherit; }
/* The count sits under the chips, and its line is always there whether or not it
   says anything: the list below must not jump up and down as you filter. */
.chips { margin-bottom: 0.5rem; }
.filter-status { font: 500 0.875rem var(--sans); color: var(--soft); margin: 0 0 0.5rem; min-height: 1.3em; }
.posts-empty { font-family: var(--serif); color: var(--soft); padding: 1.5rem 0; }
/* .post-row sets display: grid, which outranks the browser's own rule for [hidden],
   so a filtered-out row would stay on the page. */
.post-row[hidden] { display: none; }
.post-row h2 a { transition: background-color 100ms ease-out; }
.post-row h2 a:active { background: var(--mark); }

/* ---------- Footnotes ---------- */
.footnotes-list { margin: 0; padding-left: 1.2rem; }
.footnote-item p { margin: 0 0 0.5rem; }
.footnote-ref a { text-decoration: none; }
.footnote-backref { text-decoration: none; }

.plot-fallback { margin: 0; padding: 1rem 0; }
figure.plot .plotly-host { min-height: 320px; }
figure.plot .js-plotly-plot .plotly .modebar { font-size: 0.9em; }

/* ---------- Page to page ----------
   A short cross-fade between pages, nothing that moves. Browsers without
   cross-document view transitions simply navigate as before. */
@view-transition { navigation: auto; }
::view-transition-old(root), ::view-transition-new(root) { animation-duration: 150ms; }

/* The pink line moves in towards the edge of a narrow page. This is the only thing
   left at the old two column breakpoint, and it is not about the columns: it is
   about how much room the page's left padding has to give. */
@media (max-width: 74rem) {
  .page::before { left: clamp(0.4rem, 2vw, 1rem); }
}
@media (max-width: 640px) {
  .article { font-size: 1.0625rem; }
  /* Eleven chips and 351px of page. Padding and the gap between them are not the
     thing in the way at this width: the chips themselves are, and the longest of
     them is over half the line. So the type comes down a step, which takes the row
     from five lines to four, and the space the smaller chip gives up is handed
     straight back to the hit area and then some: 31px to press, where the larger
     chip offered 25px. Compact to read, not compact to hit. */
  .chip { font-size: 0.8125rem; padding: 0.2rem 0.35rem; }
  .chip::before { inset: -4px -1px; }
  .chips { gap: 0.5rem 0.3rem; }
  .post-filter { flex-wrap: wrap; }
  .pager { flex-wrap: wrap; gap: 0.75rem; }
  .pager a { max-width: none; flex: 1 1 100%; }
  .pager .pager-all { order: 3; text-align: left; }
  figure.plot .plotly-host { min-height: 260px; }
}

/* ---------- Reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
  .cell details.code-fold[open] > pre, .toc-panel[open] > ol { animation: none; }
  .cell details.code-fold > summary::before { transition: none; }
  .pager a:active, .post-row h2 a:active { transform: none; }
  html { scroll-behavior: auto; }
}

/* ---------- Reduced transparency ----------
   Nothing here blurs, but several surfaces are mixed with the page behind them.
   When the reader asks for less of that, they become solid. */
@media (prefers-reduced-transparency: reduce) {
  .post-row { background: var(--paper); }
  .callout { background: var(--panel); }
  .article code { background: var(--panel); }
  /* The pink margin line is the last thing on the page drawn at part opacity. Nothing
     reads through it, so this is not a legibility fix: it is the setting taken at its
     word, and a solid rule is what it asks for. */
  .page::before { opacity: 1; }
}

/* The fade on a scrolling equation is the one place the page fades content out. A
   reader who has asked for less of that, or for more contrast, gets a solid rule on
   the edge that has more behind it instead. */
@media (prefers-reduced-transparency: reduce), (prefers-contrast: more) {
  .math-display.scrolls[data-edge] {
    -webkit-mask-image: none; mask-image: none;
  }
  .math-display.scrolls[data-edge~="right"] { border-right: 2px solid var(--accent-line); }
  .math-display.scrolls[data-edge~="left"] { border-left: 2px solid var(--accent-line); }
}

/* ---------- More contrast ---------- */
@media (prefers-contrast: more) {
  .toc a, .post-row time, .article figcaption, figure.plot figcaption,
  .footnotes, .filter-status, .post-filter label { color: var(--ink); }
  .cell .out { color: var(--ink); border-left-color: var(--soft); }
  .chip { border-width: 2px; border-color: var(--ink); }
  .post-filter input { border-bottom-color: var(--ink); border-bottom-width: 2px; }
  .post-row { border-bottom-color: var(--soft); }
  .margin { color: var(--ink); }
}

/* Matplotlib animations, saved out of the notebook as a file rather than left
   inline. No autoplay: a page that starts moving on its own is a page you have to
   stop before you can read it. */
.output-video { display: block; max-width: 100%; height: auto; margin: 0.75rem 0; background: var(--panel); }
