/* peterjohnlambert.com — single stylesheet, no build step.

   TYPE: one family throughout, IBM Plex Sans. IBM Plex Mono (the monospaced
   cut of the same family) is used inside <pre> and <code> only. The font
   files are served from /assets/fonts/ (SIL Open Font Licence); nothing is
   loaded from another site.

   SIZES: exactly three, defined once below. Nothing else sets a font size,
   and no media query changes one.
     --fs-l  page titles and section headings
     --fs-m  reading text and paper titles
     --fs-s  metadata, controls, code, footer

   HIERARCHY comes from weight, italic and colour only. There is no
   uppercase, letter-spacing or small caps anywhere.
     page title        --fs-l  700  ink
     section heading   --fs-l  400  ink, followed by a hairline rule
     paper title       --fs-m  600  ink (italic 400 for work in progress)
     reading text      --fs-m  400  ink
     metadata          --fs-s  400  ink-2 / muted (years and labels 600)
     links and toggles --fs-s  accent colour

   WIDTHS: one column, one right edge. The intro, paper titles, metadata,
   coverage and descriptions all run to the edge of the body column, which
   is also where the header, the hairlines and the footer end. Two things
   are narrower, because they are read at length and not scanned: an opened
   abstract, and the guide. Both are capped at --measure, which is set in
   em so that it gives about 85 characters a line at any of the three sizes. */

/* IBM Plex Sans is a variable font: one file covers weights 400 to 700. */
@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/assets/fonts/ibm-plex-sans-400-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/assets/fonts/ibm-plex-sans-400-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "IBM Plex Sans";
  font-style: italic;
  font-weight: 400 700;
  font-display: swap;
  src: url("/assets/fonts/ibm-plex-sans-400-italic-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "IBM Plex Sans";
  font-style: italic;
  font-weight: 400 700;
  font-display: swap;
  src: url("/assets/fonts/ibm-plex-sans-400-italic-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/ibm-plex-mono-400-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/ibm-plex-mono-400-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  --paper: #fbfbfa;
  --paper-2: #f1f2f0;
  --ink: #17191c;
  --ink-2: #454a51;
  --muted: #686d75;      /* 5.0:1 on paper, 4.6:1 on paper-2 */
  --rule: #e0e2df;
  --accent: #0e6b63;
  --accent-ink: #0a4f49;
  --accent-soft: #e3f0ec;
  --visited: #6a4c7d;    /* links already followed */
  --hairline: #878c93;   /* underline of title and author links: 3.3:1 on paper */

  --sans: "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  --fs-l: 1.5rem;   /* 24px */
  --fs-m: 1rem;     /* 16px */
  --fs-s: 0.875rem; /* 14px */

  --lh: 1.4;        /* text */
  --lh-head: 1.25;  /* headings and titles */

  --measure: 40em;      /* long reading text: about 85 characters a line */
  --margin-col: 8.5rem; /* the left column: photo, years and labels */
  --col-gap: 2rem;
  --tap: 1.75rem;       /* height of the filter, tags and Abstract toggles on a phone (28px) */
  --ctl: 1.5rem;        /* smallest height of a control anywhere (24px) */
}

/* ---------- base ---------- */

html {
  font-size: 100%;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--fs-m);
  font-weight: 400;
  line-height: var(--lh);
  font-feature-settings: "kern";
  font-synthesis: none;
  overflow-wrap: break-word;
  -webkit-font-smoothing: antialiased;
}

/* Everything that a browser would otherwise size on its own is pinned to
   one of the three sizes. */
h1, h2, h3, h4, h5, h6 {
  margin: 0;
  font-size: var(--fs-m);
  font-weight: 600;
  line-height: var(--lh-head);
}
button, input, select, textarea {
  font-family: inherit;
  font-size: var(--fs-s);
  font-weight: inherit;
}
small, sub, sup, summary { font-size: var(--fs-s); }
sub, sup { line-height: 0; }
pre, code, kbd, samp {
  font-family: var(--mono);
  font-size: var(--fs-s);
  font-weight: 400;
}
strong, b, th { font-weight: 600; }

a {
  color: var(--accent);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.16em;
  text-decoration-color: rgba(14, 107, 99, 0.7);
}
a:visited { color: var(--visited); text-decoration-color: rgba(106, 76, 125, 0.7); }
a:hover { color: var(--accent-ink); text-decoration-color: currentColor; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 2px;
}
/* Packed controls: keep the ring off their neighbours. */
.chip:focus-visible, details.abstract summary:focus-visible { outline-offset: 1px; }

img { max-width: 100%; }
.nw { white-space: nowrap; }
[hidden] { display: none !important; }

.wrap {
  max-width: 62rem;
  margin: 0 auto;
  padding: 0 1.25rem;
}

.skip {
  position: absolute;
  left: -999px;
  top: 0.5rem;
  padding: 0.25rem 0.625rem;
  background: var(--ink);
  color: #fff;
  border-radius: 4px;
  z-index: 10;
}
/* Stays white when followed or pointed at: the link colours are unreadable on the dark ground. */
.skip:visited, .skip:hover { color: #fff; }
.skip:focus { left: 0.5rem; }

/* ---------- header / nav ---------- */

.site-header { border-bottom: 1px solid var(--rule); }
.site-header .wrap {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0 1.5rem;
  padding-top: 0.375rem;
  padding-bottom: 0.375rem;
}

.brand {
  display: inline-block;
  padding-block: 0.0625rem;
  font-weight: 600;
  color: var(--ink);
  text-decoration: none;
}
.brand:visited { color: var(--ink); }
.brand:hover { color: var(--accent); }
.site-header nav { margin-left: auto; }

.nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0 1.25rem;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--fs-s);
  font-weight: 500;
}
.nav a {
  display: inline-block;
  color: var(--ink-2);
  text-decoration: none;
  box-sizing: border-box;
  min-height: var(--ctl);
  padding: 0.125rem 0 0.0625rem;
  border-bottom: 1px solid transparent;
}
.nav a:visited { color: var(--ink-2); }
.nav a[aria-current]:visited { color: var(--ink); }
.nav a:hover { color: var(--ink); border-bottom-color: var(--rule); }
.nav a[aria-current] { color: var(--ink); border-bottom-color: var(--accent); }
/* External-link arrow. The webfont has an upward arrow but no diagonal one,
   so the upward arrow is turned 45 degrees to stay inside the one typeface. */
.nav .ext::after {
  content: "\2191";
  content: "\2191" / "";
  display: inline-block;
  margin-left: 0.25em;
  color: var(--muted);
  transform: rotate(45deg);
}

/* ---------- home: hero ---------- */

.hero {
  display: grid;
  grid-template-columns: var(--margin-col) 1fr;
  gap: var(--col-gap);
  align-items: start;
  padding: 1.25rem 0 0.875rem;
}
.hero img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: 50%;
}
.hero h1 {
  font-size: var(--fs-l);
  font-weight: 700;
  margin: 0 0 0.25rem;
}
.hero p { margin: 0 0 0.5rem; }
.hero p:last-child { margin-bottom: 0; }
.hero .lead { font-weight: 500; }

/* ---------- sections ---------- */

.section { padding: 0.875rem 0 0; }
.section-title {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 0;
  font-size: var(--fs-l);
  font-weight: 400;
  color: var(--ink);
}
.section-title::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--rule);
}
.section-intro { margin: 0.25rem 0 0.5rem; color: var(--ink-2); }

/* ---------- entries: the margin-annotated list ---------- */

.entries { margin: 0; padding: 0; list-style: none; }
.entry {
  display: grid;
  grid-template-columns: var(--margin-col) 1fr;
  gap: 0 var(--col-gap);
  align-items: baseline;
  padding: 0.5rem 0;
}
.entry:first-child, .entry.is-first { padding-top: 0.25rem; }

.entry-margin {
  font-size: var(--fs-s);
  color: var(--muted);
}
.entry-margin .year { display: block; color: var(--ink-2); font-weight: 600; }
.entry-margin .series { display: block; }
.entry-margin .live { color: var(--accent); font-weight: 600; }

/* The body is set at the small size so that the run of metadata sits on
   its own, tighter line grid. Titles set themselves back to --fs-m. */
.entry-body { min-width: 0; font-size: var(--fs-s); text-wrap: pretty; }

.entry-title {
  font-size: var(--fs-m);
  font-weight: 600;
  line-height: 1.3;
  margin: 0 0 0.125rem;
  text-wrap: balance;
}
.entry-title a,
.entry-title a:visited {
  padding-block: 0.125rem;
  color: var(--ink);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
  text-decoration-color: var(--hairline);
}
.entry-title a:visited { text-decoration-color: var(--visited); }
.entry-title a:hover { color: var(--accent); text-decoration-color: currentColor; }
/* Work in progress: italic at regular weight. Italic and bold are never combined. */
.entry-title em { font-style: italic; font-weight: 400; }
/* Format marker after a title that opens a file rather than a page. */
.entry-title .fmt { font-size: var(--fs-s); font-weight: 400; color: var(--muted); white-space: nowrap; }

/* Authors, note, venue and links run together as one line of metadata,
   separated by middle dots. */
.entry-authors,
.entry-note,
.entry-venue,
.entry-links,
.entry-links li {
  display: inline;
  margin: 0;
  padding: 0;
  list-style: none;
}
.entry-authors,
.entry-note,
.entry-venue,
.entry-links,
.entry-desc,
.coverage {
  font-size: var(--fs-s);
  color: var(--ink-2);
}
.entry-note { font-style: italic; }
.entry-authors a, .entry-authors a:visited { color: var(--ink-2); text-decoration-color: var(--hairline); }
.entry-links a, .coverage a { white-space: nowrap; }
.entry-authors a:hover { color: var(--accent-ink); text-decoration-color: currentColor; }

.entry-links li:not(:last-child)::after {
  content: "\00a0\00b7";
  color: var(--muted);
}
/* The dot is attached to the end of the item before it, so that a line
   never starts with a separator. */
:is(.entry-authors, .entry-note, .entry-venue):has(+ :is(.entry-note, .entry-venue, .entry-links))::after {
  content: "\00a0\00b7";
  font-style: normal;
  color: var(--muted);
}
@supports not selector(:has(+ *)) {
  .entry-authors + .entry-note::before,
  .entry-authors + .entry-venue::before,
  .entry-authors + .entry-links::before,
  .entry-note + .entry-venue::before,
  .entry-note + .entry-links::before,
  .entry-venue + .entry-links::before {
    content: "\00b7\00a0";
    font-style: normal;
    color: var(--muted);
  }
}

.entry-desc { margin: 0; line-height: 1.45; }

.coverage { margin: 0; }
.coverage .label {
  font-style: italic;
  margin-right: 0.25rem;
}
.coverage .label::after { content: ":"; }


details.abstract { margin-top: 0.25rem; }
details.abstract summary {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  width: -moz-fit-content;
  width: fit-content;
  min-height: var(--ctl);
  cursor: pointer;
  list-style: none;
  font-size: var(--fs-s);
  font-weight: 500;
  line-height: 1.2;
  color: var(--accent);
}
details.abstract summary::-webkit-details-marker { display: none; }
details.abstract summary::before {
  content: "+";
  content: "+" / "";
  display: inline-block;
  width: 0.75em;
  text-align: center;
}
details.abstract[open] summary::before { content: "\2212"; content: "\2212" / ""; }
details.abstract summary:hover { color: var(--accent-ink); }
/* An opened abstract is reading text, so it is set at the body size. */
details.abstract p {
  clear: both;
  max-width: var(--measure);
  box-sizing: border-box;
  margin: 0.25rem 0 0.25rem;
  padding-left: 0.75rem;
  border-left: 2px solid var(--accent-soft);
  font-size: var(--fs-m);
  line-height: var(--lh);
  color: var(--ink-2);
}

/* ---------- topic filter ---------- */

.filter {
  display: grid;
  grid-template-columns: var(--margin-col) 1fr;
  gap: 0 var(--col-gap);
  align-items: start;
  padding: 0.625rem 0 0;
  border-top: 1px solid var(--rule);
}
.filter-label {
  font-size: var(--fs-s);
  font-weight: 600;
  line-height: var(--tap);
  color: var(--ink-2);
}
.chips { display: flex; flex-wrap: wrap; gap: 0.375rem; }
.chip {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  box-sizing: border-box;
  min-height: var(--tap);
  margin: 0;
  padding: 0 0.625rem;
  font-family: inherit;
  font-size: var(--fs-s);
  font-weight: 400;
  line-height: 1.2;
  color: var(--ink-2);
  background: transparent;
  border: 1px solid var(--rule);
  border-radius: 4px;
  cursor: pointer;
}
.chip:hover { color: var(--ink); border-color: var(--accent); }
.chip .n { color: var(--muted); }
.chip[aria-pressed="true"] { color: #fff; background: var(--accent); border-color: var(--accent); }
.chip[aria-pressed="true"] .n { color: rgba(255, 255, 255, 0.78); }
.filter-status {
  margin: 0.25rem 0 0;
  font-size: var(--fs-s);
  color: var(--muted);
}
.filter-status:empty { margin: 0; }
.filter-status.is-quiet { position: absolute; width: 1px; height: 1px; margin: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

/* Windows High Contrast and similar: backgrounds are forced, so the selected
   topic is shown with the system highlight colours. */
@media (forced-colors: active) {
  .chip[aria-pressed="true"] {
    forced-color-adjust: none;
    background: Highlight;
    color: HighlightText;
    border-color: Highlight;
    box-shadow: none;
  }
  .chip[aria-pressed="true"] .n { color: HighlightText; }
  .chip[aria-pressed="true"]:focus-visible { outline-color: ButtonText; }
}

/* ---------- article pages (the guide) ---------- */

.article-header {
  padding: 1rem 0 0.625rem;
  border-bottom: 1px solid var(--rule);
  margin-bottom: 0.75rem;
}
.eyebrow {
  font-size: var(--fs-s);
  color: var(--muted);
  margin: 0 0 0.125rem;
}
.eyebrow a, .eyebrow a:visited { color: var(--muted); text-decoration-color: currentColor; }
.eyebrow a:hover { color: var(--accent); }
.article-header h1,
.page-header h1 {
  font-size: var(--fs-l);
  font-weight: 700;
  margin: 0 0 0.25rem;
}
.article-meta { margin: 0; font-size: var(--fs-s); color: var(--ink-2); max-width: var(--measure); }

/* The page title and its introduction sit in the body column, so that text
   starts at the same left edge on the home, Tutorials and 404 pages. The
   guide is set flush with the site header. */
.page-header { padding: 1rem 0 0.25rem calc(var(--margin-col) + var(--col-gap)); }
.page-header p { color: var(--ink-2); margin: 0; }
.page-header .eyebrow { margin: 0 0 0.125rem; color: var(--muted); }

.article { max-width: var(--measure); }
.article > :first-child { margin-top: 0; }
.article h2 {
  display: flex;
  flex-wrap: wrap-reverse;
  align-items: center;
  gap: 0.5rem 0.75rem;
  font-size: var(--fs-l);
  font-weight: 400;
  margin: 1rem 0 0.375rem;
}
.article h2::after { content: ""; flex: 1 0 3rem; height: 1px; background: var(--rule); }
.article hr:has(+ h2) { display: none; }
.article h2 + h3, .article h3 + h3 { margin-top: 0.375rem; }
.article h3 {
  font-size: var(--fs-m);
  font-weight: 600;
  margin: 0.875rem 0 0.25rem;
}
.article h4 { font-size: var(--fs-m); font-weight: 400; font-style: italic; margin: 0.75rem 0 0.25rem; }
.article h2 strong, .article h3 strong, .article h4 strong { font-weight: inherit; }
.article p, .article ul, .article ol { margin: 0 0 0.5rem; }
.article ul, .article ol { padding-left: 1.375rem; }
.article li { margin-bottom: 0.125rem; }
.article li > p { margin-bottom: 0.125rem; }
.article li > ul, .article li > ol { margin-top: 0.125rem; margin-bottom: 0.25rem; }
.article a { overflow-wrap: anywhere; }
.article hr { border: 0; border-top: 1px solid var(--rule); margin: 0.875rem 0 0.625rem; }
.article img {
  display: block;
  height: auto;
  margin: 0.375rem 0 0.625rem;
  border: 1px solid var(--rule);
  border-radius: 6px;
  box-sizing: border-box;
}
.article blockquote {
  margin: 0.5rem 0;
  padding: 0 0 0 0.75rem;
  border-left: 3px solid var(--accent-soft);
  color: var(--ink-2);
}
.article blockquote > :last-child { margin-bottom: 0; }
.article table { border-collapse: collapse; width: 100%; font-size: var(--fs-s); margin: 0 0 0.625rem; }
.article th, .article td { text-align: left; padding: 0.1875rem 0.5rem; border-bottom: 1px solid var(--rule); vertical-align: top; overflow-wrap: anywhere; }
.article th:first-child, .article td:first-child { padding-left: 0; }
.article th:last-child, .article td:last-child { padding-right: 0; }
.article th { font-weight: 600; overflow-wrap: normal; }

.article :not(pre) > code {
  background: var(--paper-2);
  padding: 0.0625rem 0.25rem;
  border-radius: 4px;
  overflow-wrap: anywhere;
}
.article pre {
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: 6px;
  padding: 0.5rem 0.75rem;
  margin: 0 0 0.625rem;
  overflow-x: auto;
  line-height: 1.45;
}
.article pre code { background: none; padding: 0; }
.article a:has(> img) { display: block; text-decoration: none; }

/* ---------- footer ---------- */

.site-footer {
  margin-top: 0.75rem;
  padding: 0.375rem 0 0.5rem;
  border-top: 1px solid var(--rule);
  font-size: var(--fs-s);
  color: var(--muted);
}
.site-footer .wrap {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0 1.5rem;
}
.site-footer a, .site-footer a:visited { color: var(--ink-2); text-decoration-color: currentColor; }

/* ---------- small screens ---------- */
/* Layout only. Font sizes never change here. */

@media (max-width: 44rem) {
  .wrap { padding: 0 1rem; }
  .site-header nav { margin-left: 0; }
  .nav { gap: 0 1rem; }
  .nav a { padding: 0.25rem 0 0.1875rem; }

  /* The photo sits beside the name and the opening line; the rest of the
     text starts underneath it at full width. The opening line keeps to its
     own block beside the photo, so it never wraps raggedly round it. Below
     318px wide, or with text enlarged, that costs one extra line. */
  .hero { display: block; padding-top: 0.875rem; }
  .hero::after { content: ""; display: block; clear: both; }
  .hero img {
    float: left;
    width: 5.5rem;
    margin: 0.125rem 0.875rem 0.375rem 0;
  }
  .hero p { clear: left; }
  .hero .lead { clear: none; display: flow-root; }

  .entry {
    grid-template-columns: 1fr;
    gap: 0;
  }
  .entry-margin { display: flex; flex-wrap: wrap; gap: 0 0.5rem; }
  .entry-margin .year, .entry-margin .series { display: inline; }

  .page-header { padding-left: 0; }

  .filter { grid-template-columns: 1fr; }
  .filter-label { line-height: var(--lh); margin-bottom: 0.25rem; }

  /* Controls stay tall enough to tap. */
  details.abstract summary { min-height: var(--tap); }

  /* Link labels may break across lines here, so that enlarged text never
     makes the page scroll sideways. */
  .entry-links a, .coverage a { white-space: normal; }
}

/* Very narrow phones: a smaller photo leaves room for the name beside it. */
@media (max-width: 24rem) {
  .hero img { width: 4.5rem; margin-right: 0.75rem; }
}

@media print {
  .site-header, .site-footer, .skip, .filter, details.abstract summary { display: none; }
  /* Paper cannot scroll: long commands wrap instead of being cut off. */
  .article pre { overflow: visible; white-space: pre-wrap; overflow-wrap: anywhere; }
  body { background: #fff; }
  a { color: inherit; text-decoration: none; }
}
