/* Light palette by default. The theme picker pins data-theme on <html>;
   with no attribute, prefers-color-scheme decides. */
:root { /* the Jupyter orange, as in the logo and favicon */
        --accent: #f37726; --ink: #1c1c1c;
        /* text on an orange fill, in both palettes: white, with a dark
           glow that offsets white on the orange's 2.8:1, as on
           jupyter.org's banner (see "Orange fills" below) */
        --on-accent: #fff; --on-accent-shadow: 0 0 4px #000;
        /* text grays clear WCAG AAA (7:1) on both --bg and --card */
        --soft: #444444; --muted: #525252; --bg: #f4f4f4; --card: #ffffff;
        --line: #e2e2e2; --code-bg: #f6f6f6; --mark: #fbd6bc;
        --error-bg: #fef2f2; --error-line: #fecaca; --error-ink: #dc2626;
        --error-soft: #b91c1c;
        /* 5.5:1 on --card, 3.1:1 against --ink */
        --link: #046bb9;
        /* syntax colours: Primer's prettylights light set */
        --syn-keyword: #cf222e; --syn-string: #0a3069; --syn-comment: #59636e;
        --syn-number: #0550ae; --syn-name: #6639ba; --syn-builtin: #953800;
        /* what sets cards and posts off the page: a shadow, which the
           dark palette swaps for a 1px ring in --line */
        --card-edge: 0 1px 3px rgba(0,0,0,.09), 0 4px 14px rgba(0,0,0,.05);
        /* which masthead logo shows (see .site-logo) */
        --logo-light: block; --logo-dark: none;
        color-scheme: light; }
:root[data-theme="dark"] {
  /* text grays clear WCAG AAA (7:1) on both --bg and --card */
  --ink: #e8e6e3; --soft: #c9c6c2; --muted: #aeaaa4;
  --bg: #131313; --card: #1e1e1e; --line: #333333; --code-bg: #2a2a2a;
  --mark: #7a4114; --error-bg: #2a1a1a; --error-line: #5c2828;
  --error-ink: #f87171; --error-soft: #ef4444;
  /* 8.3:1 on --card */
  --link: #7cbcff;
  --syn-keyword: #ff7b72; --syn-string: #a5d6ff; --syn-comment: #8b949e;
  --syn-number: #79c0ff; --syn-name: #d2a8ff; --syn-builtin: #ffa657;
  --card-edge: 0 0 0 1px #333333;
  /* show the dark-palette logo (see .site-logo) */
  --logo-light: none; --logo-dark: block;
  color-scheme: dark;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
  /* text grays clear WCAG AAA (7:1) on both --bg and --card */
  --ink: #e8e6e3; --soft: #c9c6c2; --muted: #aeaaa4;
  --bg: #131313; --card: #1e1e1e; --line: #333333; --code-bg: #2a2a2a;
  --mark: #7a4114; --error-bg: #2a1a1a; --error-line: #5c2828;
  --error-ink: #f87171; --error-soft: #ef4444;
  /* 8.3:1 on --card */
  --link: #7cbcff;
  --syn-keyword: #ff7b72; --syn-string: #a5d6ff; --syn-comment: #8b949e;
  --syn-number: #79c0ff; --syn-name: #d2a8ff; --syn-builtin: #ffa657;
  --card-edge: 0 0 0 1px #333333;
  /* show the dark-palette logo (see .site-logo) */
  --logo-light: none; --logo-dark: block;
  color-scheme: dark;
  }
}
* { box-sizing: border-box; }
/* each face keeps its older name as a local fallback */
:root { --source-sans: "Source Sans 3", "Source Sans Pro",
                       "Helvetica Neue", Helvetica, Arial, sans-serif;
        --source-serif: "Source Serif 4", "Source Serif Pro", Georgia,
                        Cambria, "Times New Roman", Times, serif;
        --source-code: "Source Code Pro", ui-monospace, SFMono-Regular,
                       Menlo, Consolas, monospace;
        --body-font: var(--source-sans);
        --mono: var(--source-code); }
/* "Skip to content" (base.html): off screen until focused */
.skip-link { position: absolute; left: .75rem; top: .5rem; z-index: 10;
             padding: .5rem .9rem; background: var(--card); color: var(--ink);
             border: 2px solid var(--ink); border-radius: 6px; font-weight: 600;
             text-decoration: none; transform: translateY(-200%); }
.skip-link:focus { transform: none; }
body { margin: 0; background: var(--bg); color: var(--ink);
       font: 1rem/1.65 var(--body-font); }
.wrap { max-width: 72rem; margin: 0 auto; padding: 0 1.25rem; }
a { color: var(--link); text-decoration-line: underline;
    text-decoration-thickness: 1px; }
/* Component links: no underline at rest, inherited ink. */
.site-title, .site-header nav a, .card-cover, .card-title a,
.card-meta a, .tag, .share-link, .chip, ul.pagination .page-link,
.archives a, .archive-year a { text-decoration-line: none; color: currentColor; }
/* Hover thickens the underline in the link's own colour: an orange
   underline under blue link text put two accents on one word. */
a:hover { text-decoration-line: underline; text-decoration-color: currentColor;
          text-decoration-thickness: 2px; }

/* Matches jupyter.org's .global-banner box (43.8px tall with one line),
   but in --body-font. The box is 14px/20px and .announcement-content
   (added by announcement.html) 18px/27px. */
.announcement { position: relative; background: var(--accent); color: var(--on-accent);
                text-shadow: var(--on-accent-shadow);
                text-align: center;
                font: 400 .875rem/1.42857143 var(--body-font);
                padding: .6em 2.5em; }
.announcement[hidden] { display: none; }
.announcement-content { font-size: 1.125rem; line-height: 1.5; }
.announcement p { margin: 0; }
.announcement a { color: var(--on-accent); text-decoration: underline;
                  text-decoration-thickness: 2px; }
/* buttons default to the UA's UI font */
.announcement-close { position: absolute; right: .5em; top: 50%;
                      transform: translateY(-50%); padding: .2em .4em;
                      border: 0; background: none; color: inherit;
                      text-shadow: inherit;
                      font-family: inherit;
                      font-size: 1.4em; line-height: 1; cursor: pointer; }

/* Same height as jupyter.org's navbar: 15px (.9375rem) padding around a
   40px logo, plus the 1px border. The nav tab bar depends on .9375rem. */
.site-header { background: var(--card); border-bottom: 1px solid var(--line); }
.site-header .bar { display: flex; align-items: center; justify-content: space-between;
                    flex-wrap: wrap; gap: .5rem;
                    padding-top: .9375rem; padding-bottom: .9375rem; }
.site-title { font-size: 1.25rem; font-weight: 700; color: var(--ink);
              display: flex; align-items: center; gap: .55rem; }
.site-title img { height: 2.1rem; width: auto; }
/* Logo in place of the title (site.toml "logo"; "logo_dark" for the
   dark palette, picked by --logo-light/--logo-dark). */
.site-title img.site-logo { height: 2.5rem; }
.site-title img.site-logo-light { display: var(--logo-light); }
.site-title img.site-logo-dark { display: var(--logo-dark); }
/* a:hover outranks .site-title, so this needs its own rule */
.site-title:hover { text-decoration-line: none; }
/* Nav items are tabs: the current page is bold ink with a 3px accent
   bar on the header's bottom border (padding down through the bar's
   bottom padding, pulled back by a matching negative margin). A flex
   row with row-gap, not inline-blocks, so wrapped rows don't overlap
   the negative margin; row-gap must exceed .9375rem. */
.site-header nav { display: flex; flex-wrap: wrap; align-items: center;
                   column-gap: 1.25rem; row-gap: 1.25rem; }
.site-header nav a { display: inline-block;
                     padding-bottom: calc(.9375rem - 3px); margin-bottom: -.9375rem;
                     border-bottom: 3px solid transparent;
                     color: var(--soft); font-weight: 500; }
.site-header nav a:hover { color: var(--ink); }
.site-header nav a[aria-current="page"] { color: var(--ink); font-weight: 700;
                                          border-bottom-color: var(--accent); }

.theme-picker { display: inline-flex; vertical-align: middle; }
.theme-picker[hidden] { display: none; }
.theme-picker button {
                       display: inline-flex; align-items: center;
                       justify-content: center; width: 1.9rem; height: 1.9rem;
                       padding: 0; border: 1px solid var(--line);
                       border-radius: 999px; background: none;
                       color: var(--muted); cursor: pointer; }
.theme-picker button:hover { color: var(--accent); }
.theme-picker svg { width: 1rem; height: 1rem; }

/* feed icon in the header nav and beside tag/author page titles */
.feed-link { display: inline-flex; align-items: center; }
.feed-icon { width: 1rem; height: 1rem; }
.site-header nav .feed-link { vertical-align: middle; padding-bottom: 0;
                              margin-bottom: 0; border-bottom: 0; }
.page-title .feed-link { margin-left: .55rem; color: var(--muted);
                         vertical-align: middle; }
.page-title .feed-link:hover { color: var(--accent); }
.page-title .feed-icon { width: 1.4rem; height: 1.4rem; }

.page-title { font-size: 2.4rem; font-weight: 700; margin: 2.2rem 0 1rem; }
.intro { max-width: 46rem; color: var(--muted); margin-bottom: 2rem; }

/* The home page's heading, with the post filter (index.html) at its
   right; below it where the two no longer fit one row. */
.listing-head { display: flex; flex-wrap: wrap; align-items: baseline;
                column-gap: 1.5rem; }
.post-filter { position: relative; margin: 0 0 1rem auto;
               flex: 0 1 17rem; }
.post-filter[hidden] { display: none; }
.post-filter-icon { position: absolute; left: .8rem; top: 50%;
                    width: 1rem; height: 1rem; transform: translateY(-50%);
                    color: var(--muted); pointer-events: none; }
.post-filter input { width: 100%; padding: .45rem 2.2rem;
                     border: 1px solid var(--line); border-radius: 999px;
                     background: var(--card); color: var(--ink);
                     font: inherit; }
/* one clear button in every browser: WebKit's own is hidden */
.post-filter input::-webkit-search-cancel-button { -webkit-appearance: none;
                                                  appearance: none; }
.post-filter-clear { position: absolute; right: .45rem; top: 50%;
                     transform: translateY(-50%); display: inline-flex;
                     align-items: center; justify-content: center;
                     width: 1.6rem; height: 1.6rem; padding: 0; border: 0;
                     border-radius: 999px; background: none;
                     color: var(--muted); cursor: pointer; }
.post-filter-clear[hidden] { display: none; }
.post-filter-clear:hover { color: var(--ink); background: var(--bg); }
.post-filter-clear svg { width: 1rem; height: 1rem; }
.post-filter input::placeholder { color: var(--muted); opacity: 1; }
.post-filter input:focus { outline: 2px solid var(--accent);
                           outline-offset: -1px; border-color: transparent; }
.filter-status { color: var(--muted); margin: 0 0 1rem; }
.intro[hidden], ul.pagination[hidden] { display: none; }
/* a listing opened with ?q=, until the filter's results replace its
   own cards (index.html): they keep their space, so the page below
   does not jump up and back */
.filter-pending :is(.intro, .page-number, ul.pagination:not(.filter-pages)) { display: none; }
.filter-pending .card-grid { visibility: hidden; }
@media (max-width: 36rem) {
  .post-filter { flex-basis: 100%; margin-left: 0; }
}

.card-grid { display: grid; gap: 1.5rem; margin: 1rem 0 2.5rem;
             grid-template-columns: repeat(auto-fill, minmax(min(19rem, 100%), 1fr)); }
.card { background: var(--card); border-radius: 8px; overflow: hidden;
        box-shadow: var(--card-edge);
        display: flex; flex-direction: column; }
/* Covers all have site.toml's cover_size shape, which the img's width
   and height give the frame (pelicanconf.py's _make_covers). */
.card-cover { display: block; background: var(--bg); }
.card-cover img { width: 100%; height: auto; display: block; }
.card-body { padding: 1.1rem 1.25rem 1.25rem; display: flex;
             flex-direction: column; flex: 1; }
.card-tags { margin: 0 0 .5rem; display: flex; flex-wrap: wrap; gap: .35rem;
              /* a row's cards share the tag track (below), so it can be
                 taller than this card's tags: they keep their height and
                 the space falls below them, rather than stretching */
              align-items: flex-start; align-content: flex-start; }
.card-title { margin: 0 0 .5rem; font-size: 1.3rem; line-height: 1.3; }
.card-title a { color: var(--ink); }
.card-text { flex: 1; }
.card-excerpt { margin: 0; color: var(--muted); font-size: .95rem; }
.card-meta { margin: 1rem 0 0; color: var(--muted); font-size: .875rem; }
/* Cards in a grid row share its tracks (cover, tags, title and
   excerpt, meta), so titles line up across the row when a card has no
   cover or its tags wrap. The grid's row gap would otherwise also fall
   between a card's own tracks, so the space between rows is a margin. */
@supports (grid-template-rows: subgrid) {
  .card-grid { row-gap: 0; margin-bottom: 1rem; }
  .card { display: grid; grid-row: span 4; grid-template-rows: subgrid;
          row-gap: 0; margin-bottom: 1.5rem; }
  .card-cover { grid-row: 1; }
  .card-body { grid-row: 2 / span 3; display: grid;
               grid-template-rows: subgrid; row-gap: 0; }
  .card-tags { grid-row: 1; }
  .card-text { grid-row: 2; }
  .card-meta { grid-row: 3; }
}

.post { background: var(--card); border-radius: 8px; margin: 2rem auto 3rem;
        font-family: var(--source-serif);
        /* a word longer than the line (a URL as link text, long inline
           code) breaks at the edge rather than widening the page; code
           blocks scroll instead (below). Unlike anywhere, break-word
           leaves a box sized by its content (a table column) as wide as
           its longest word. */
        overflow-wrap: break-word;
        padding: 2.5rem clamp(1.25rem, 5vw, 3.5rem); max-width: 52rem;
        font-size: 1.25rem; line-height: 1.6;
        box-shadow: var(--card-edge); }
.post h1 { font-size: 2.4rem; line-height: 1.25; margin: 0 0 .5rem; }
/* Headings would otherwise inherit .post's 1.6 line-height. More space
   above than below binds a heading to the text it introduces. */
.post :is(h2, h3, h4, h5, h6) { line-height: 1.25; }
/* One step down per level, in size and the space above, so a
   subsection reads as part of its section: h2 at 1.35em (the title is
   about 1.4 times a section heading), h3 at 1.1em, and h4 to h6 at the
   text's size in --soft. All stay bold: the sans at a lighter weight
   reads weaker than bold serif text, so a heading would sit below the
   lead-ins of the text it introduces. */
.post h2 { font-size: 1.35em; margin: 2.75rem 0 .5rem; }
.post h3 { font-size: 1.1em; margin: 2rem 0 .35rem; }
.post :is(h4, h5, h6) { font-size: 1em; color: var(--soft);
                        margin: 1.6rem 0 .25rem; }
/* The section link heading-anchor.html appends to each heading: shown
   on heading hover, on focus, or always without hover. Hidden by
   opacity so revealing it doesn't re-wrap the heading. */
.heading-anchor { margin-left: .3em; color: var(--muted); opacity: 0; }
.heading-anchor, .heading-anchor:hover { text-decoration-line: none; }
.post :hover > .heading-anchor,
.heading-anchor:focus-visible { opacity: 1; }
@media (hover: none) { .heading-anchor { opacity: 1; } }
.heading-anchor svg { width: .8em; height: .8em; vertical-align: baseline; }
.heading-anchor:hover, .heading-anchor:focus-visible { color: var(--accent); }
/* The inner <p> comes from Pelican, which renders the subtitle as
   Markdown (FORMATTED_FIELDS). */
.post-subtitle { color: var(--muted); font-size: 1.45rem; line-height: 1.35;
                 margin: 0 0 1rem; }
.post-subtitle p { margin: 0; font: inherit; color: inherit; }
.post-meta { color: var(--muted); margin: 0 0 .9rem; font-size: 1rem; }
/* Tag pill. Hover colours the border, not the text: orange text fails
   contrast. */
.tag { display: inline-flex; align-items: center;
       background: var(--code-bg); border: 1px solid var(--line);
       border-radius: 999px; padding: .05rem .65rem;
       font-size: .875rem; color: var(--soft); }
.tag:hover { border-color: var(--accent); color: var(--ink);
             text-decoration: none; }
/* white behind transparent images, which were drawn for Medium's white
   page, so dark logos stay legible */
.post img { max-width: 100%; height: auto; border-radius: 4px; background: #fff; }
/* fluid 16:9 embeds (convert writes YouTube embeds as 560x315 iframes) */
.post iframe { width: 100%; max-width: 100%; height: auto; aspect-ratio: 16 / 9;
               border: 0; border-radius: 4px; }
/* clips replacing animated gifs and Giphy embeds (see clip-motion.html) */
.post video { max-width: 100%; height: auto; border-radius: 4px; }
/* Centre standalone images and clips: alone in a paragraph, optionally
   linked (the reader classes the paragraph, as CSS cannot see the text
   beside an inline image), or in a figure. */
.post p.standalone-image, .post figure { text-align: center; }
/* Inline code is em so it tracks the prose. Blocks are rem: 15px, which
   fits about 76 columns at the column's full width (longer lines
   scroll), where 14px left code at 70% of the 20px text. */
.post pre { overflow-wrap: normal; overflow-x: auto; padding: 1rem; background: var(--code-bg);
            border-radius: 6px; font-family: var(--mono);
            font-size: .9375rem; line-height: 1.4; }
.post code { background: var(--code-bg); font-family: var(--mono);
             font-size: .9em; }
.post pre code { font-size: inherit; background: none; }
/* Token colours on the class names shared by Pygments (Pelican) and
   Chroma (Hugo, noClasses = false). The --syn-* values are Primer's
   (AA, not AAA), and all clear 4.5:1 on --code-bg: the light comment
   grey is Primer's current muted text (#59636e, 5.7:1), as its older
   #6e7781 was 4.2:1. */
.post .highlight .k, .post .highlight .kd, .post .highlight .kn,
.post .highlight .kr, .post .highlight .kt, .post .highlight .kc,
.post .highlight .ow { color: var(--syn-keyword); }
.post .highlight .s, .post .highlight .s1, .post .highlight .s2,
.post .highlight .sb, .post .highlight .sd, .post .highlight .sa,
.post .highlight .se, .post .highlight .sh, .post .highlight .si,
.post .highlight .sx, .post .highlight .sr, .post .highlight .ss,
.post .highlight .dl { color: var(--syn-string); }
.post .highlight .c, .post .highlight .c1, .post .highlight .cm,
.post .highlight .cp, .post .highlight .cs,
.post .highlight .ch { color: var(--syn-comment); font-style: italic; }
.post .highlight .m, .post .highlight .mi, .post .highlight .mf,
.post .highlight .mh, .post .highlight .mo, .post .highlight .mb,
.post .highlight .il { color: var(--syn-number); }
.post .highlight .nf, .post .highlight .fm, .post .highlight .nc,
.post .highlight .nd, .post .highlight .ne, .post .highlight .nn,
.post .highlight .nt { color: var(--syn-name); }
.post .highlight .nb, .post .highlight .bp,
.post .highlight .na { color: var(--syn-builtin); }
/* Copy button from code-copy.html. It is positioned on the .code-block
   wrapper, not the pre, so it doesn't scroll away with the code. Shown
   on hover, on focus, or always without hover; hidden by opacity so it
   stays in the tab order. .code-copy-status is a visually hidden live
   region. */
.code-block { position: relative; }
.code-copy { position: absolute; top: .45rem; right: .45rem;
             display: inline-flex; align-items: center; justify-content: center;
             width: 1.9rem; height: 1.9rem; padding: 0;
             border: 1px solid var(--line); border-radius: 6px;
             background: var(--code-bg); color: var(--muted);
             cursor: pointer; opacity: 0; }
.code-block:hover .code-copy, .code-copy:focus-visible { opacity: 1; }
@media (hover: none) { .code-copy { opacity: 1; } }
.code-copy svg { width: 1rem; height: 1rem; }
.code-copy svg[hidden] { display: none; }
.code-copy:hover, .code-copy:focus-visible { color: var(--accent);
                                             border-color: var(--accent); }
.code-copy-status { position: absolute; width: 1px; height: 1px;
                    margin: -1px; padding: 0; overflow: hidden;
                    clip-path: inset(50%); white-space: nowrap; }
.post blockquote { margin-left: 0; padding-left: 1rem;
                   border-left: 3px solid var(--accent); color: var(--soft); }
/* tables come from Markdown gists inlined by convert */
.post table { border-collapse: collapse; width: 100%; margin: 1rem 0;
              font-size: .9em; font-variant-numeric: tabular-nums; }
.post th, .post td { padding: .45em .6em; text-align: left;
                     vertical-align: top; border-bottom: 1px solid var(--line); }
.post th { border-bottom: 2px solid var(--line); }
/* Table columns are as wide as their longest word (.post's break-word).
   On a phone, long inline code (a directory name) may break anywhere,
   and a table whose words are still too wide scrolls rather than the
   page. */
@media (max-width: 40rem) {
  .post table { display: block; overflow-x: auto; }
  .post td code { overflow-wrap: anywhere; }
}
/* Upright on a phone, whole words no longer fit three columns: any word
   may break, but no column narrows below about eight letters, so a
   header such as "People" stays whole. */
@media (max-width: 27rem) {
  .post :is(th, td) { overflow-wrap: anywhere; min-width: 4.5em; }
}
/* Override the UA's 40px figure indent. Goldmark renders an embed
   figure's caption as a paragraph. */
.post figure { margin: 1rem 0; }
.post figure > p { margin: 0; }
/* undo the figure centring for captioned code blocks */
.post figure pre { text-align: left; }
/* Markdown footnotes: the reference marks keep the line's spacing, and
   the notes under the post are set a step smaller than the text. */
.post sup { line-height: 0; }
.post .footnotes { font-size: .9em; }
.post figcaption { font-size: .8em; font-style: italic;
                   margin-top: .35rem; text-align: center; }
.post figcaption p { margin: 0; }
.post figcaption, .post em img + em { color: var(--muted); }

/* only running text is in the serif */
.post :is(h1, h2, h3, h4, h5, h6), .post-subtitle, .post-meta,
.post-share, .post figcaption, .post table { font-family: var(--body-font); }

/* Share bar (share-icons.html sprite), under the byline and at the foot
   of a post. */
.share-sprite { display: none; }
.post-share { display: flex; align-items: center; flex-wrap: wrap; gap: .55rem;
              margin: 2.5rem 0 0; padding-top: 1.6rem;
              border-top: 1px solid var(--line); }
/* the copy under the byline has no top rule */
.post-meta + .post-share { margin: 0 0 2rem; padding-top: 0; border-top: 0; }
.related { margin-top: 3rem; padding-top: 1rem; border-top: 1px solid var(--line); }
.related .page-title { font-size: 1.6rem; margin: 1rem 0; }
.share-label { color: var(--muted); font-size: .9rem; margin-right: .2rem; }
.share-link { display: inline-flex; align-items: center; justify-content: center;
              width: 2.1rem; height: 2.1rem; border: 1px solid var(--line);
              border-radius: 999px; color: var(--muted); }
/* network logos are not recoloured with the accent (brand guidelines);
   only the ring is */
.share-link:hover { color: var(--ink); border-color: var(--accent);
                    text-decoration: none; }
.share-icon { width: 1.05rem; height: 1.05rem; fill: currentColor; }

/* Click-to-zoom (article.html marks only images whose original is
   larger than shown as .zoomable, and wraps each in a .zoom-button,
   unstyled so the image looks as it would without it). */
.post .zoom-button { display: inline-block; max-width: 100%; margin: 0;
                     padding: 0; border: 0; background: none; font: inherit;
                     color: inherit; line-height: 0; cursor: zoom-in; }
.post .zoom-button:focus-visible { outline-offset: 3px; }
.zoom-dialog { width: 100%; height: 100%; max-width: 100%; max-height: 100%;
               margin: 0; padding: 0; border: 0; background: none;
               color: #f2f2f2; cursor: zoom-out;
               display: none; flex-direction: column; align-items: center;
               justify-content: center; gap: .75rem; overflow: hidden; }
.zoom-dialog[open] { display: flex; }
.zoom-dialog::backdrop { background: rgba(0, 0, 0, .85); }
/* white behind transparency, as for .post img */
.zoom-dialog img { max-width: 94vw; max-height: 88vh; width: auto;
                   height: auto; border-radius: 4px; background: #fff; }
.zoom-caption { max-width: 60ch; margin: 0; padding: 0 1rem;
                text-align: center; font-size: .9rem; }
.zoom-caption[hidden] { display: none; }
@keyframes zoom-open { from { opacity: 0; transform: scale(.97); } }
@keyframes backdrop-open { from { opacity: 0; } }
.zoom-dialog[open] img { animation: zoom-open .18s ease-out; }
.zoom-dialog[open]::backdrop { animation: backdrop-open .18s ease-out; }
@media (prefers-reduced-motion: reduce) {
  .zoom-dialog[open] img, .zoom-dialog[open]::backdrop { animation: none; }
}

.term-list { display: flex; flex-wrap: wrap; gap: .6rem; margin: 1.5rem 0 3rem; }
.chip { background: var(--card); border: 1px solid var(--line); border-radius: 999px;
        padding: .35rem .9rem; color: var(--ink); }
.chip span { color: var(--muted); font-size: .875em; }
.chip:hover { border-color: var(--accent); text-decoration: none; }

.term-sort { margin: 1.5rem 0 0; color: var(--muted); font-size: .9rem; }
.term-sort[hidden] { display: none; }
.term-sort button { border: 1px solid var(--line); border-radius: 999px;
                    background: var(--card); color: var(--soft); font: inherit;
                    padding: .15rem .8rem; margin-left: .35rem; cursor: pointer; }
.term-sort button:hover { border-color: var(--accent); }
/* ~, not +: term-sort.html's script tag sits between the two */
.term-sort ~ .term-list { margin-top: .9rem; }

ul.pagination { display: flex; flex-wrap: wrap; justify-content: center; gap: .25rem;
                list-style: none; padding: 0; margin: 0 0 3rem; }
/* Hover colours the border, as on the tag pill; the transparent rest
   border keeps the box from shifting on hover. */
ul.pagination .page-link { display: inline-block; padding: .35rem .8rem;
                           background: var(--card); border: 1px solid transparent;
                           border-radius: 6px; color: var(--ink); }
ul.pagination a.page-link:hover { border-color: var(--accent); text-decoration: none; }
/* Orange fills: one style for the current pagination page, the pressed
   sort button and, from the same tokens in base.html, the newsletter's
   Subscribe button: semibold --on-accent on the orange. */
ul.pagination .active .page-link,
.term-sort button[aria-pressed="true"] { background: var(--accent);
                                         border-color: var(--accent);
                                         color: var(--on-accent); font-weight: 600;
                                         text-shadow: var(--on-accent-shadow); }
/* an arrow that leads nowhere (first and last pages) keeps its space,
   so the numbers don't shift from page to page, but isn't shown */
ul.pagination .disabled { visibility: hidden; }

.archives { list-style: none; padding: 0; margin: 1rem 0 2rem; }
.archives time { color: var(--muted); font-variant-numeric: tabular-nums;
                 margin-right: .6rem; }
.archives a { color: var(--ink); }
/* a year's heading on /archives/, linking to its page: a heading in
   ink, with a rule over the year's posts */
.archive-year { font-size: 1.4rem; margin: 2rem 0 .5rem; padding-bottom: .35rem;
                border-bottom: 1px solid var(--line); }

/* Pagefind's component CSS has ID-level specificity, so overrides here
   need !important. */
#search { margin: 0 0 3rem;
          /* map Pagefind's --pf-* variables to the site palette, since
             it does not follow prefers-color-scheme itself */
          --pf-text: var(--ink); --pf-text-secondary: var(--soft);
          --pf-text-muted: var(--muted); --pf-background: var(--card);
          --pf-border: var(--line); --pf-skeleton: var(--code-bg);
          --pf-hover: var(--code-bg); --pf-mark: var(--ink);
          --pf-error-bg: var(--error-bg); --pf-error-border: var(--error-line);
          --pf-error-text: var(--error-ink);
          --pf-error-text-secondary: var(--error-soft);
          /* and its type to the site's, from Pagefind's system stack
             and 12px result count */
          --pf-font: var(--body-font); --pf-summary-font-size: .875rem;
          --pf-result-excerpt-font-size: .95rem; }
#search mark { color: inherit; border-radius: 2px; padding: 0 .12em;
               background: var(--mark) !important; }
#search .pf-result-title { margin-bottom: .2rem; }
#search .pf-result-link { font-size: 1.25rem !important;
                          font-weight: 700 !important;
                          color: var(--ink) !important; }
#search .pf-result-excerpt { color: var(--soft) !important; }
#search .pf-heading-link { font-size: .92rem !important;
                           font-weight: 600 !important;
                           color: var(--ink) !important; }
#search .pf-heading-excerpt { color: var(--muted) !important;
                              font-size: .9rem !important; }
/* Newsletter band. The HubSpot form renders in its own iframe, so
   newsletter.html styles it from these tokens and unhides the band. */
.newsletter { background: var(--card); border-top: 1px solid var(--line);
              margin-top: 3rem; padding: 2.5rem 0; }
.newsletter[hidden] { display: none; }
.newsletter h2 { font-size: 1.6rem; font-weight: 700; line-height: 1.25;
                 margin: 0 0 1.5rem; }
/* the footer (site.toml "footer") is Markdown and may arrive wrapped
   in a <p> */
.site-footer { color: var(--muted); font-size: .875rem; padding-top: 1rem;
               padding-bottom: 2.5rem; }
.site-footer p { margin: 0; }

/* Phones (under 40rem): post text drops to 18px and the gutters
   narrow, for about 40 characters a line at 390px rather than 32. */
@media (max-width: 40rem) {
  .wrap { padding: 0 .75rem; }
  .post { padding: 1.5rem 1rem; margin-top: 1rem; font-size: 1.125rem; }
  .post h1 { font-size: 2.1rem; }
}
/* Where the header no longer fits one row (about 36.5rem), the nav
   takes a row of its own below the logo and the theme toggle moves to
   the right of the logo's row, which would otherwise be empty, rather
   than wrapping onto a third row. The top centres it on the 2.5rem
   logo, inside the bar's .9375rem padding. */
@media (max-width: 36rem) {
  .site-header .bar { position: relative; }
  .site-header nav { flex-basis: 100%; }
  .theme-picker { position: absolute; right: .75rem;
                  top: calc(.9375rem + (2.5rem - 1.9rem) / 2); }
}

/* Print: the post alone, full width, in the light palette with black
   links (a dark-palette reader would otherwise print light text), and
   code wrapped rather than cut off at the page edge. */
@media print {
  :root, :root[data-theme], :root:not([data-theme]) {
    --ink: #000; --soft: #222; --muted: #444; --bg: #fff; --card: #fff;
    --line: #ccc; --code-bg: #f4f4f4; --mark: #fbd6bc; --link: #000;
    --syn-keyword: #cf222e; --syn-string: #0a3069; --syn-comment: #59636e;
    --syn-number: #0550ae; --syn-name: #6639ba; --syn-builtin: #953800;
    --card-edge: none; color-scheme: light; }
  .skip-link, .announcement, .site-header, .post-share, .related,
  .newsletter, .code-copy, .heading-anchor, ul.pagination { display: none !important; }
  .wrap { max-width: none; padding: 0; }
  .post { margin: 0; padding: 0; max-width: none; border-radius: 0;
          font-size: 11pt; }
  .post a { color: inherit; }
  .post pre { white-space: pre-wrap; overflow-wrap: anywhere; }
  .post :is(img, video, figure, pre, table, blockquote) { break-inside: avoid; }
  .post :is(h1, h2, h3, h4, h5, h6) { break-after: avoid; }
}
