*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { -webkit-text-size-adjust: 100%; }
body { line-height: 1.5; }
img, picture, video, canvas, svg { display: block; max-width: 100%; }
input, button, textarea, select { font: inherit; }
p, h1, h2, h3, h4, h5, h6 { overflow-wrap: break-word; }
a { color: inherit; text-decoration: none; }
ul, ol { list-style: none; }
table { border-collapse: collapse; }

@view-transition {
  navigation: auto;
}

/* Cross-document view transitions (native browser MPA navigation, no JS).
   Astro's <ClientRouter /> does this via a client-side router; here the
   browser handles it directly off `@view-transition { navigation: auto }`
   above — this block just replaces the default cross-fade with a slightly
   nicer slide+fade, and keeps header/footer stable instead of fading with
   the rest of the page. The named ::view-transition-group(...) pair below
   operates on the browser's top-layer snapshot tree, not the regular DOM,
   so unlike the view-transition-name declarations themselves (nested
   inside header/footer below) it can't be scoped and has to stay global. */
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 220ms;
  animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}

::view-transition-old(root) {
  animation-name: view-transition-fade-out, view-transition-slide-out;
}

::view-transition-new(root) {
  animation-name: view-transition-fade-in, view-transition-slide-in;
}

@keyframes view-transition-fade-out {
  to { opacity: 0; }
}

@keyframes view-transition-fade-in {
  from { opacity: 0; }
}

@keyframes view-transition-slide-out {
  to { transform: translateY(-8px); }
}

@keyframes view-transition-slide-in {
  from { transform: translateY(8px); }
}

::view-transition-group(site-header),
::view-transition-group(site-footer) {
  animation: none;
}

@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation: none !important;
  }
}

:root {
  --color-black: light-dark(hsl(0, 0%, 0%), hsl(0, 0%, 0%));
  --color-white: light-dark(hsl(0, 0%, 100%), hsl(0, 0%, 100%));
  --color-accent: hsl(57.25deg 100% 70%);
  --color-body-bg: light-dark(hsl(0, 0%, 100%), hsl(210, 13%, 15%));
  --color-box-bg: light-dark(hsl(0, 0%, 95%), hsl(210, 13%, 9%));
  --color-text: light-dark(hsl(0, 0%, 13%), hsl(210, 17%, 98%));
  --color-link: light-dark(hsl(211, 100%, 45%), hsl(211, 100%, 60%));
  --color-post-link: light-dark(hsl(0, 0%, 0%), hsl(211, 100%, 60%));
  --color-highlight-bg: light-dark(hsl(183, 80%, 88%), hsl(183, 80%, 18%));
  --color-code-fg: light-dark(hsl(348, 86%, 43%), hsl(348, 86%, 80%));
  --color-code-bg: light-dark(hsl(0, 0%, 89%), hsl(210, 13%, 6%));
  --color-pre-bg: light-dark(hsl(0, 0%, 89%), hsl(210, 13%, 6%));
  --color-tag: light-dark(hsl(152, 96%, 35%), hsl(152, 96%, 44%));
  --token-comment: light-dark(hsl(220, 10%, 45%), hsl(220, 10%, 60%));
  --token-keyword: light-dark(hsl(310, 60%, 45%), hsl(310, 70%, 72%));
  --token-string: light-dark(hsl(95, 45%, 35%), hsl(95, 55%, 65%));
  --token-function: light-dark(hsl(210, 70%, 45%), hsl(210, 80%, 72%));
  --token-number: light-dark(hsl(25, 80%, 42%), hsl(25, 90%, 65%));
  --token-builtin: light-dark(hsl(175, 55%, 32%), hsl(175, 60%, 60%));
  --token-punctuation: light-dark(hsl(220, 8%, 40%), hsl(220, 8%, 70%));
  --token-tag: light-dark(hsl(0, 60%, 45%), hsl(0, 70%, 72%));
  --token-attr-name: light-dark(hsl(35, 70%, 38%), hsl(35, 80%, 65%));
  color-scheme: light dark;
  --btn-light: none;
  --btn-dark: block;

  /* Fluid type/space scale (utopia.fyi methodology): each token scales
     continuously between its min size at a 320px viewport and its max
     size at a 1280px viewport, replacing what used to be a hard jump at
     a single max-width:720px breakpoint. Structural changes (flex
     direction, grid column counts, sidebar widths) aren't continuous
     properties and stay as ordinary breakpoints elsewhere. */
  --fs-sm: clamp(1rem, calc(0.9667rem + 0.1667vw), 1.1rem);
  --fs-body: clamp(1.1rem, calc(1.05rem + 0.25vw), 1.25rem);
  --fs-md: clamp(1.15rem, calc(1.0667rem + 0.4167vw), 1.4rem);
  --fs-title-lg: clamp(1.6rem, calc(1.5083rem + 0.4583vw), 1.875rem);
  --fs-heading-md: clamp(1.2rem, calc(1.1rem + 0.5vw), 1.5rem);
  --fs-heading-sm: clamp(1rem, calc(0.9167rem + 0.4167vw), 1.25rem);
  --fs-repo-title: clamp(1.3rem, calc(1.2rem + 0.5vw), 1.6rem);
  --fs-hero-xl: clamp(1.65rem, calc(1.5333rem + 0.5833vw), 2rem);
  --fs-features: clamp(0.925rem, calc(0.8583rem + 0.3333vw), 1.125rem);
  --space-gap-fluid: clamp(0rem, calc(-0.6667rem + 3.3333vw), 2rem);
  --space-section-mb: clamp(0rem, calc(-0.3333rem + 1.6667vw), 1rem);
}

/* data-theme is tri-state: absent = follow OS (color-scheme: light dark
   above already does that), "light"/"dark" = explicit user override that
   must win even against an opposite OS preference. Every color below is
   driven by light-dark() reading this color-scheme value — no need to
   redeclare each variable per theme. */
:root[data-theme="light"] {
  color-scheme: light;
}

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

@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) {
    --btn-light: block;
    --btn-dark: none;
  }
}

:root[data-theme="dark"] {
  --btn-light: block;
  --btn-dark: none;
}

:root[data-theme="light"] {
  --btn-light: none;
  --btn-dark: block;
}

[data-tooltip] {
  position: relative;
  cursor: help;
}

[data-tooltip]::after {
  position: absolute;
  opacity: 0;
  pointer-events: none;
  content: attr(data-tooltip);
  left: 0;
  top: calc(100% + 10px);
  border-radius: 3px;
  box-shadow: 0 0 1px 1px var(--color-text);
  background-color: var(--color-box-bg);
  z-index: 10;
  padding: 8px;
  width: 300px;
  transform: translateY(-20px);
  transition: all 150ms cubic-bezier(0.25, 0.8, 0.25, 1);
}

[data-tooltip]:hover::after {
  opacity: 1;
  transform: translateY(0);
  transition-duration: 300ms;
}

body {
  display: flex;
  flex-direction: column;
  flex: 1;
  background-color: var(--color-body-bg);
  color: var(--color-text);
  font-family: system-ui;
  text-rendering: optimizeLegibility;
  font-variant-ligatures: common-ligatures;
  font-kerning: normal;
  font-size: var(--fs-body);
  line-height: 1.5;
  min-height: 100vh;
}

main {
  margin-top: 1rem;
  margin-bottom: 1rem;
  padding-bottom: 1em;
}

.wrapper {
  flex: 1;
  width: 100%;
  max-width: 960px;
  margin-right: auto;
  margin-left: auto;
  padding-left: 1em;
  padding-right: 1em;
}

/* site-header.njk/site-footer.njk are plain includes (no wrapping custom
   element), so these are just nested under the real <header>/<footer>
   tag — plain CSS nesting scopes .logo/.links etc to it same as any other
   descendant selector would, no @scope needed since there's only ever
   one header and one footer on the page. */
header {
  background: #131618;
  view-transition-name: site-header;

  .logo {
    display: flex;
    font-size: 22px;
    line-height: 56px;
    font-weight: 400;
    margin-bottom: 0;
    float: left;
    color: var(--color-accent);
    margin-right: 8px;

    &.active,
    &:hover {
      color: var(--color-accent);
      text-decoration: underline;
      text-decoration-color: var(--color-accent);
      text-underline-offset: 8px;
    }
  }

  .links {
    display: flex;
    flex-direction: row;
    float: right;
    font-size: 1.4rem;
    line-height: 56px;
    color: white;

    #theme-switch {
      display: flex;
      align-items: center;
      font-size: 1.3rem;

      button {
        background: none;
        border: none;
        padding: 0;
        padding-right: 12px;
        margin-bottom: -2px;
        color: inherit;
        cursor: pointer;

        &:hover,
        &:focus,
        &:active {
          background: none;
          border: none;
          color: inherit;
        }
      }
    }

    a {
      display: inline-block;
      text-decoration: none;
      font-size: 22px;
      line-height: 56px;
      color: white;
      font-weight: 400;
      padding-left: 12px;
      padding-right: 12px;

      &:last-child {
        padding-right: 0px;
      }

      &.active,
      &:hover {
        color: var(--color-gray-200);
        text-decoration: underline;
        text-decoration-color: var(--color-accent);
        text-underline-offset: 8px;
      }
    }
  }
}

footer {
  background: #131618;
  view-transition-name: site-footer;

  .container {
    display: flex;
    flex-direction: row;
    flex: 1;
    padding: 16px 0px;
  }

  .spacer {
    flex: 1;
  }

  .copyright-container {
    display: flex;
    align-items: center;
    justify-content: center;
    margin-left: 0.5rem;
    margin-right: 0.5rem;
    color: var(--color-white);
    font-size: 1rem;
  }

  .link {
    font-size: 1rem;
    line-height: 1.5rem;
    margin-left: 0.5rem;
    color: var(--color-white);
    font-weight: 500;
    text-underline-offset: 2px;
    text-decoration-thickness: 2px;
    text-decoration-line: underline;
    text-decoration-color: white;

    &:hover {
      color: var(--color-gray-200);
      text-decoration-color: var(--color-gray-200);
    }
  }
}

/* Syntax highlighting theme: shared by code-view's own file-viewer pre and
   by fenced code blocks inside markdown-view's article content (both
   Prism-highlighted blog-post code and plain markdown-it README code
   fences). It's genuinely cross-cutting rather than owned by one
   component — scoping it to either would mean duplicating the whole token
   palette in the other — so it stays global. */
pre[class*="language-"],
code[class*="language-"] {
  background: var(--color-pre-bg);
  color: var(--color-text);
}

pre[class*="language-"],
pre.code-view,
.markdown-body pre {
  padding: 1rem;
  margin: 1rem 0;
  overflow-x: auto;
  border-radius: 4px;
  line-height: 1.5;
}

/* File-viewer code (pre.code-view) matches the rest of that layout's
   0.9rem scale (see repos.css); blog/README fenced code blocks stay at
   0.8rem — they're a different context and weren't asked to change. */
pre.code-view {
  font-size: 0.9rem;
}

pre[class*="language-"],
.markdown-body pre {
  font-size: 0.8rem;
}

pre.code-view,
.markdown-body pre {
  background: var(--color-pre-bg);
  color: var(--color-text);
}

code[class*="language-"] {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
  color: var(--token-comment);
  font-style: italic;
}

.token.keyword,
.token.selector,
.token.important,
.token.atrule {
  color: var(--token-keyword);
}

.token.string,
.token.char,
.token.attr-value,
.token.regex {
  color: var(--token-string);
}

.token.function,
.token.class-name {
  color: var(--token-function);
}

.token.number,
.token.boolean,
.token.constant {
  color: var(--token-number);
}

.token.builtin,
.token.deleted {
  color: var(--token-builtin);
}

.token.punctuation,
.token.operator {
  color: var(--token-punctuation);
}

.token.tag {
  color: var(--token-tag);
}

.token.attr-name,
.token.property {
  color: var(--token-attr-name);
}

/* Repo browsing pages (readme/files/commits/blame). Restored from the
   original Astro-era RepoLayout/FileLayout/Commit/RecursiveList components
   (see git history at 7325531^), with the tab nav restyled as a bordered
   tab bar and a couple of small crates.io-inspired touches (clone command
   as its own code box, tags as pills) layered on top.

   Font sizes on this page follow one small scale instead of one-off
   values, so nothing reads as randomly bigger/smaller than its neighbour:
     0.85rem — small badges (tags, pull-right meta, file-size hints)
     0.9rem  — code/monospace content, nav links and sub-headings alike
               (pre/code-view, file tree, blame, file title)
     0.95rem — box body text (.repo, .event)
     var(--fs-repo-title) — page-level heading (.repo h1), fluid 1.3–1.6rem
   All of them are rem-based, not em, so nesting depth can't change the
   rendered size — that's what made the old code-view/blame font sizes
   inconsistent (em compounds with whatever ancestor happens to wrap it).

   Everything below uses plain CSS nesting rather than @scope: .repo,
   .file-layout, .event, .file-explorer and table.blame are all real,
   always-present classes/tags on these pages (none of them are wrapped
   in a custom element anymore), so nesting under them scopes their
   descendants exactly the way @scope would, without needing a scope root
   selector that has to be kept in sync with whatever markup happens to
   wrap it. */

.repo {
  text-overflow: ellipsis;
  overflow: hidden;
  padding: 0.5rem;
  background: var(--color-box-bg);
  color: var(--color-text);
  font-size: 0.95rem;

  a {
    color: var(--color-link);
  }

  .header {
    display: flex;
    flex-direction: row;
    align-items: baseline;

    @media (max-width: 720px) {
      flex-direction: column;
      align-items: start;
    }
  }

  h1 {
    font-size: var(--fs-repo-title);
    font-weight: 500;
    line-height: 1;
    margin-bottom: 0.1rem;
    flex: 1;
  }

  .tags {
    margin-top: 0.5rem;
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem;
  }

  .tag {
    color: var(--color-tag);
    padding: 0.15rem 0.5rem 0.5rem 0;
    border-radius: 4px;
    font-size: 0.95rem;
    font-weight: 500;
  }

  h3 {
    font-size: 0.85rem;
    font-weight: 400;
    margin-top: 0.5rem;
    padding: 0.5rem 0.75rem;
    background: var(--color-pre-bg);
    border-radius: 4px;
    overflow-x: auto;
    white-space: pre;
  }

  .headerExtension h2 {
    display: flex;
    flex: 1;
    padding-top: 0.3rem;
    font-size: 0.95rem;
    font-weight: 400;
  }

  hr {
    margin-top: 0.5rem;
    border: none;
    border-top: 1px solid var(--color-text);
  }

  .nav {
    display: flex;
    align-items: center;
    margin-top: 0.5rem;

    span {
      padding: 0 0.75rem;
      color: var(--color-text);
    }

    a {
      font-size: 1rem;
      font-weight: 500;
      cursor: pointer;
      color: var(--color-link);
      text-decoration: none;

      &.active-tab {
        text-decoration: underline;
        text-underline-offset: 4px;
      }
    }
  }
}

#repo-content {
  margin-top: 0.75rem;

  /* README (repos/repo.njk) — same box treatment as the file explorer
     panes below, so it doesn't sit as bare unstyled text against the
     page background. Scoped to #repo-content so blog posts (which also
     use .markdown-body) are untouched. */
  .markdown-body {
    background: var(--color-box-bg);
    padding: 1rem 1.25rem;
  }
}

/* Commit list / commit detail header (Commit.astro) — repos/commit.njk,
   commits.njk, file-history.njk. pre.commit is nested here too since
   it's always .event's child, never used alone. */
.event {
  background-color: var(--color-box-bg);
  color: var(--color-text);
  text-overflow: ellipsis;
  overflow: hidden;
  padding: 0.6rem 0.75rem;
  margin: 0.5rem 0;
  font-size: 0.95rem;

  a {
    color: var(--color-link);
  }

  strong {
    font-weight: 500;
  }

  .pull-right {
    font-size: 0.85rem;
    font-weight: 400;
    float: right;
  }

  pre.commit {
    font-family: inherit;
    white-space: pre-wrap;
    margin-top: 0.35rem;
  }
}

/* Two-pane IDE-style file explorer: a persistent tree sidebar + a content
   pane, each its own rounded box with a gap between them rather than a
   single shared border — the gap is what visually separates them, so
   they don't also need to differ in colour. The tree lives outside
   #file-pane, so htmx swaps of #file-pane (clicking a file) or
   #file-content (Contents/History/Blame) never touch the sidebar — it
   just stays where it is, already expanded, no reload.

   Fixed-height explorer: both panes stretch to the same height and scroll
   independently, so scrolling a long file never scrolls the tree out of
   view (or the whole page) — closer to a real IDE split view than a page
   that just keeps growing with the file's content. */
.file-explorer {
  display: flex;
  align-items: stretch;
  gap: 0.5rem;
  height: 80vh;

  /* File tree: flat rows (no per-item card background), a rotating
     triangle for expand/collapse instead of an emoji folder glyph, and a
     left accent border + tint on the active file instead of a filled
     pill. */
  .file-explorer-tree {
    width: 260px;
    flex-shrink: 0;
    height: 100%;
    overflow-y: auto;
    padding: 0.6rem;
    background: var(--color-box-bg);
    border-radius: 6px;
    font-size: 0.9rem;

    ul {
      list-style: none;
      margin: 0 0 0 1.1rem;
      padding: 0;
    }

    > ul {
      margin-left: 0;
    }

    li {
      margin: 0;

      &.active-file,
      & > a.active-file {
        color: var(--color-link);
      }
    }

    summary,
    li > a {
      display: flex;
      align-items: center;
      gap: 0.4rem;
      padding: 0.2rem 0.35rem;
      border-radius: 4px;
      border-left: 2px solid transparent;
      cursor: pointer;
      text-decoration: none;
      color: var(--color-text);
      line-height: 1.6;
    }

    summary {
      list-style: none;

      &::-webkit-details-marker {
        display: none;
      }

      &::before {
        content: "";
        flex-shrink: 0;
        width: 0;
        height: 0;
        border-style: solid;
        border-width: 0.3em 0 0.3em 0.4em;
        border-color: transparent transparent transparent currentColor;
        opacity: 0.5;
        transition: transform 120ms ease;
      }
    }

    details[open] > summary::before {
      transform: rotate(90deg);
    }

    summary svg,
    li > a svg {
      flex-shrink: 0;
      width: 1em;
      height: 1em;
    }

    summary:hover,
    li > a:hover {
      background-color: var(--color-pre-bg);
    }

    li > a.active-file {
      color: var(--color-link);
      background-color: var(--color-highlight-bg);
      border-left-color: var(--color-link);
      font-weight: 500;
    }

    .file-size {
      margin-left: auto;
      opacity: 0.5;
      font-size: 0.85rem;
    }
  }

  .file-explorer-main {
    flex: 1;
    min-width: 0;
    height: 100%;
    display: flex;
    flex-direction: column;
    border: 1px solid var(--color-box-bg);
    border-radius: 6px;
    overflow: hidden;

    &:has(.file-explorer-placeholder) {
      align-items: center;
      justify-content: center;
    }

    /* #file-content padding/background: when it holds actual code (a
       plain <pre>), let the box-bg colour fill the whole pane
       edge-to-edge instead of floating as a small inset card — closer to
       a real code viewer's continuous code surface. box-bg (not pre-bg)
       so it reads as one calm surface with the file-layout header above
       it, rather than the near-black pre-bg used for one-off code
       snippets elsewhere on the site. */
    #file-content {
      flex: 1;
      overflow-y: auto;
      padding: 0.85rem;

      &:has(> pre) {
        padding: 0;
        background: var(--color-box-bg);

        pre {
          margin: 0;
          background: transparent;
          border-radius: 0;
        }
      }
    }
  }

  .file-explorer-placeholder {
    color: var(--color-text);
    opacity: 0.6;
    padding: 1rem 0;
  }

  @media (max-width: 720px) {
    flex-direction: column;
    height: 85vh;

    .file-explorer-tree {
      width: 100%;
      height: auto;
      flex: 0 0 35%;
    }

    .file-explorer-main {
      width: 100%;
      height: auto;
      flex: 1 1 auto;
    }
  }
}

/* File view header — a compact icon+filename strip with the
   Contents/History/Blame tabs, sitting as the card's title bar rather
   than a full-width heading. */
.file-layout {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  flex-shrink: 0;
  gap: 0.5rem;
  padding: 0.6rem 0.85rem;
  background: var(--color-box-bg);
  border-bottom: 1px solid var(--color-pre-bg);

  .title {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    /* flex:1 (not the default 0 1 auto) so it's the one that gives up
       space when the row is tight — without this, a long filename could
       force the row to wrap .nav onto its own line instead of shrinking,
       since the wrap decision is made off each item's unshrunk
       hypothetical width, not its post-shrink width. */
    flex: 1 1 auto;
    min-width: 0;
    font-size: 0.9rem;
    font-weight: 500;
    margin-bottom: -4px;

    svg {
      flex-shrink: 0;
      width: 1rem;
      height: 1rem;
    }

    span {
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
  }

  .nav {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    flex-shrink: 0;

    div:not(:has(a)) {
      display: none;
    }

    a {
      font-size: 0.9rem;
      font-weight: 500;
      padding: 0.3rem 0.1rem;
      margin-right: 0.75rem;
      cursor: pointer;
      color: var(--color-text);
      border-bottom: 2px solid transparent;

      &:hover {
        color: var(--color-link);
      }

      &[aria-current="true"] {
        color: var(--color-link);
        border-bottom-color: var(--color-link);
      }
    }
  }
}

/* Blame table — repos/file-blame.njk. */
table.blame {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  background: var(--color-pre-bg);
  border-radius: 4px;
  overflow: hidden;

  td {
    vertical-align: top;
    padding: 0.1rem 0.5rem;
    border-bottom: 1px solid var(--color-box-bg);
  }

  .blame-meta {
    white-space: nowrap;
    color: var(--color-link);
    width: 1%;
  }

  .blame-line-no {
    white-space: nowrap;
    opacity: 0.5;
    text-align: right;
    width: 1%;
  }

  .blame-content pre {
    margin: 0;
    white-space: pre-wrap;
  }
}

/* diff2html ships its own light/dark token sets as plain CSS custom
   properties on :root (see node_modules/diff2html/bundles/css) but only
   applies the dark set under a `.d2h-dark-color-scheme` class we never
   add. Remapping the base tokens it actually reads to their `--d2h-dark-*`
   counterparts under our own [data-theme="dark"] gets the same result
   without needing that class or a second copy of every diff2html rule.
   This re-themes a third-party library's own classes rather than styling
   one of our own, so it's left flat/global rather than nested. */
:root[data-theme="dark"] {
  --d2h-bg-color: var(--d2h-dark-bg-color);
  --d2h-border-color: var(--d2h-dark-border-color);
  --d2h-dim-color: var(--d2h-dark-dim-color);
  --d2h-line-border-color: var(--d2h-dark-line-border-color);
  --d2h-file-header-bg-color: var(--d2h-dark-file-header-bg-color);
  --d2h-file-header-border-color: var(--d2h-dark-file-header-border-color);
  --d2h-empty-placeholder-bg-color: var(--d2h-dark-empty-placeholder-bg-color);
  --d2h-empty-placeholder-border-color: var(--d2h-dark-empty-placeholder-border-color);
  --d2h-selected-color: var(--d2h-dark-selected-color);
  --d2h-ins-bg-color: var(--d2h-dark-ins-bg-color);
  --d2h-ins-border-color: var(--d2h-dark-ins-border-color);
  --d2h-ins-highlight-bg-color: var(--d2h-dark-ins-highlight-bg-color);
  --d2h-ins-label-color: var(--d2h-dark-ins-label-color);
  --d2h-del-bg-color: var(--d2h-dark-del-bg-color);
  --d2h-del-border-color: var(--d2h-dark-del-border-color);
  --d2h-del-highlight-bg-color: var(--d2h-dark-del-highlight-bg-color);
  --d2h-del-label-color: var(--d2h-dark-del-label-color);
  --d2h-change-del-color: var(--d2h-dark-change-del-color);
  --d2h-change-ins-color: var(--d2h-dark-change-ins-color);
  --d2h-info-bg-color: var(--d2h-dark-info-bg-color);
  --d2h-info-border-color: var(--d2h-dark-info-border-color);
  --d2h-change-label-color: var(--d2h-dark-change-label-color);
  --d2h-moved-label-color: var(--d2h-dark-moved-label-color);
}

.d2h-wrapper {
  color: var(--color-text);
}

/* Shared typography for rendered markdown content (blog posts + repo
   READMEs) — anything wrapped in a plain <article class="markdown-body">
   (see repo.njk/post.njk; no wrapping custom element anymore). Extracted
   from the old posts-detail.css so repo pages get the same look instead
   of no styling at all. Deliberately scoped to .markdown-body p/li code
   (inline code), not .markdown-body code generally — a bare `code`
   selector would also catch the <code> inside fenced <pre> blocks and
   stomp the syntax-highlighting styles from shared.css with the small
   inline-code padding/background (that shared styling is cross-cutting
   between markdown content and the file-viewer, so it stays global
   rather than duplicated here). */
.markdown-body {
  font-size: 1.1rem;
  line-height: 1.5;

  h1 {
    font-size: var(--fs-heading-md);
    font-weight: 700;
    margin-top: 0;
    margin-bottom: 0.5rem;
  }

  h2 {
    font-size: var(--fs-heading-md);
    font-weight: 700;
    margin-top: 0;
    margin-bottom: 0.5rem;
  }

  h3 {
    font-size: var(--fs-heading-sm);
    font-weight: 700;
    margin-top: 0.5rem;
    margin-bottom: 0.1rem;
  }

  p {
    font-size: 1.1rem;
    padding-bottom: 1rem;
  }

  li {
    font-size: 1.1rem;
  }

  p code,
  li code {
    color: var(--color-code-fg) !important;
    background: var(--color-code-bg) !important;
    word-wrap: break-word;
    box-decoration-break: clone;
    padding: 2px 4px;
    border-radius: 0.2rem;
    font-weight: 400;
    font-size: 0.8rem;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  }

  /* Fenced code blocks in a README (markdown-it output — no language-
     class on the <pre> itself, unlike Prism's blog-post output, which is
     how this targets only the README case) get a subtle border + corner
     radius, matching the framed-code-block look. */
  pre:not([class*="language-"]) {
    border: 1px solid var(--color-box-bg);
    border-radius: 0.4rem;
  }

  blockquote {
    font-size: 1.2rem;
    font-weight: 600;
    background: var(--color-highlight-bg);
    padding: 0.4rem;
    margin: 16px 0px;

    p {
      padding: 0;
    }
  }
}

:host,:root{--d2h-bg-color:#fff;--d2h-border-color:#ddd;--d2h-dim-color:rgba(0,0,0,.3);--d2h-line-border-color:#eee;--d2h-file-header-bg-color:#f7f7f7;--d2h-file-header-border-color:#d8d8d8;--d2h-empty-placeholder-bg-color:#f1f1f1;--d2h-empty-placeholder-border-color:#e1e1e1;--d2h-selected-color:#c8e1ff;--d2h-ins-bg-color:#dfd;--d2h-ins-border-color:#b4e2b4;--d2h-ins-highlight-bg-color:#97f295;--d2h-ins-label-color:#399839;--d2h-del-bg-color:#fee8e9;--d2h-del-border-color:#e9aeae;--d2h-del-highlight-bg-color:#ffb6ba;--d2h-del-label-color:#c33;--d2h-change-del-color:#fdf2d0;--d2h-change-ins-color:#ded;--d2h-info-bg-color:#f8fafd;--d2h-info-border-color:#d5e4f2;--d2h-change-label-color:#d0b44c;--d2h-moved-label-color:#3572b0;--d2h-dark-color:#e6edf3;--d2h-dark-bg-color:#0d1117;--d2h-dark-border-color:#30363d;--d2h-dark-dim-color:#6e7681;--d2h-dark-line-border-color:#21262d;--d2h-dark-file-header-bg-color:#161b22;--d2h-dark-file-header-border-color:#30363d;--d2h-dark-empty-placeholder-bg-color:hsla(215,8%,47%,.1);--d2h-dark-empty-placeholder-border-color:#30363d;--d2h-dark-selected-color:rgba(56,139,253,.1);--d2h-dark-ins-bg-color:rgba(46,160,67,.15);--d2h-dark-ins-border-color:rgba(46,160,67,.4);--d2h-dark-ins-highlight-bg-color:rgba(46,160,67,.4);--d2h-dark-ins-label-color:#3fb950;--d2h-dark-del-bg-color:rgba(248,81,73,.1);--d2h-dark-del-border-color:rgba(248,81,73,.4);--d2h-dark-del-highlight-bg-color:rgba(248,81,73,.4);--d2h-dark-del-label-color:#f85149;--d2h-dark-change-del-color:rgba(210,153,34,.2);--d2h-dark-change-ins-color:rgba(46,160,67,.25);--d2h-dark-info-bg-color:rgba(56,139,253,.1);--d2h-dark-info-border-color:rgba(56,139,253,.4);--d2h-dark-change-label-color:#d29922;--d2h-dark-moved-label-color:#3572b0}.d2h-wrapper{text-align:left}.d2h-file-header{background-color:#f7f7f7;background-color:var(--d2h-file-header-bg-color);border-bottom:1px solid #d8d8d8;border-bottom:1px solid var(--d2h-file-header-border-color);display:-webkit-box;display:-ms-flexbox;display:flex;font-family:Source Sans Pro,Helvetica Neue,Helvetica,Arial,sans-serif;height:35px;padding:5px 10px}.d2h-file-header.d2h-sticky-header{position:sticky;top:0;z-index:1}.d2h-file-stats{display:-webkit-box;display:-ms-flexbox;display:flex;font-size:14px;margin-left:auto}.d2h-lines-added{border:1px solid #b4e2b4;border:1px solid var(--d2h-ins-border-color);border-radius:5px 0 0 5px;color:#399839;color:var(--d2h-ins-label-color);padding:2px;text-align:right;vertical-align:middle}.d2h-lines-deleted{border:1px solid #e9aeae;border:1px solid var(--d2h-del-border-color);border-radius:0 5px 5px 0;color:#c33;color:var(--d2h-del-label-color);margin-left:1px;padding:2px;text-align:left;vertical-align:middle}.d2h-file-name-wrapper{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;font-size:15px;width:100%}.d2h-file-name{overflow-x:hidden;text-overflow:ellipsis;white-space:nowrap}.d2h-file-wrapper{border:1px solid #ddd;border:1px solid var(--d2h-border-color);border-radius:3px;margin-bottom:1em}.d2h-file-collapse{-webkit-box-pack:end;-ms-flex-pack:end;cursor:pointer;display:none;font-size:12px;justify-content:flex-end;-webkit-box-align:center;-ms-flex-align:center;align-items:center;border:1px solid #ddd;border:1px solid var(--d2h-border-color);border-radius:3px;padding:4px 8px}.d2h-file-collapse.d2h-selected{background-color:#c8e1ff;background-color:var(--d2h-selected-color)}.d2h-file-collapse-input{margin:0 4px 0 0}.d2h-diff-table{border-collapse:collapse;font-family:Menlo,Consolas,monospace;font-size:13px;width:100%}.d2h-files-diff{display:-webkit-box;display:-ms-flexbox;display:flex;width:100%}.d2h-file-diff{overflow-y:hidden}.d2h-file-diff.d2h-d-none,.d2h-files-diff.d2h-d-none{display:none}.d2h-file-side-diff{display:inline-block;overflow-x:scroll;overflow-y:hidden;width:50%}.d2h-code-line{padding:0 8em;width:calc(100% - 16em)}.d2h-code-line,.d2h-code-side-line{display:inline-block;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;white-space:nowrap}.d2h-code-side-line{padding:0 4.5em;width:calc(100% - 9em)}.d2h-code-line-ctn{background:none;display:inline-block;padding:0;word-wrap:normal;-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text;vertical-align:middle;white-space:pre;width:100%}.d2h-code-line del,.d2h-code-side-line del{background-color:#ffb6ba;background-color:var(--d2h-del-highlight-bg-color)}.d2h-code-line del,.d2h-code-line ins,.d2h-code-side-line del,.d2h-code-side-line ins{border-radius:.2em;display:inline-block;margin-top:-1px;-webkit-text-decoration:none;text-decoration:none}.d2h-code-line ins,.d2h-code-side-line ins{background-color:#97f295;background-color:var(--d2h-ins-highlight-bg-color);text-align:left}.d2h-code-line-prefix{background:none;display:inline;padding:0;word-wrap:normal;white-space:pre}.line-num1{float:left}.line-num1,.line-num2{-webkit-box-sizing:border-box;box-sizing:border-box;overflow:hidden;padding:0 .5em;text-overflow:ellipsis;width:3.5em}.line-num2{float:right}.d2h-code-linenumber{background-color:#fff;background-color:var(--d2h-bg-color);border:solid #eee;border:solid var(--d2h-line-border-color);border-width:0 1px;-webkit-box-sizing:border-box;box-sizing:border-box;color:rgba(0,0,0,.3);color:var(--d2h-dim-color);cursor:pointer;display:inline-block;position:absolute;text-align:right;width:7.5em}.d2h-code-linenumber:after{content:"\200b"}.d2h-code-side-linenumber{background-color:#fff;background-color:var(--d2h-bg-color);border:solid #eee;border:solid var(--d2h-line-border-color);border-width:0 1px;-webkit-box-sizing:border-box;box-sizing:border-box;color:rgba(0,0,0,.3);color:var(--d2h-dim-color);cursor:pointer;display:inline-block;overflow:hidden;padding:0 .5em;position:absolute;text-align:right;text-overflow:ellipsis;width:4em}.d2h-code-side-linenumber:after{content:"\200b"}.d2h-code-side-emptyplaceholder,.d2h-emptyplaceholder{background-color:#f1f1f1;background-color:var(--d2h-empty-placeholder-bg-color);border-color:#e1e1e1;border-color:var(--d2h-empty-placeholder-border-color)}.d2h-code-line-prefix,.d2h-code-linenumber,.d2h-code-side-linenumber,.d2h-emptyplaceholder{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.d2h-code-linenumber,.d2h-code-side-linenumber{direction:rtl}.d2h-del{background-color:#fee8e9;background-color:var(--d2h-del-bg-color);border-color:#e9aeae;border-color:var(--d2h-del-border-color)}.d2h-ins{background-color:#dfd;background-color:var(--d2h-ins-bg-color);border-color:#b4e2b4;border-color:var(--d2h-ins-border-color)}.d2h-info{background-color:#f8fafd;background-color:var(--d2h-info-bg-color);border-color:#d5e4f2;border-color:var(--d2h-info-border-color);color:rgba(0,0,0,.3);color:var(--d2h-dim-color)}.d2h-file-diff .d2h-del.d2h-change{background-color:#fdf2d0;background-color:var(--d2h-change-del-color)}.d2h-file-diff .d2h-ins.d2h-change{background-color:#ded;background-color:var(--d2h-change-ins-color)}.d2h-file-list-wrapper{margin-bottom:10px}.d2h-file-list-wrapper a{-webkit-text-decoration:none;text-decoration:none}.d2h-file-list-wrapper a,.d2h-file-list-wrapper a:visited{color:#3572b0;color:var(--d2h-moved-label-color)}.d2h-file-list-header{text-align:left}.d2h-file-list-title{font-weight:700}.d2h-file-list-line{display:-webkit-box;display:-ms-flexbox;display:flex;text-align:left}.d2h-file-list{display:block;list-style:none;margin:0;padding:0}.d2h-file-list>li{border-bottom:1px solid #ddd;border-bottom:1px solid var(--d2h-border-color);margin:0;padding:5px 10px}.d2h-file-list>li:last-child{border-bottom:none}.d2h-file-switch{cursor:pointer;display:none;font-size:10px}.d2h-icon{fill:currentColor;margin-right:10px;vertical-align:middle}.d2h-deleted{color:#c33;color:var(--d2h-del-label-color)}.d2h-added{color:#399839;color:var(--d2h-ins-label-color)}.d2h-changed{color:#d0b44c;color:var(--d2h-change-label-color)}.d2h-moved{color:#3572b0;color:var(--d2h-moved-label-color)}.d2h-tag{background-color:#fff;background-color:var(--d2h-bg-color);display:-webkit-box;display:-ms-flexbox;display:flex;font-size:10px;margin-left:5px;padding:0 2px}.d2h-deleted-tag{border:1px solid #c33;border:1px solid var(--d2h-del-label-color)}.d2h-added-tag{border:1px solid #399839;border:1px solid var(--d2h-ins-label-color)}.d2h-changed-tag{border:1px solid #d0b44c;border:1px solid var(--d2h-change-label-color)}.d2h-moved-tag{border:1px solid #3572b0;border:1px solid var(--d2h-moved-label-color)}.d2h-dark-color-scheme{background-color:#0d1117;background-color:var(--d2h-dark-bg-color);color:#e6edf3;color:var(--d2h-dark-color)}.d2h-dark-color-scheme .d2h-file-header{background-color:#161b22;background-color:var(--d2h-dark-file-header-bg-color);border-bottom:#30363d;border-bottom:var(--d2h-dark-file-header-border-color)}.d2h-dark-color-scheme .d2h-lines-added{border:1px solid rgba(46,160,67,.4);border:1px solid var(--d2h-dark-ins-border-color);color:#3fb950;color:var(--d2h-dark-ins-label-color)}.d2h-dark-color-scheme .d2h-lines-deleted{border:1px solid rgba(248,81,73,.4);border:1px solid var(--d2h-dark-del-border-color);color:#f85149;color:var(--d2h-dark-del-label-color)}.d2h-dark-color-scheme .d2h-code-line del,.d2h-dark-color-scheme .d2h-code-side-line del{background-color:rgba(248,81,73,.4);background-color:var(--d2h-dark-del-highlight-bg-color)}.d2h-dark-color-scheme .d2h-code-line ins,.d2h-dark-color-scheme .d2h-code-side-line ins{background-color:rgba(46,160,67,.4);background-color:var(--d2h-dark-ins-highlight-bg-color)}.d2h-dark-color-scheme .d2h-diff-tbody{border-color:#30363d;border-color:var(--d2h-dark-border-color)}.d2h-dark-color-scheme .d2h-code-side-linenumber{background-color:#0d1117;background-color:var(--d2h-dark-bg-color);border-color:#21262d;border-color:var(--d2h-dark-line-border-color);color:#6e7681;color:var(--d2h-dark-dim-color)}.d2h-dark-color-scheme .d2h-files-diff .d2h-code-side-emptyplaceholder,.d2h-dark-color-scheme .d2h-files-diff .d2h-emptyplaceholder{background-color:hsla(215,8%,47%,.1);background-color:var(--d2h-dark-empty-placeholder-bg-color);border-color:#30363d;border-color:var(--d2h-dark-empty-placeholder-border-color)}.d2h-dark-color-scheme .d2h-code-linenumber{background-color:#0d1117;background-color:var(--d2h-dark-bg-color);border-color:#21262d;border-color:var(--d2h-dark-line-border-color);color:#6e7681;color:var(--d2h-dark-dim-color)}.d2h-dark-color-scheme .d2h-del{background-color:rgba(248,81,73,.1);background-color:var(--d2h-dark-del-bg-color);border-color:rgba(248,81,73,.4);border-color:var(--d2h-dark-del-border-color)}.d2h-dark-color-scheme .d2h-ins{background-color:rgba(46,160,67,.15);background-color:var(--d2h-dark-ins-bg-color);border-color:rgba(46,160,67,.4);border-color:var(--d2h-dark-ins-border-color)}.d2h-dark-color-scheme .d2h-info{background-color:rgba(56,139,253,.1);background-color:var(--d2h-dark-info-bg-color);border-color:rgba(56,139,253,.4);border-color:var(--d2h-dark-info-border-color);color:#6e7681;color:var(--d2h-dark-dim-color)}.d2h-dark-color-scheme .d2h-file-diff .d2h-del.d2h-change{background-color:rgba(210,153,34,.2);background-color:var(--d2h-dark-change-del-color)}.d2h-dark-color-scheme .d2h-file-diff .d2h-ins.d2h-change{background-color:rgba(46,160,67,.25);background-color:var(--d2h-dark-change-ins-color)}.d2h-dark-color-scheme .d2h-file-wrapper{border:1px solid #30363d;border:1px solid var(--d2h-dark-border-color)}.d2h-dark-color-scheme .d2h-file-collapse{border:1px solid #0d1117;border:1px solid var(--d2h-dark-bg-color)}.d2h-dark-color-scheme .d2h-file-collapse.d2h-selected{background-color:rgba(56,139,253,.1);background-color:var(--d2h-dark-selected-color)}.d2h-dark-color-scheme .d2h-file-list-wrapper a,.d2h-dark-color-scheme .d2h-file-list-wrapper a:visited{color:#3572b0;color:var(--d2h-dark-moved-label-color)}.d2h-dark-color-scheme .d2h-file-list>li{border-bottom:1px solid #0d1117;border-bottom:1px solid var(--d2h-dark-bg-color)}.d2h-dark-color-scheme .d2h-deleted{color:#f85149;color:var(--d2h-dark-del-label-color)}.d2h-dark-color-scheme .d2h-added{color:#3fb950;color:var(--d2h-dark-ins-label-color)}.d2h-dark-color-scheme .d2h-changed{color:#d29922;color:var(--d2h-dark-change-label-color)}.d2h-dark-color-scheme .d2h-moved{color:#3572b0;color:var(--d2h-dark-moved-label-color)}.d2h-dark-color-scheme .d2h-tag{background-color:#0d1117;background-color:var(--d2h-dark-bg-color)}.d2h-dark-color-scheme .d2h-deleted-tag{border:1px solid #f85149;border:1px solid var(--d2h-dark-del-label-color)}.d2h-dark-color-scheme .d2h-added-tag{border:1px solid #3fb950;border:1px solid var(--d2h-dark-ins-label-color)}.d2h-dark-color-scheme .d2h-changed-tag{border:1px solid #d29922;border:1px solid var(--d2h-dark-change-label-color)}.d2h-dark-color-scheme .d2h-moved-tag{border:1px solid #3572b0;border:1px solid var(--d2h-dark-moved-label-color)}@media (prefers-color-scheme:dark){.d2h-auto-color-scheme{background-color:#0d1117;background-color:var(--d2h-dark-bg-color);color:#e6edf3;color:var(--d2h-dark-color)}.d2h-auto-color-scheme .d2h-file-header{background-color:#161b22;background-color:var(--d2h-dark-file-header-bg-color);border-bottom:#30363d;border-bottom:var(--d2h-dark-file-header-border-color)}.d2h-auto-color-scheme .d2h-lines-added{border:1px solid rgba(46,160,67,.4);border:1px solid var(--d2h-dark-ins-border-color);color:#3fb950;color:var(--d2h-dark-ins-label-color)}.d2h-auto-color-scheme .d2h-lines-deleted{border:1px solid rgba(248,81,73,.4);border:1px solid var(--d2h-dark-del-border-color);color:#f85149;color:var(--d2h-dark-del-label-color)}.d2h-auto-color-scheme .d2h-code-line del,.d2h-auto-color-scheme .d2h-code-side-line del{background-color:rgba(248,81,73,.4);background-color:var(--d2h-dark-del-highlight-bg-color)}.d2h-auto-color-scheme .d2h-code-line ins,.d2h-auto-color-scheme .d2h-code-side-line ins{background-color:rgba(46,160,67,.4);background-color:var(--d2h-dark-ins-highlight-bg-color)}.d2h-auto-color-scheme .d2h-diff-tbody{border-color:#30363d;border-color:var(--d2h-dark-border-color)}.d2h-auto-color-scheme .d2h-code-side-linenumber{background-color:#0d1117;background-color:var(--d2h-dark-bg-color);border-color:#21262d;border-color:var(--d2h-dark-line-border-color);color:#6e7681;color:var(--d2h-dark-dim-color)}.d2h-auto-color-scheme .d2h-files-diff .d2h-code-side-emptyplaceholder,.d2h-auto-color-scheme .d2h-files-diff .d2h-emptyplaceholder{background-color:hsla(215,8%,47%,.1);background-color:var(--d2h-dark-empty-placeholder-bg-color);border-color:#30363d;border-color:var(--d2h-dark-empty-placeholder-border-color)}.d2h-auto-color-scheme .d2h-code-linenumber{background-color:#0d1117;background-color:var(--d2h-dark-bg-color);border-color:#21262d;border-color:var(--d2h-dark-line-border-color);color:#6e7681;color:var(--d2h-dark-dim-color)}.d2h-auto-color-scheme .d2h-del{background-color:rgba(248,81,73,.1);background-color:var(--d2h-dark-del-bg-color);border-color:rgba(248,81,73,.4);border-color:var(--d2h-dark-del-border-color)}.d2h-auto-color-scheme .d2h-ins{background-color:rgba(46,160,67,.15);background-color:var(--d2h-dark-ins-bg-color);border-color:rgba(46,160,67,.4);border-color:var(--d2h-dark-ins-border-color)}.d2h-auto-color-scheme .d2h-info{background-color:rgba(56,139,253,.1);background-color:var(--d2h-dark-info-bg-color);border-color:rgba(56,139,253,.4);border-color:var(--d2h-dark-info-border-color);color:#6e7681;color:var(--d2h-dark-dim-color)}.d2h-auto-color-scheme .d2h-file-diff .d2h-del.d2h-change{background-color:rgba(210,153,34,.2);background-color:var(--d2h-dark-change-del-color)}.d2h-auto-color-scheme .d2h-file-diff .d2h-ins.d2h-change{background-color:rgba(46,160,67,.25);background-color:var(--d2h-dark-change-ins-color)}.d2h-auto-color-scheme .d2h-file-wrapper{border:1px solid #30363d;border:1px solid var(--d2h-dark-border-color)}.d2h-auto-color-scheme .d2h-file-collapse{border:1px solid #0d1117;border:1px solid var(--d2h-dark-bg-color)}.d2h-auto-color-scheme .d2h-file-collapse.d2h-selected{background-color:rgba(56,139,253,.1);background-color:var(--d2h-dark-selected-color)}.d2h-auto-color-scheme .d2h-file-list-wrapper a,.d2h-auto-color-scheme .d2h-file-list-wrapper a:visited{color:#3572b0;color:var(--d2h-dark-moved-label-color)}.d2h-auto-color-scheme .d2h-file-list>li{border-bottom:1px solid #0d1117;border-bottom:1px solid var(--d2h-dark-bg-color)}.d2h-dark-color-scheme .d2h-deleted{color:#f85149;color:var(--d2h-dark-del-label-color)}.d2h-auto-color-scheme .d2h-added{color:#3fb950;color:var(--d2h-dark-ins-label-color)}.d2h-auto-color-scheme .d2h-changed{color:#d29922;color:var(--d2h-dark-change-label-color)}.d2h-auto-color-scheme .d2h-moved{color:#3572b0;color:var(--d2h-dark-moved-label-color)}.d2h-auto-color-scheme .d2h-tag{background-color:#0d1117;background-color:var(--d2h-dark-bg-color)}.d2h-auto-color-scheme .d2h-deleted-tag{border:1px solid #f85149;border:1px solid var(--d2h-dark-del-label-color)}.d2h-auto-color-scheme .d2h-added-tag{border:1px solid #3fb950;border:1px solid var(--d2h-dark-ins-label-color)}.d2h-auto-color-scheme .d2h-changed-tag{border:1px solid #d29922;border:1px solid var(--d2h-dark-change-label-color)}.d2h-auto-color-scheme .d2h-moved-tag{border:1px solid #3572b0;border:1px solid var(--d2h-dark-moved-label-color)}}
/* Homepage-only styling, nested under .pageContainer (the page's own
   top-level wrapper — see src/index.njk) now that this file ships in the
   site-wide bundle.css instead of being the only stylesheet loaded on
   this page. Without this nesting, the bare `h2`/`section` selectors
   below would apply to every h2/section on every other page too. */
.pageContainer {
  margin-left: auto;
  margin-right: auto;
  margin-bottom: 2.5rem;

  .description {
    font-size: var(--fs-sm);
  }

  h2 {
    font-size: var(--fs-md);
    font-weight: 600;
  }

  section {
    display: flex;
    flex-direction: column;
    margin-top: 1.5rem;
    margin-bottom: var(--space-section-mb);
  }

  .rounded-md {
    border-radius: 0.375rem;
  }

  .repos {
    display: grid;
    grid-template-columns: auto auto;
    gap: 1rem;
    margin-top: 0.5rem;

    @media (max-width: 720px) {
      gap: 1rem;
      grid-template-columns: auto;
    }
  }

  .title {
    font-size: var(--fs-title-lg);
    line-height: 2.25rem;
    font-weight: 700;
    margin-bottom: 1rem;
  }

  .firstSection {
    display: flex;
    flex-direction: column;
  }

  .firstPara {
    display: flex;
    flex-direction: row;
  }

  .linkUnderline {
    text-decoration-line: underline;
  }

  .gridContainer {
    display: grid;
    grid-template-columns: repeat(1, minmax(0, 1fr));
    gap: var(--space-gap-fluid);

    @media (min-width: 640px) {
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }
  }

  .repo {
    text-overflow: ellipsis;
    overflow: hidden;
    padding: 0.5rem;
    background: var(--color-box-bg);
    color: var(--color-text);
    font-size: 0.95rem;

    a {
      color: var(--color-link);
    }

    h4 {
      font-size: 1.05rem;
      font-weight: 500;
      line-height: 1.2;
      border-bottom: 1px solid #495057;
      text-overflow: ellipsis;
      white-space: nowrap;
      overflow: hidden;
      margin-bottom: 0;
      padding: 0;
    }

    .tags {
      margin-top: 0.5rem;
      display: flex;
      flex-wrap: wrap;
      gap: 0.25rem;
    }

    .tag {
      color: var(--color-tag);
      padding: 0.15rem 0.5rem 0.5rem 0rem;
      border-radius: 0.25rem;
      font-size: 0.95rem;
      font-weight: 500;
    }
  }

  .interests {
    ul {
      display: grid;
      gap: 0.5rem;
      grid-template-columns: auto auto auto;
      text-align: center;
      margin-top: 0.5rem;
      font-size: 1.1rem;

      li {
        background-color: var(--color-box-bg);
        padding: 0.25rem;
      }
    }
  }

  .contact {
    ul {
      display: grid;
      gap: 0.5rem;
      grid-template-columns: auto;
      margin-top: 0.5rem;

      li {
        display: flex;
        flex-direction: row;
        align-items: baseline;
        padding: 0.25rem;
        background-color: var(--color-box-bg);
        font-size: var(--fs-sm);

        @media (max-width: 720px) {
          flex-direction: column;
        }
      }

      a {
        color: var(--color-link);
      }

      strong {
        font-weight: 500;
        margin-left: 0.25rem;
        margin-right: 0.5rem;
      }
    }
  }

  .tools {
    img {
      width: 36px;
      height: 36px;
    }

    ul {
      display: grid;
      gap: 0.5rem;
      grid-template-columns: auto auto auto auto;
      text-align: center;
      margin-top: 0.5rem;

      @media (max-width: 720px) {
        grid-template-columns: auto auto auto;
      }

      li {
        display: flex;
        align-items: center;
        background-color: var(--color-box-bg);
        padding: 0.25rem;
        font-size: 1rem;

        a {
          display: flex;
          flex: 1;
          flex-direction: row;
          align-items: center;
          text-align: left;
          margin-left: 0.25rem;
          margin-right: 0.25rem;

          div {
            flex: 1;
          }
        }
      }
    }
  }
}

/* Nested under .cv-page — this ships in the site-wide bundle.css, and a
   bare h1/.pdf selector would otherwise leak onto every other page's
   h1/.pdf, the same mistake posts-index.css made before it got dropped
   from the merge entirely (see eleventy.config.js's CSS_FILES_TO_MERGE
   comment). */
.cv-page {
  h1 {
    display: flex;
    align-items: flex-start;
    font-weight: 800;
    font-size: var(--fs-hero-xl);
    margin-bottom: 1rem;

    a {
      margin-left: 0.4rem;
      margin-top: 0.8rem;
      color: var(--color-link);
    }
  }

  .pdf {
    border: 1px solid black;
  }
}
