/*
 * Noto Sans and Noto Sans Mono (SIL OFL 1.1, see NotoSans-OFL.txt), self-hosted and subset to Latin.
 * Chosen from reading research: Noto Sans scored highly on both preference and reading
 * effectiveness across 16 fonts (Wallace et al., ACM TOCHI 2022). The italic and mono
 * files only download on pages that use them.
 */
@font-face { font-family: "Noto Sans"; src: url("noto-sans-1.woff2") format("woff2"); font-weight: 400 800; font-style: normal; font-display: swap; }
@font-face { font-family: "Noto Sans"; src: url("noto-sans-italic-1.woff2") format("woff2"); font-weight: 400 600; font-style: italic; font-display: swap; }
@font-face { font-family: "Noto Sans Mono"; src: url("noto-sans-mono-1.woff2") format("woff2"); font-weight: 400 600; font-style: normal; font-display: swap; }
/* Metric-matched fallback keeps the layout steady while the web font swaps in. */
@font-face { font-family: "Noto Sans Fallback"; src: local("Arial"), local("Helvetica"); size-adjust: 106.3%; ascent-override: 100.5%; descent-override: 27.6%; line-gap-override: 0%; }

@layer reset, base, layout, components, article, motion, responsive;

@layer reset {
  *, *::before, *::after { box-sizing: border-box; }
  body, h1, h2, h3, h4, p, figure, ul, ol { margin: 0; }
  ul[class], ol[class] { padding: 0; list-style: none; }
  button, input, textarea, select { font: inherit; color: inherit; }
  button, a, input, select, textarea { -webkit-tap-highlight-color: transparent; }
  img, svg { max-width: 100%; }
  img { height: auto; }
  [hidden] { display: none !important; }
}

@layer base {
  /*
   * One definition per token for both themes. Light is the default reading mode (NN/g);
   * dark uses a dark grey rather than black and desaturated accents (Material), with
   * off-white text to limit halation. Neutrals lean warm, not blue-grey: warm backgrounds
   * read faster than cool ones (Rello & Bigham, ASSETS 2017).
   */
  :root {
    color-scheme: light;
    --paper: light-dark(#ffffff, #171716);
    --surface: light-dark(#ffffff, #1e1e1d);
    --raised: light-dark(#f7f6f3, #212120);
    --ink: light-dark(#1c1b19, #eeece8);
    --ink-soft: light-dark(#3a3935, #d0cec8);
    --muted: light-dark(#6d6b65, #9e9b94);
    --line: light-dark(#e8e6e1, #31302d);
    --chip: light-dark(#f2f1ed, #292927);
    --accent: light-dark(#1d5ad1, #93b6ff);
    --on-accent: light-dark(#ffffff, #171716);
    --mark: #ffe066;
    /* The floating badge stays dark in both themes so its yellow dot always reads. */
    --badge: light-dark(#1c1b19, #2e2d2a);
    --on-badge: light-dark(#ffffff, #eeece8);
    --mark-ink: #1c1b19;
    --swipe: light-dark(#ffe58a, rgb(255 224 102 / .3));
    --ring: light-dark(rgb(29 90 209 / .2), rgb(147 182 255 / .25));
    --danger: light-dark(#b42318, #ff9e92);
    --tok-comment: light-dark(#6d6b65, #8f8c86);
    --tok-keyword: light-dark(#7a2db0, #cfaeff);
    --tok-string: light-dark(#0f7048, #95d5a8);
    --tok-number: light-dark(#ad3f17, #ffb48f);
    --tok-variable: light-dark(#a02d63, #f4a8ca);
    --tok-function: light-dark(#1d5ad1, #93b6ff);
    --tok-type: light-dark(#8a5300, #ffd47a);
    --sans: "Noto Sans", "Noto Sans Fallback", system-ui, sans-serif;
    --mono: "Noto Sans Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
    /* 46rem at 20px is ~75 characters per line: inside WCAG 1.4.8's 80. */
    --column: 46rem;
    --shell: 76rem;
    --gutter: clamp(1.25rem, 4vw, 3rem);
    --ease: cubic-bezier(.2, .8, .2, 1);
  }
  :root[data-theme="light"] { color-scheme: light; }
  :root[data-theme="dark"] { color-scheme: dark; }
  html { scroll-behavior: smooth; scroll-padding-top: 2rem; -webkit-text-size-adjust: 100%; }
  body {
    color: var(--ink-soft); background: var(--paper);
    font-family: var(--sans); font-size: 1rem; line-height: 1.6;
    -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility;
  }
  ::selection { background: var(--mark); color: var(--mark-ink); }
  a { color: var(--ink); text-decoration-thickness: 1px; text-underline-offset: .2em; }
  :focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 3px; }
  main:focus { outline: none; }
  button { cursor: pointer; }
  h1, h2, h3, h4 { color: var(--ink); font-weight: 700; line-height: 1.2; letter-spacing: -.02em; text-wrap: balance; }
  p { text-wrap: pretty; }
  input, textarea, select {
    min-width: 0; padding: .75rem 1rem; border: 1px solid var(--line); border-radius: 10px;
    background: var(--surface); color: var(--ink); font-size: 1rem;
  }
  input:focus-visible, textarea:focus-visible, select:focus-visible { outline: none; border-color: var(--accent); box-shadow: 0 0 0 4px var(--ring); }
  input, textarea { width: 100%; }
  textarea { resize: vertical; line-height: 1.6; }
  input::placeholder, textarea::placeholder { color: var(--muted); opacity: 1; }
  label { display: block; font-size: .9375rem; font-weight: 600; color: var(--ink); }
  label span { font-weight: 400; color: var(--muted); }
  label + input, label + textarea { margin-top: .4rem; }
  .sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
  .skip-link { position: fixed; top: -100px; left: 1rem; z-index: 10; padding: .6rem 1rem; border-radius: 8px; background: var(--ink); color: var(--paper); }
  .skip-link:focus { top: 1rem; }
  .muted { color: var(--muted); }
}

@layer layout {
  .shell { max-width: var(--shell); margin-inline: auto; padding-inline: var(--gutter); }
  /* Full-width rules mark where the site chrome ends and the page begins. */
  .site-header { border-bottom: 1px solid var(--line); }
  .site-header-inner { display: flex; align-items: center; justify-content: space-between; gap: 1.5rem; min-height: 4.5rem; }
  .brand { display: inline-flex; align-items: center; gap: .75rem; color: var(--ink); text-decoration: none; }
  /* The header's IA badge matches the floating badge, so when the header scrolls away the badge seems to stay with the reader. */
  .brand-badge {
    display: inline-grid; place-items: center; width: 2.125rem; height: 2.125rem; flex: none; margin-right: -.25rem;
    border-radius: 50%; background: var(--badge); color: var(--on-badge);
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--on-badge) 14%, transparent);
    font-size: .8125rem; font-weight: 800; letter-spacing: -.04em; line-height: 1;
    transition: scale .25s var(--ease), rotate .25s var(--ease);
  }
  .brand-badge > span { display: inline-flex; align-items: baseline; }
  .brand-badge i { width: .3em; height: .3em; margin-left: .1em; border-radius: 50%; background: var(--mark); }
  .brand:hover .brand-badge { scale: 1.06; rotate: -6deg; }
  .brand-name { font-weight: 700; letter-spacing: -.01em; color: var(--ink); white-space: nowrap; }
  .brand-tagline { padding-left: .75rem; border-left: 1px solid var(--line); color: var(--muted); font-size: .9375rem; }
  .site-header nav { display: flex; align-items: center; gap: 1.75rem; }
  .site-header nav a { color: var(--muted); font-weight: 500; }
  .site-footer { margin-top: 8rem; border-top: 1px solid var(--line); font-size: .9375rem; color: var(--muted); }
  .site-footer-inner { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 1rem 2rem; padding-block: 2rem; }
  .site-footer .footer-name { margin-right: .5rem; }
  .footer-links { display: flex; align-items: center; gap: 1rem; }
}

@layer components {
  /* Quiet underline that draws in on hover: header and footer links. */
  .brand-name, .site-header nav a, .toc a {
    text-decoration: none;
    background: linear-gradient(currentColor, currentColor) no-repeat 0 100% / 0 1px;
    transition: background-size .25s var(--ease), color .2s;
  }
  .brand:hover .brand-name, .site-header nav a:hover, .toc a:hover, .site-header nav [aria-current="page"] {
    color: var(--ink); background-size: 100% 1px;
  }
  /* The footer name links to LinkedIn: the icon says so, and the name gets the same drawn underline on hover. */
  .footer-name { display: inline-flex; align-items: center; gap: .45rem; color: var(--ink); text-decoration: none; vertical-align: bottom; }
  .footer-name svg { flex: none; color: var(--muted); transition: color .2s; }
  .footer-name:hover svg { color: var(--accent); }
  .footer-name:hover .brand-name { background-size: 100% 1px; }

  .icon-link {
    display: inline-grid; place-items: center; width: 2.25rem; height: 2.25rem; border-radius: 50%; color: var(--muted);
    transition: color .2s, background-color .2s, transform .15s var(--ease);
  }
  .icon-link:hover { color: var(--ink); background: var(--chip); }
  .icon-link:active { transform: scale(.9); }

  .theme-toggle {
    display: inline-grid; place-items: center; width: 2.25rem; height: 2.25rem; padding: 0;
    border: 0; border-radius: 50%; background: transparent; color: var(--muted);
    transition: color .2s, background-color .2s, transform .15s var(--ease);
  }
  .theme-toggle:hover { color: var(--ink); background: var(--chip); }
  .theme-toggle:active { transform: scale(.9); }
  .theme-toggle svg { grid-area: 1 / 1; transition: opacity .3s, transform .5s var(--ease); }
  .theme-toggle .icon-sun, :root[data-theme="dark"] .theme-toggle .icon-moon { opacity: 0; transform: rotate(-90deg) scale(.5); }
  :root[data-theme="dark"] .theme-toggle .icon-sun { opacity: 1; transform: none; }
  .theme-toggle[x-cloak] { display: inline-grid !important; visibility: hidden; }
  :root:not([data-theme]) .theme-toggle { display: none !important; }

  /*
   * Floating badge: fades in once the header has scrolled away. Opening it slides a pill out
   * from behind the circle and eases the icons in one after another. Every moving property is
   * opacity, scale, rotate, or translate, so the browser animates it on the compositor, and
   * one deceleration curve without overshoot keeps the parts moving together.
   */
  .dock {
    position: fixed; top: 1rem; left: 1rem; z-index: 20;
    visibility: hidden; opacity: 0; scale: .7; rotate: -20deg; transform-origin: 1.625rem 1.625rem;
    transition: opacity .25s var(--ease), scale .4s var(--ease), rotate .4s var(--ease), visibility 0s .4s;
  }
  .dock.is-shown { visibility: visible; opacity: 1; scale: 1; rotate: 0deg; transition-delay: 0s; }
  .dock-toggle {
    position: relative; z-index: 2; display: grid; place-items: center; width: 3.25rem; height: 3.25rem; padding: 0;
    border: 0; border-radius: 50%; background: var(--badge); color: var(--on-badge);
    box-shadow: 0 0 0 3px var(--paper), 0 0 0 4px var(--line), 0 10px 24px -8px rgb(0 0 0 / .45);
    transition: scale .25s var(--ease);
  }
  .dock-toggle:hover { scale: 1.04; }
  .dock-toggle:active { scale: .96; transition-duration: .1s; }
  .dock-initials, .dock-close { grid-area: 1 / 1; transition: opacity .2s var(--ease), rotate .35s var(--ease), scale .35s var(--ease); }
  .dock-initials { display: inline-flex; align-items: baseline; font-size: 1.0625rem; font-weight: 800; letter-spacing: -.04em; }
  .dock-initials i { width: .3em; height: .3em; margin-left: .1em; border-radius: 50%; background: var(--mark); }
  .dock-close { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; opacity: 0; rotate: -90deg; scale: .6; }
  .is-open .dock-initials { opacity: 0; rotate: 90deg; scale: .6; }
  .is-open .dock-close { opacity: 1; rotate: 0deg; scale: 1; }
  .dock-menu {
    position: absolute; top: 50%; left: 1.625rem; z-index: 1;
    display: flex; gap: .2rem; padding: .3rem .35rem .3rem 2.15rem;
    border: 1px solid var(--line); border-radius: 999px; background: var(--surface);
    box-shadow: 0 14px 34px -14px rgb(0 0 0 / .35);
    /* Closed, the pill waits just behind the circle; the short travel keeps its left end hidden while it moves. */
    opacity: 0; translate: -1.25rem -50%; visibility: hidden; pointer-events: none;
    transition: opacity .15s var(--ease), translate .25s var(--ease), visibility 0s .25s;
  }
  .is-open .dock-menu {
    opacity: 1; translate: 0 -50%; visibility: visible; pointer-events: auto;
    transition: opacity .2s var(--ease), translate .4s var(--ease), visibility 0s;
  }
  .dock-item {
    --delay: 0s;
    position: relative; display: grid; place-items: center; width: 2.6rem; height: 2.6rem; padding: 0;
    border: 0; border-radius: 50%; background: transparent; color: var(--ink-soft);
    opacity: 0; translate: -.6rem 0;
    transition: opacity .15s, translate .2s var(--ease), background-color .2s, color .2s;
  }
  .is-open .dock-item {
    opacity: 1; translate: 0 0;
    transition: opacity .25s var(--ease) var(--delay), translate .4s var(--ease) var(--delay), background-color .2s, color .2s;
  }
  .is-open .dock-item:nth-child(1) { --delay: .04s; }
  .is-open .dock-item:nth-child(2) { --delay: .08s; }
  .is-open .dock-item:nth-child(3) { --delay: .12s; }
  .is-open .dock-item:nth-child(4) { --delay: .16s; }
  .dock-item:hover, .dock-item:focus-visible { background: var(--chip); color: var(--ink); }
  .dock-item[aria-current="page"] { color: var(--accent); }
  .dock-item svg { grid-area: 1 / 1; width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
  .dock-theme svg { transition: opacity .3s, rotate .5s var(--ease), scale .5s var(--ease); }
  .dock-theme .icon-sun, :root[data-theme="dark"] .dock-theme .icon-moon { opacity: 0; rotate: -90deg; scale: .5; }
  :root[data-theme="dark"] .dock-theme .icon-sun { opacity: 1; rotate: 0deg; scale: 1; }
  .dock-tip {
    position: absolute; top: calc(100% + .45rem); left: 50%; translate: -50% -4px;
    padding: .15rem .5rem; border-radius: 6px; background: var(--ink); color: var(--paper);
    font-size: .75rem; font-weight: 600; white-space: nowrap; opacity: 0; pointer-events: none;
    transition: opacity .15s, translate .2s var(--ease);
  }
  .dock-item:hover .dock-tip, .dock-item:focus-visible .dock-tip { opacity: 1; translate: -50% 0; }

  .intro { padding-block: 4.5rem 5rem; }
  .intro-title { font-size: clamp(3.5rem, 15vw, 9rem); line-height: .95; font-weight: 800; letter-spacing: -.05em; }
  .intro-lede { max-width: 48rem; margin-top: 2.25rem; font-size: clamp(1.125rem, 2.2vw, 1.375rem); line-height: 1.6; }
  /* With a portrait, the photo takes the right column and the greeting scales down to make room. */
  .intro.has-portrait { display: grid; grid-template-columns: minmax(0, 1fr) clamp(10rem, 22vw, 18rem); column-gap: clamp(2rem, 5vw, 4rem); align-items: start; }
  .intro.has-portrait > * { grid-column: 1; }
  .has-portrait .intro-title { font-size: clamp(3.5rem, 11vw, 9rem); }
  .portrait {
    grid-column: 2 !important; grid-row: 1 / span 3; width: 100%; aspect-ratio: 4 / 5; object-fit: cover;
    border-radius: 1.5rem; background: var(--chip); rotate: 2deg; box-shadow: -14px 14px 0 var(--mark);
    transition: rotate .5s var(--ease), scale .5s var(--ease), box-shadow .5s var(--ease);
  }
  .portrait:hover { rotate: 0deg; scale: 1.02; box-shadow: -8px 8px 0 var(--mark); }
  .topics { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; margin-top: 2rem; }
  .topics > span { margin-right: .5rem; font-size: .9375rem; color: var(--muted); }

  /* Highlighter swipe: answers hovering a reading link. */
  .post-row h3 a, .prose a, .filter-summary a {
    text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
    background: linear-gradient(var(--swipe), var(--swipe)) no-repeat 0 88% / 0 .4em;
    transition: background-size .3s var(--ease), color .2s;
  }
  .post-row h3 a:hover, .prose a:hover, .filter-summary a:hover { color: var(--ink); background-size: 100% .4em; }
  .post-row h3 a { text-decoration: none; }

  /* Section headings sit on a rule, so each part of the page has a visible start. */
  .list-header, .section-title { display: flex; flex-wrap: wrap; align-items: end; justify-content: space-between; gap: 1rem 2rem; padding-bottom: 1rem; border-bottom: 1px solid var(--ink); }
  .list-header h2, .section-title { font-size: 1.375rem; }
  .topic-title { font-size: clamp(2.5rem, 7vw, 4rem); font-weight: 800; letter-spacing: -.04em; margin-top: 3rem; line-height: 1.05; }
  .search-form { position: relative; width: min(100%, 22rem); }
  .search-form input { height: 2.75rem; padding-left: 2.6rem; border-radius: 999px; }
  .search-form input::-webkit-search-cancel-button { cursor: pointer; }
  .search-icon { position: absolute; left: 1rem; top: 50%; translate: 0 -50%; color: var(--muted); pointer-events: none; transition: color .2s; }
  .search-form:focus-within .search-icon { color: var(--accent); }
  .filter-summary { margin-top: .75rem; font-size: .9375rem; color: var(--muted); }
  .local-loader { margin-top: .75rem; font-size: .9375rem; color: var(--muted); }
  .spinner { display: inline-block; width: .85em; height: .85em; margin-right: .4em; border: 2px solid var(--line); border-top-color: var(--accent); border-radius: 50%; vertical-align: -.1em; animation: spin .7s linear infinite; }
  @keyframes spin { to { transform: rotate(360deg); } }
  .is-updating { opacity: .5; transition: opacity .2s; }

  .button {
    display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
    padding: .7rem 1.25rem; border: 1px solid var(--line); border-radius: 10px;
    background: var(--surface); color: var(--ink); font-size: .9375rem; font-weight: 600; text-decoration: none; white-space: nowrap;
    transition: background-color .2s, border-color .2s, color .2s, transform .15s var(--ease);
  }
  .button:hover { border-color: var(--muted); }
  .button:active { transform: scale(.97); }
  .button-primary { border-color: var(--ink); background: var(--ink); color: var(--paper); }
  .button-primary:hover { border-color: var(--accent); background: var(--accent); color: var(--on-accent); }
  button:disabled { cursor: wait; opacity: .6; transform: none; }

  .post-row { padding-block: 2rem; border-bottom: 1px solid var(--line); }
  .post-row h3 { width: fit-content; max-width: 100%; font-size: 1.5rem; line-height: 1.3; }
  .post-row > p:not(.post-meta) { max-width: var(--column); margin-top: .5rem; font-size: 1.0625rem; }
  /* Covers: the author's image, or a pattern generated from the title. Hovering the row eases the cover in. */
  .post-cover { display: block; aspect-ratio: 3 / 2; overflow: hidden; border-radius: 12px; background: var(--chip); }
  .post-cover > img, .post-cover > svg { display: block; width: 100%; height: 100%; object-fit: cover; transition: scale .6s var(--ease); }
  .post-row:hover .post-cover > * { scale: 1.04; }
  /* Main list: cover on the left, text on the right. */
  .writing .post-row { display: grid; grid-template-columns: clamp(12rem, 22vw, 17rem) minmax(0, 1fr); grid-template-rows: auto auto 1fr; column-gap: 2.5rem; }
  .writing .post-row > * { grid-column: 2; }
  .writing .post-row > .post-cover { grid-column: 1; grid-row: 1 / span 3; }
  .writing .post-row h3 { margin-top: .25rem; font-size: 1.75rem; letter-spacing: -.025em; }
  .related .post-list { display: grid; grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr)); column-gap: 3rem; }
  .related .post-row { border-bottom: 0; }
  .related .post-cover { margin-bottom: 1rem; }
  .post-meta { display: flex; flex-wrap: wrap; gap: .1rem 1rem; margin-top: .6rem; font-size: .875rem; color: var(--muted); }

  .tag {
    display: inline-flex; align-items: center; padding: .2rem .6rem; border-radius: 6px;
    background: var(--chip); color: var(--ink-soft); font-size: .8125rem; font-weight: 500; text-decoration: none;
    transition: background-color .2s, color .2s;
  }
  .tag:hover { background: var(--mark); color: var(--mark-ink); }

  .pagination { display: flex; justify-content: space-between; gap: 1rem; padding-block: 2.5rem; font-size: .9375rem; color: var(--muted); }
  .pagination [aria-disabled] { opacity: .5; }

  .empty-state { max-width: var(--column); padding-block: 3rem; }
  .empty-state h1 { font-size: clamp(2.5rem, 7vw, 4rem); font-weight: 800; letter-spacing: -.04em; }
  .empty-state h2, .empty-state h3 { font-size: 1.375rem; }
  .empty-state p { margin-block: .75rem 1rem; }

  .notice { margin-block: 1rem; padding: .9rem 1.1rem; border-radius: 10px; background: var(--raised); color: var(--ink); }
  .field-error { margin-block: .4rem; font-size: .875rem; color: var(--danger); }
  .inline-success { margin-top: .6rem; font-size: .875rem; color: var(--accent); }

  .about { max-width: 64rem; padding-top: 4rem; }
  .about h1 { font-size: clamp(2.75rem, 8vw, 5rem); font-weight: 800; letter-spacing: -.045em; }
  .about-role { margin-top: 1.5rem; color: var(--ink); font-size: clamp(1.25rem, 2.5vw, 1.75rem); font-weight: 600; letter-spacing: -.02em; }
  .about-role span { text-decoration: underline; text-decoration-color: var(--mark); text-decoration-thickness: .2em; text-underline-offset: .18em; }
  .about-intro { max-width: var(--column); margin-top: 1.25rem; font-size: 1.125rem; line-height: 1.75; }
  .about-facts { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 2rem; margin: 2.75rem 0 0; padding-block: 1.75rem; border-block: 1px solid var(--line); }
  .about-facts dt { color: var(--ink); font-size: clamp(1.25rem, 2.2vw, 1.625rem); font-weight: 750; line-height: 1.3; letter-spacing: -.035em; }
  .about-facts dd { max-width: 28ch; margin: .5rem 0 0; font-size: .9375rem; color: var(--muted); }
  .about-section { margin-top: 3.5rem; }
  .about-section-title { margin-bottom: 1.75rem; font-size: 1.375rem; }
  .about-strengths { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 2.25rem; }
  .about-strengths h3 { font-size: 1.125rem; }
  .about-strengths p { margin-top: 1rem; line-height: 1.7; }
  .about-technologies { display: flex; flex-wrap: wrap; align-content: flex-start; gap: .4rem; margin-top: 1rem; }
  .about-technologies li { padding: .25rem .6rem; border-radius: 5px; background: var(--chip); color: var(--ink); font-size: .8125rem; font-weight: 600; line-height: 1.5; }
  .about-frontend { margin-top: 2rem; padding-top: 1.5rem; border-top: 1px solid var(--line); font-size: .9375rem; }
  .about-frontend h3 { font-size: 1rem; color: var(--muted); }
  .about-frontend-stack { margin-top: .6rem; color: var(--ink-soft); font-weight: 500; }
  .about-frontend > p:last-child { max-width: var(--column); margin-top: .5rem; color: var(--muted); }
  .about-experience { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 2.25rem; }
  .about-experience article { padding-left: 1.25rem; border-left: 3px solid var(--mark); }
  .about-experience h3 { font-size: 1.25rem; }
  .about-experience h3 span { color: var(--muted); font-weight: 500; }
  .about-position { margin-top: .5rem; font-size: .9375rem; color: var(--muted); }
  .about-experience article > p:last-child { margin-top: .75rem; line-height: 1.7; }
  .about-principles > p { max-width: var(--column); line-height: 1.75; }
  .about-principles > p + p { margin-top: 1rem; }
  .about-links { display: flex; flex-wrap: wrap; gap: 1.5rem; margin-top: 1.5rem; }
  .about-links a { display: inline-flex; gap: .5rem; align-items: center; padding-block: .25rem; font-weight: 600; }
  .about + .related .post-list { grid-template-columns: repeat(auto-fill, minmax(min(100%, 20rem), 1fr)); }
  .about-side-projects { max-width: var(--column); padding-top: 1.5rem; border-top: 1px solid var(--line); font-size: .9375rem; }
  .about-side-projects .about-section-title { margin-bottom: .75rem; color: var(--muted); font-size: 1.125rem; }
  .about-project-list { display: grid; gap: .4rem; }
  .about-project-list li { position: relative; padding-left: 1rem; }
  .about-project-list li::before { content: "•"; position: absolute; left: 0; color: var(--muted); }
  .about-project-list strong { font-weight: 600; }


  .related { margin-top: 6rem; }
  .discussion h2 { font-size: 1.375rem; }

  .auth-panel { max-width: 26rem; padding-top: 3rem; }
  .auth-panel h1 { font-size: 2.5rem; font-weight: 800; letter-spacing: -.04em; }
  .auth-panel > .muted { margin-top: .5rem; }
  .auth-panel form { margin-top: 2rem; }
  .auth-panel input + label, .auth-panel .field-error + label { margin-top: 1.25rem; }
  .auth-panel button { margin-top: 1.5rem; }

  .section-heading { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 1rem; }
  .moderation { max-width: 56rem; padding-top: 3rem; }
  .moderation h1 { font-size: 2.25rem; }
  .moderation-card { margin-block: 1rem; padding: 1.5rem; border: 1px solid var(--line); border-radius: 12px; }
  .moderation-card header { display: flex; align-items: center; gap: .75rem; color: var(--ink); }
  .moderation-card .post-meta { margin-block: .5rem .75rem; }
  .moderation-card form { display: flex; flex-wrap: wrap; gap: .6rem; margin-top: 1.25rem; }
  .comment-text, .comment > p { white-space: pre-wrap; overflow-wrap: anywhere; }
  [wire\:cloak], [x-cloak] { display: none !important; }
}

@layer components {
  /*
   * Background sketches: faint engineering drawings in the page margins. Rules and how to add
   * one are in docs/architecture.md ("Background sketches").
   * - Each drawing is an SVG used as a CSS mask and filled with --sketch, so one file serves
   *   light and dark mode.
   * - They live only in the empty side margins, never behind text or controls, so they show
   *   from 1408px wide and fade out before the footer.
   * - Motion is slow enough to be noticed only after a while: inside the files, dots travel
   *   the connectors, dashes creep and nodes breathe; here, each drawing drifts a few pixels
   *   over about a minute. Reduced motion stops the drift and swaps in still copies, because
   *   browsers don't reliably pass that preference into SVG images.
   */
  :root { --sketch: light-dark(rgb(29 90 209 / .14), rgb(147 182 255 / .12)); }
  body { position: relative; isolation: isolate; overflow-x: clip; }
  .sketches {
    position: absolute; inset: 0; z-index: -1; display: none; overflow: clip; pointer-events: none;
    mask-image: linear-gradient(#000 calc(100% - 18rem), transparent calc(100% - 7rem));
  }
  .sketch {
    /*
     * Sit in the margin, 2rem clear of the text column. Where the margin is narrow, a drawing
     * may slide up to 45% off the screen edge, then shrinks, so it never reaches the text.
     */
    --size: clamp(9rem, calc((50% - 37rem) / .6), var(--w));
    --inset: max(calc(50% - 37rem - var(--size)), calc(var(--size) * -.45));
    position: absolute; top: var(--top); width: var(--size); aspect-ratio: var(--ratio);
    background: var(--sketch);
    mask-position: center; mask-size: contain; mask-repeat: no-repeat;
    animation: sketch-drift 64s ease-in-out infinite alternate;
    will-change: translate;
  }
  @keyframes sketch-drift {
    from { translate: 0 0; }
    50% { translate: 9px -6px; }
    to { translate: -6px 5px; }
  }
  .sketch:nth-child(odd) { left: var(--inset); }
  .sketch:nth-child(even) { right: var(--inset); }
  .sketch-cache { mask-image: url("sketch-cache.svg"); --w: 12rem; --ratio: 320 / 470; }
  .sketch-cluster { mask-image: url("sketch-cluster.svg"); --w: 14rem; --ratio: 1; }
  .sketch-deploy { mask-image: url("sketch-deploy.svg"); --w: 12rem; --ratio: 280 / 540; }
  .sketch-git { mask-image: url("sketch-git.svg"); --w: 10rem; --ratio: 280 / 560; }
  .sketch-queue { mask-image: url("sketch-queue.svg"); --w: 16rem; --ratio: 460 / 170; }
  .sketch-sequence { mask-image: url("sketch-sequence.svg"); --w: 14rem; --ratio: 380 / 440; }
  .sketch-split { mask-image: url("sketch-split.svg"); --w: 15rem; --ratio: 440 / 260; }
  .sketch-stack { mask-image: url("sketch-stack.svg"); --w: 11rem; --ratio: 360 / 560; }
  .sketch-states { mask-image: url("sketch-states.svg"); --w: 12rem; --ratio: 1; }
  .sketch-tables { mask-image: url("sketch-tables.svg"); --w: 15rem; --ratio: 400 / 300; }
  .sketch-tree { mask-image: url("sketch-tree.svg"); --w: 11rem; --ratio: 300 / 520; }
  /* Alternate sides, about every 20rem; uneven drift timings keep neighbours from moving together. */
  .sketch:nth-child(1) { --top: 6rem; animation-duration: 61s; }
  .sketch:nth-child(2) { --top: 12rem; animation-duration: 55s; animation-delay: -14s; }
  .sketch:nth-child(3) { --top: 40rem; animation-duration: 67s; animation-delay: -21s; }
  .sketch:nth-child(4) { --top: 50rem; animation-duration: 59s; animation-delay: -28s; }
  .sketch:nth-child(5) { --top: 80rem; animation-duration: 72s; animation-delay: -35s; }
  .sketch:nth-child(6) { --top: 92rem; animation-duration: 57s; animation-delay: -2s; }
  .sketch:nth-child(7) { --top: 122rem; animation-duration: 63s; animation-delay: -9s; }
  .sketch:nth-child(8) { --top: 134rem; animation-duration: 69s; animation-delay: -16s; }
  .sketch:nth-child(9) { --top: 162rem; animation-duration: 58s; animation-delay: -23s; }
  .sketch:nth-child(10) { --top: 176rem; animation-duration: 65s; animation-delay: -30s; }
  .sketch:nth-child(11) { --top: 204rem; animation-duration: 60s; animation-delay: -37s; }
  .sketch:nth-child(12) { --top: 218rem; animation-duration: 71s; animation-delay: -4s; }
  .sketch:nth-child(13) { --top: 246rem; animation-duration: 54s; animation-delay: -11s; }
  .sketch:nth-child(14) { --top: 260rem; animation-duration: 66s; animation-delay: -18s; }
  .sketch:nth-child(15) { --top: 290rem; animation-duration: 62s; animation-delay: -25s; }
  .sketch:nth-child(16) { --top: 304rem; animation-duration: 68s; animation-delay: -32s; }
  .sketch:nth-child(17) { --top: 334rem; animation-duration: 56s; animation-delay: -39s; }
  .sketch:nth-child(18) { --top: 348rem; animation-duration: 64s; animation-delay: -6s; }
  /* Only where the page has real margins: 1408px and wider. */
  @media (min-width: 88rem) { .sketches { display: block; } }
  @media (prefers-reduced-motion: reduce) {
    .sketch { animation: none; }
    .sketch-cache { mask-image: url("sketch-cache-still.svg"); }
    .sketch-cluster { mask-image: url("sketch-cluster-still.svg"); }
    .sketch-deploy { mask-image: url("sketch-deploy-still.svg"); }
    .sketch-git { mask-image: url("sketch-git-still.svg"); }
    .sketch-queue { mask-image: url("sketch-queue-still.svg"); }
    .sketch-sequence { mask-image: url("sketch-sequence-still.svg"); }
    .sketch-split { mask-image: url("sketch-split-still.svg"); }
    .sketch-stack { mask-image: url("sketch-stack-still.svg"); }
    .sketch-states { mask-image: url("sketch-states-still.svg"); }
    .sketch-tables { mask-image: url("sketch-tables-still.svg"); }
    .sketch-tree { mask-image: url("sketch-tree-still.svg"); }
  }
  @media print { .sketches { display: none; } }
}

@layer article {
  .article-header { margin-bottom: 3.5rem; padding-block: 3.5rem 2.5rem; border-bottom: 1px solid var(--line); }
  .article-header .post-meta { align-items: center; margin: 0 0 1.25rem; }
  .article-header h1 { width: fit-content; max-width: 60rem; font-size: clamp(2.5rem, 6vw, 4.5rem); line-height: 1.05; font-weight: 800; letter-spacing: -.04em; }
  .article-deck { max-width: 52rem; margin-top: 1.5rem; font-size: clamp(1.125rem, 2.2vw, 1.375rem); line-height: 1.6; }
  .tags { display: flex; flex-wrap: wrap; gap: .4rem; margin-top: 1.75rem; }
  .article-cover { margin-top: 2.5rem; }
  .article-cover img { display: block; width: 100%; max-height: 34rem; object-fit: cover; border-radius: 16px; background: var(--chip); }

  /* Download control: a visible chip, the arrow drops on hover like a download starting. */
  .pdf-link {
    display: inline-flex; align-items: center; gap: .4rem; margin-left: auto; padding: .35rem .8rem .35rem .6rem;
    border: 1px solid var(--line); border-radius: 999px; color: var(--ink); font-weight: 600; text-decoration: none;
    transition: color .2s, background-color .2s, border-color .2s, transform .15s var(--ease);
  }
  .pdf-link svg { color: var(--accent); transition: color .2s; }
  .pdf-link .pdf-arrow { transition: translate .25s var(--ease); }
  .pdf-link:hover { border-color: var(--accent); background: var(--accent); color: var(--on-accent); }
  .pdf-link:hover svg { color: inherit; }
  .pdf-link:hover .pdf-arrow { translate: 0 1.5px; }
  .pdf-link:active { transform: scale(.96); }

  .article-layout { display: grid; grid-template-columns: minmax(0, var(--column)) minmax(0, 15rem); justify-content: space-between; gap: 4rem; align-items: start; }
  .article-main { grid-column: 1; grid-row: 1; min-width: 0; }
  .toc { grid-column: 2; grid-row: 1; position: sticky; top: 2rem; padding-left: 1.25rem; border-left: 1px solid var(--line); font-size: .875rem; }
  .toc h2 { font-size: .875rem; color: var(--muted); font-weight: 600; letter-spacing: 0; }
  .toc ol { margin-top: .75rem; padding: 0; list-style: none; }
  .toc li { position: relative; }
  .toc li + li { margin-top: .6rem; }
  .toc a { color: var(--muted); line-height: 1.4; }
  .toc a[aria-current="location"] { color: var(--accent); font-weight: 600; }
  .toc a[aria-current="location"]::before { content: ""; position: absolute; left: calc(-1.25rem - 2px); top: 0; bottom: 0; width: 3px; border-radius: 2px; background: currentColor; }

  .takeaway { margin-bottom: 3rem; padding-left: 1.25rem; border-left: 3px solid var(--mark); }
  .takeaway h2 { font-size: .9375rem; }
  .takeaway p { margin-top: .25rem; font-size: 1.125rem; color: var(--ink); }

  /* 20px body, ~75 characters per line, 1.65 leading: within Butterick's and WCAG 1.4.8 ranges. */
  .prose { font-size: 1.25rem; line-height: 1.65; overflow-wrap: break-word; }
  .prose > :first-child, .prose > section:first-child > :first-child { margin-top: 0; }
  .prose p, .prose ul, .prose ol, .prose blockquote { margin-block: 1.2em; }
  .prose ul, .prose ol { padding-left: 1.3em; }
  .prose li + li { margin-top: .4em; }
  .prose li::marker { color: var(--muted); }
  .prose h2 { margin-block: 2.2em .6em; font-size: 1.625rem; letter-spacing: -.025em; }
  .prose h3 { margin-block: 1.8em .5em; font-size: 1.25rem; }
  .prose h4, .prose h5, .prose h6 { margin-block: 1.6em .5em; font-size: 1.125rem; }
  .prose strong { color: var(--ink); font-weight: 650; }
  .prose a { color: var(--accent); }
  .prose hr { margin-block: 3rem; border: 0; border-top: 1px solid var(--line); }
  .prose code { font-family: var(--mono); font-size: .875em; padding: .12em .35em; border-radius: 5px; background: var(--chip); color: var(--ink); }
  .prose pre, .code-block { margin-block: 1.75rem; }
  .prose pre { padding: 1.1rem 1.25rem; border-radius: 10px; overflow-x: auto; background: var(--raised); color: var(--ink); font-size: .9375rem; line-height: 1.65; tab-size: 4; }
  .code-block { position: relative; }
  .code-block > pre { margin: 0; }
  .prose pre code { padding: 0; border-radius: 0; background: none; font-size: inherit; }
  .tok-comment { color: var(--tok-comment); font-style: italic; }
  .tok-keyword, .tok-tag { color: var(--tok-keyword); }
  .tok-string { color: var(--tok-string); }
  .tok-number { color: var(--tok-number); }
  .tok-variable { color: var(--tok-variable); }
  .tok-function { color: var(--tok-function); }
  .tok-type, .tok-attribute { color: var(--tok-type); }
  .copy-code {
    position: absolute; top: .55rem; right: .55rem; display: inline-flex; align-items: center; gap: .35rem; padding: .2rem .6rem .2rem .5rem; border: 1px solid var(--line); border-radius: 6px;
    background: var(--surface); color: var(--muted); font-family: var(--sans); font-size: .8125rem;
    transition: opacity .2s, color .2s, border-color .2s, transform .15s var(--ease);
  }
  .copy-code:hover { color: var(--ink); border-color: var(--muted); }
  .copy-code:active { transform: scale(.95); }
  .copy-code.is-copied { color: var(--accent); border-color: var(--accent); }
  .copy-code svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
  @media (hover: hover) {
    .copy-code { opacity: 0; }
    .code-block:hover .copy-code, .copy-code:focus-visible, .copy-code.is-copied { opacity: 1; }
  }
  .prose figure { margin-block: 2.25rem; }
  .prose figure img { display: block; width: 100%; border-radius: 10px; }
  /* Diagrams are exported with transparent backgrounds; in dark mode they are inverted so lines and text stay readable. */
  .prose img.diagram { border-radius: 0; }
  :root[data-theme="dark"] .prose img.diagram { filter: invert(.92) hue-rotate(180deg); }
  .prose figcaption { padding-top: .75rem; font-size: .9375rem; line-height: 1.55; color: var(--muted); }
  .prose table { width: 100%; margin-block: 1.75rem; border-collapse: collapse; font-size: .9375rem; }
  .prose caption { margin-bottom: .6rem; text-align: left; font-size: .9375rem; color: var(--muted); }
  .prose th { text-align: left; font-weight: 650; color: var(--ink); }
  .prose td, .prose th { padding: .7rem .75rem .7rem 0; border-bottom: 1px solid var(--line); overflow-wrap: anywhere; }
  .prose blockquote { padding-left: 1.25rem; border-left: 3px solid var(--line); color: var(--ink); }
  .prose .callout { padding: 1.25rem 1.5rem; border-radius: 10px; background: var(--raised); }
  .prose .callout p { margin: 0; }

  .discussion { margin-top: 5rem; }
  .discussion > .muted { margin-top: .4rem; }
  .comment { padding-block: 1.25rem; border-bottom: 1px solid var(--line); }
  .comment header { display: flex; justify-content: space-between; gap: .75rem; margin-bottom: .35rem; color: var(--ink); }
  .comment time { font-size: .875rem; color: var(--muted); }
  .comment-form { padding-top: 1.75rem; }
  .form-columns { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin-bottom: 1.25rem; }
  .form-footer { display: flex; justify-content: space-between; align-items: center; gap: 1rem; margin-top: 1rem; }
  .form-footer > span { font-size: .875rem; color: var(--muted); }
  .spam-trap { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

  @media print {
    :root { color-scheme: light; }
    .site-header, .site-footer, .dock, .pdf-link, .toc, .discussion, .related, .copy-code, .web-enhancement { display: none !important; }
    .shell { max-width: none; padding: 0; }
    .article-layout { display: block; }
    .static-fallback { display: block !important; }
    .prose pre { white-space: pre-wrap; overflow-wrap: anywhere; }
  }
}

@layer motion {
  /*
   * Page transitions ride on Livewire's wire:navigate View Transitions. The clicked
   * article title morphs into the article heading; the rest of the page fades through.
   */
  ::view-transition-group(*) { animation-duration: .4s; animation-timing-function: var(--ease); }
  /* The class comes from the destination element, so it tells the direction: into an article the title grows, back to the list it settles. */
  .article-header h1 { view-transition-class: title-grow; }
  .post-row h3 { view-transition-class: title-settle; }
  ::view-transition-group(*.title-grow), ::view-transition-group(*.title-settle) { animation-duration: .5s; }
  ::view-transition-old(*.title-grow), ::view-transition-new(*.title-grow),
  ::view-transition-old(*.title-settle), ::view-transition-new(*.title-settle) { width: auto; height: auto; transform-origin: 0 0; }
  ::view-transition-old(*.title-grow) { animation: title-up-out .5s var(--ease) both; }
  ::view-transition-new(*.title-grow) { animation: title-up-in .5s var(--ease) both; }
  ::view-transition-old(*.title-settle) { animation: title-down-out .45s var(--ease) both; }
  ::view-transition-new(*.title-settle) { animation: title-down-in .45s var(--ease) both; }
  @keyframes title-up-out { 60%, 100% { opacity: 0; transform: scale(2); } }
  @keyframes title-up-in { from { opacity: 0; transform: scale(.5); } 40% { opacity: 1; } }
  @keyframes title-down-out { 60%, 100% { opacity: 0; transform: scale(.5); } }
  @keyframes title-down-in { from { opacity: 0; transform: scale(2); } 40% { opacity: 1; } }
  ::view-transition-group(page) { animation: none; }
  ::view-transition-old(page) { animation: page-out .12s ease-in both; }
  ::view-transition-new(page) { animation: page-in .35s var(--ease) .1s both; }
  @keyframes page-out { to { opacity: 0; } }
  @keyframes page-in { from { opacity: 0; transform: translateY(12px); } }

  /* Feedback that appears after an action eases in so the change is noticed. */
  .notice, .inline-success, .field-error { animation: appear .3s var(--ease) both; }
  @keyframes appear { from { opacity: 0; transform: translateY(-4px); } }
}

@layer responsive {
  @media (max-width: 70rem) {
    .article-layout { display: block; }
    .toc { display: none; }
  }
  @media (max-width: 48rem) {
    .about-facts, .about-strengths, .about-experience { grid-template-columns: 1fr; gap: 1.75rem; }
    .about-facts dt { font-size: 1.5rem; }
    .about-facts dd { max-width: none; }
    .about-strengths section { max-width: var(--column); }
    .writing .post-row { display: block; }
    .writing .post-row > .post-cover { aspect-ratio: 2 / 1; margin-bottom: 1.25rem; }
    .writing .post-row h3 { font-size: 1.5rem; }
    .intro.has-portrait { display: block; }
    .portrait { width: 7.5rem; margin: 0 0 1.75rem .6rem; rotate: -3deg; border-radius: 1rem; box-shadow: -8px 8px 0 var(--mark); }
  }
  @media (max-width: 40rem) {
    .site-header-inner { min-height: 3.75rem; }
    .brand-tagline { display: none; }
  }
  /* On phones the full name no longer fits beside the menu: the IA badge stands in, and the name stays for screen readers. */
  @media (max-width: 30rem) {
    .site-header .brand-name { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
    .site-header nav { gap: 1.25rem; }
    .dock { top: .75rem; left: .75rem; }
    .about { padding-top: 2.5rem; }
    .about-section { margin-top: 2.75rem; }
    .intro { padding-block: 2.5rem 3rem; }
    .search-form { width: 100%; }
    .intro-lede { margin-top: 1.5rem; }
    .post-row h3 { font-size: 1.3125rem; }
    .article-header { margin-bottom: 2.5rem; padding-block: 2rem 2rem; }
    .prose { font-size: 1.0625rem; }
    .prose pre { border-radius: 0; }
    .prose > pre, .prose section > pre, .code-block { margin-inline: calc(-1 * var(--gutter)); }
    .form-columns { grid-template-columns: 1fr; }
    .form-footer { flex-direction: column; align-items: flex-start; }
    .site-footer { margin-top: 6rem; }
  }
  @media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    *, *::before, *::after { transition-duration: .01ms !important; animation-duration: .01ms !important; animation-delay: 0s !important; }
    ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; }
  }
}
