/*
 * cora.earth
 * Square corners, plain dark text, tight boxes and highlights.
 * Berkeley Mono for headings, navigation, metadata and code; Inter for post
 * text.
 * Light and dark follow the device setting (prefers-color-scheme) unless the
 * reader has picked one with the toggle, which sets data-theme on <html>.
 */

/* Berkeley Mono (licensed for self-hosting as WOFF2 only; see README.md).
   Until the files are in static/fonts/, the fallback stack in --mono is used. */
@font-face {
  font-family: "Berkeley Mono";
  src: url("/fonts/BerkeleyMono-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Berkeley Mono";
  src: url("/fonts/BerkeleyMono-Oblique.woff2") format("woff2");
  font-weight: 400;
  font-style: oblique;
  font-display: swap;
}
@font-face {
  font-family: "Berkeley Mono";
  src: url("/fonts/BerkeleyMono-Bold.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Berkeley Mono";
  src: url("/fonts/BerkeleyMono-Bold-Oblique.woff2") format("woff2");
  font-weight: 700;
  font-style: oblique;
  font-display: swap;
}

/* Inter (SIL OFL, static/fonts/inter/OFL.txt), latin subset from Fontsource. */
@font-face {
  font-family: "Inter";
  src: url("/fonts/inter/inter-latin-400-normal.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("/fonts/inter/inter-latin-400-italic.woff2") format("woff2");
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("/fonts/inter/inter-latin-700-normal.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("/fonts/inter/inter-latin-700-italic.woff2") format("woff2");
  font-weight: 700;
  font-style: italic;
  font-display: swap;
}

:root {
  color-scheme: light;

  --mono: "Berkeley Mono", ui-monospace, "SF Mono", SFMono-Regular, Menlo,
    "Cascadia Mono", Consolas, "DejaVu Sans Mono", "Liberation Mono", monospace;
  --sans: Inter, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  --bg: #ffffff;
  --fg: #161616;
  --muted: #5e5e5e;
  --box: #f5f5f5;      /* box body */
  --box-head: #ebebeb; /* box header, nav */
  --hl: #e2e3ea;       /* tight highlight behind text */
  --selected: #bfc8e3; /* current nav item, active theme */
  --rule: #d4d4d4;
  --accent: #4b64a3;   /* link hover, selection */
  --accent-fg: #ffffff;
  --track: #f5f5f5;    /* scrollbar */
  --thumb: #cdcdcd;
  --thumb-hover: #a8a8a8;
  --cover-dim: 1;      /* brightness of a post's cover photo */
  --ink-blue: #4b64a3; /* diagram colours (the diagram shortcode) */
  --ink-purple: #7d52b0;
  --ink-amber: #9a6814;
  --ink-orange: #e56900;
  --ink-orange-fg: #161616; /* text on --ink-orange */
  --ink-green: #2f7a4c;
  --ink-red: #b2443f;
  --ink-grey: #767676; /* 3:1 or more on the tinted boxes */
}

/* The dark colours appear twice, for the device setting and for the toggle.
   Keep the two blocks the same. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --bg: #121212;
    --fg: #e4e4e4;
    --muted: #9b9b9b;
    --box: #1b1b1b;
    --box-head: #262626;
    --hl: #2d2f38;
    --selected: #3f4866;
    --rule: #383838;
    --accent: #93a8dc;
    --accent-fg: #121212;
    --track: #1b1b1b;
    --thumb: #3c3c3c;
    --thumb-hover: #555555;
    --cover-dim: 0.8;
    --ink-blue: #93a8dc;
    --ink-purple: #bb9de6;
    --ink-amber: #e0b462;
    --ink-orange: #fd923e;
    --ink-orange-fg: #121212;
    --ink-green: #7cc79a;
    --ink-red: #e48a83;
    --ink-grey: #7d7d7d;
  }
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --bg: #121212;
  --fg: #e4e4e4;
  --muted: #9b9b9b;
  --box: #1b1b1b;
  --box-head: #262626;
  --hl: #2d2f38;
  --selected: #3f4866;
  --rule: #383838;
  --accent: #93a8dc;
  --accent-fg: #121212;
  --track: #1b1b1b;
  --thumb: #3c3c3c;
  --thumb-hover: #555555;
  --cover-dim: 0.8;
  --ink-blue: #93a8dc;
  --ink-purple: #bb9de6;
  --ink-amber: #e0b462;
  --ink-orange: #fd923e;
  --ink-orange-fg: #121212;
  --ink-green: #7cc79a;
  --ink-red: #e48a83;
  --ink-grey: #7d7d7d;
}

*,
*::before,
*::after {
  box-sizing: border-box;
  border-radius: 0;
}

html {
  background: var(--bg);
  color: var(--fg);
  font-family: var(--mono);
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  margin: 0;
  font-size: 0.9375rem;
  line-height: 1.65;
}

/* Square scrollbar. Blink and WebKit take the pseudo-elements; Firefox gets
   the standard properties. Chrome ignores the pseudo-elements once
   scrollbar-color is set, hence the @supports guard. */
@supports not selector(::-webkit-scrollbar) {
  html {
    scrollbar-color: var(--thumb) var(--track);
  }
}
::-webkit-scrollbar {
  width: 12px;
  height: 12px;
  background: var(--track);
}
::-webkit-scrollbar-thumb {
  background: var(--thumb);
  border-radius: 0;
}
::-webkit-scrollbar-thumb:hover {
  background: var(--thumb-hover);
}
::-webkit-scrollbar-corner {
  background: var(--track);
}

::selection {
  background: var(--accent);
  color: var(--accent-fg);
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

a {
  color: inherit;
}
a:hover {
  background: var(--accent);
  color: var(--accent-fg);
  text-decoration: none;
}

/* A tight box behind each line of text. */
.hl {
  background: var(--hl);
  padding: 0 0.25em;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

/* Layout: sidebar on the left, posts on the right; stacked on narrow screens. */
.site {
  display: grid;
  grid-template-columns: 12rem minmax(0, 44rem);
  gap: 5rem;
  justify-content: center;
  padding: 5rem 1.5rem 6rem;
  /* A wide figure can reach under a classic scrollbar (see .wide below);
     clip that instead of scrolling sideways. Clip, not hidden, so the
     sidebar still sticks. */
  overflow-x: clip;
}

.sidebar {
  position: sticky;
  top: 5rem;
  align-self: start;
}

.site-title {
  display: inline-block;
  margin-bottom: 2rem;
  font-size: 1.25rem;
  font-weight: 700;
  text-decoration: none;
}
.site-title:hover .hl {
  background: var(--accent);
}

.nav {
  display: flex;
  flex-direction: column;
  background: var(--box-head);
  font-weight: 700;
}
.nav a {
  padding: 0 0.25em;
  text-decoration: none;
}
.nav a[aria-current="page"] {
  background: var(--selected);
}
/* Hover comes after the selected state so it wins there too; otherwise the
   selected item would get the hover text colour on the selected background. */
.nav a:hover {
  background: var(--accent);
  color: var(--accent-fg);
}

.theme-toggle {
  display: flex;
  width: fit-content;
  margin-top: 1rem;
  background: var(--box-head);
  font-weight: 700;
}
.theme-toggle[hidden] {
  display: none;
}
.theme-toggle button {
  padding: 0 0.25em;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  cursor: pointer;
}
.theme-toggle button[aria-pressed="true"] {
  background: var(--selected);
}
.theme-toggle button:hover {
  background: var(--accent);
  color: var(--accent-fg);
}

@media (max-width: 52rem) {
  .site {
    grid-template-columns: minmax(0, 1fr);
    gap: 2.5rem;
    padding: 2rem 1rem 4rem;
  }
  .sidebar {
    position: static;
  }
  .site-title {
    margin-bottom: 1rem;
  }
  .nav {
    flex-direction: row;
    width: fit-content;
  }
}

/* Headings */
h1,
h2,
h3,
h4 {
  font-size: 1rem;
  line-height: 1.4;
  margin: 0;
}

.page-title {
  font-size: 1.375rem;
  line-height: 1.5;
  margin: 0 0 2rem;
}

/* Post cards on the index */
.card {
  margin: 0 0 3.5rem;
}
.card-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  background: var(--box-head);
  padding: 0.85rem 1.25rem;
}
.card-head time {
  flex-shrink: 0;
  color: var(--muted);
}
.card-title a {
  text-decoration: none;
}
.card-body {
  background: var(--box);
  padding: 1.1rem 1.25rem 1.25rem;
}
.card-body > p,
.card-body > .prose > :first-child {
  margin-top: 0;
}
.more {
  display: inline-block;
  margin-top: 0.25rem;
  font-size: 0.9375rem;
}

/* Single posts and pages */
.post-head {
  margin-bottom: 2.25rem;
}
.post-head .page-title {
  margin-bottom: 0.5rem;
}
.meta {
  display: inline-block;
  margin: 0;
  padding: 0 0.25em;
  background: var(--box-head);
  color: var(--muted);
  font-size: 0.875rem;
}

.pager {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 3.5rem;
}
.pager a {
  background: var(--box-head);
  padding: 0.35rem 0.6rem;
  text-decoration: none;
}
.pager a:hover {
  background: var(--accent);
}
.pager .older {
  margin-left: auto;
}

/* Newer and older posts, below a post: two labelled boxes under a rule,
   stacked on narrow screens. */
.post-nav {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
  margin-top: 5rem;
  padding-top: 2rem;
  border-top: 1px solid var(--rule);
}
.post-nav a {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.4rem;
  padding: 0.85rem 1.1rem 1rem;
  background: var(--box);
  text-decoration: none;
}
.post-nav .post-nav-older {
  grid-column: 2;
  align-items: flex-end;
  text-align: right;
}
.post-nav-label {
  padding: 0 0.25em;
  background: var(--box-head);
  color: var(--muted);
  font-size: 0.8125rem;
}
.post-nav-title {
  font-weight: 700;
}
.post-nav a:hover {
  background: var(--accent);
}
.post-nav a:hover .post-nav-label {
  background: none;
  color: inherit;
}
@media (max-width: 52rem) {
  .post-nav {
    grid-template-columns: minmax(0, 1fr);
    margin-top: 3.5rem;
  }
  .post-nav .post-nav-older {
    grid-column: auto;
  }
}

/* Archive: every post, newest first */
.archive {
  list-style: none;
  margin: 0;
  padding: 0;
}
.archive li {
  display: flex;
  gap: 2ch;
  padding: 0.15rem 0;
}
.archive time {
  flex-shrink: 0;
  color: var(--muted);
}
.archive a {
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
}

/* Prose: rendered markdown. Text is Inter; headings and code stay mono. */
.prose,
.card-body {
  font-family: var(--sans);
  font-size: 1.0625rem;
  line-height: 1.6;
}
.prose h2,
.prose h3,
.prose h4,
.prose code,
.prose pre,
.more {
  font-family: var(--mono);
}
.prose > :first-child {
  margin-top: 0;
}
.prose > :last-child {
  margin-bottom: 0;
}
.prose p,
.prose ul,
.prose ol,
.prose blockquote,
.prose pre,
.prose table,
.prose figure {
  margin: 0 0 1.15em;
}
.prose h2,
.prose h3,
.prose h4 {
  width: fit-content;
  margin: 2.25em 0 0.9em;
  padding: 0 0.25em;
  background: var(--hl);
}
.prose h2 {
  font-size: 1.125rem;
}
/* A link to a heading in the post (the section_link shortcode), in the
   heading's type and highlight. */
.section-link {
  font-family: var(--mono);
  font-weight: bold;
  padding: 0 0.25em;
  background: var(--hl);
}
/* Heading links (static/heading-links.js): a "#" in the gap left of a
   heading, shown while the heading is hovered or the "#" has keyboard focus,
   that copies the heading's address and says "copied". Phones have neither
   the gap nor hover, so they go without. */
.heading {
  position: relative;
}
.prose > .heading:first-child > :first-child {
  margin-top: 0;
}
.heading-link {
  position: absolute;
  top: 0;
  right: 100%;
  margin-right: 0.25em;
  padding: 0 0.25em;
  color: var(--muted);
  font: 1rem/1.4 var(--mono);
  text-decoration: none;
  opacity: 0;
}
.prose h2 + .heading-link {
  font-size: 1.125rem;
}
.heading:hover .heading-link,
.heading-link:focus-visible,
.heading-link.copied {
  opacity: 1;
}
.heading-link.copied {
  background: var(--selected);
  color: var(--fg);
}
@media (max-width: 52rem) {
  .heading-link {
    display: none;
  }
}
.prose a {
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
}
.prose ul {
  list-style: none;
  padding-left: 2ch;
}
.prose ul > li::before {
  content: "-";
  display: inline-block;
  width: 2ch;
  margin-left: -2ch;
  color: var(--muted);
}
.prose ol {
  padding-left: 3ch;
}
.prose li + li {
  margin-top: 0.2em;
}
.prose blockquote {
  margin-left: 0;
  margin-right: 0;
  padding: 0.85rem 1.25rem;
  background: var(--box);
  border-left: 4px solid var(--box-head);
}
.prose blockquote > :last-child {
  margin-bottom: 0;
}
/* Rhymes (the rhymes shortcode): each rhyme group, and its letter in the
   scheme, gets a tight highlight tinted with one of the diagram colours. The
   highlight alone marks the endings, so they lose their bold (feed readers,
   without this CSS, keep it). */
.rhyme {
  --rhyme: var(--ink-grey);
  font-weight: inherit;
  background: color-mix(in oklab, var(--rhyme) 40%, var(--bg));
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}
.rhyme-a { --rhyme: var(--ink-blue); }
.rhyme-b { --rhyme: var(--ink-amber); }
.rhyme-c { --rhyme: var(--ink-green); }
.rhyme-d { --rhyme: var(--ink-purple); }
.rhyme-e { --rhyme: var(--ink-red); }
.rhyme-scheme {
  font: 0.9em var(--mono);
  white-space: nowrap;
}
.rhyme-scheme .rhyme {
  padding: 0 0.1em;
}
.rhyme-scheme .rhyme + .rhyme {
  margin-left: 0.1em;
}
/* AI-generated text (the ai shortcode): a blockquote with a small marker in
   its top-right corner. Screen readers hear "AI-generated:" instead. */
.prose .ai-quote {
  position: relative;
  padding-right: 3.25rem;
}
.ai-mark {
  position: absolute;
  top: 1.05rem;
  right: 1rem;
  padding: 0 0.3em;
  background: var(--selected);
  font: 700 0.75rem/1.5 var(--mono);
  cursor: help;
  user-select: none;
}
/* The tag in a line of text ({{ ai() }}, or a caption_ai caption). */
.ai-inline {
  position: static;
}
/* With static/ai-tag.js the tag is a button, and hovering, focusing,
   clicking or tapping it shows what it means in a box just under it. The
   tag and its box are one colour, like a link being hovered. */
button.ai-mark {
  margin: 0;
  border: 0;
  color: var(--fg);
  cursor: pointer;
}
button.ai-mark.open {
  background: var(--accent);
  color: var(--accent-fg);
}
@media (hover: hover) {
  button.ai-mark:hover {
    background: var(--accent);
    color: var(--accent-fg);
  }
}
.ai-tip {
  position: absolute;
  z-index: 10;
  width: max-content;
  max-width: min(20rem, 100vw - 2rem);
  padding: 0.3rem 0.55rem 0.35rem;
  background: var(--accent);
  color: var(--accent-fg);
  font: 400 0.8125rem/1.45 var(--mono);
}
.ai-tip-word {
  white-space: nowrap;
}
/* Verse (verse=true): a line too long for the column wraps with a hanging
   indent, so it still reads as one line. The <br>s are for feed readers. */
.prose .verse .line {
  display: block;
  padding-left: 1.5em;
  text-indent: -1.5em;
}
.prose .verse br {
  display: none;
}
/* A folded ai block (summary="..."): the label opens it, with a triangle
   that turns down when it's open. */
.ai-quote summary {
  display: block;
  width: fit-content;
  padding: 0 0.25em;
  margin-left: -0.25em;
  font-family: var(--mono);
  font-size: 0.9375rem;
  cursor: pointer;
  user-select: none;
}
.ai-quote summary::-webkit-details-marker {
  display: none;
}
.ai-quote summary::before {
  content: "▶";
  display: inline-block;
  margin-right: 1ch;
  font-size: 0.75em;
}
.ai-quote details[open] > summary {
  margin-bottom: 1.15em;
}
.ai-quote details[open] > summary::before {
  transform: rotate(90deg);
}
.ai-quote summary:hover {
  background: var(--accent);
  color: var(--accent-fg);
}

/* "skip to content", the first thing Tab reaches on every page: hidden
   until it has keyboard focus. */
.skip-link {
  position: absolute;
  top: 1rem;
  left: 1rem;
  z-index: 20;
  padding: 0 0.25em;
  background: var(--accent);
  color: var(--accent-fg);
  font: 700 1rem/1.5 var(--mono);
  text-decoration: none;
}
.skip-link:not(:focus) {
  clip-path: inset(50%);
  width: 1px;
  height: 1px;
  overflow: hidden;
  white-space: nowrap;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Spoilers (the spoiler shortcode, static/spoiler.js): a solid bar until
   clicked or tapped, then a tight highlight. Without the script, plain
   text. */
.spoiler-button {
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: inherit;
  cursor: pointer;
}
.spoiler-button .spoiler {
  padding: 0 0.25em;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}
.spoiler-button[aria-expanded="false"] .spoiler {
  background: var(--muted);
  color: transparent;
  user-select: none;
}
.spoiler-button[aria-expanded="false"]:hover .spoiler {
  background: var(--accent);
}
.spoiler-button[aria-expanded="true"] .spoiler {
  background: var(--hl);
}
/* Play/stop on an animated figure, for readers who prefer reduced motion
   (static/anim.js). */
.anim-frame {
  display: block;
  position: relative;
}
.anim-button {
  position: absolute;
  bottom: 0.5rem;
  left: 0.5rem;
  margin: 0;
  padding: 0 0.3em;
  border: 0;
  background: var(--selected);
  color: var(--fg);
  font: 700 0.75rem/1.5 var(--mono);
  cursor: pointer;
}
.anim-button:hover {
  background: var(--accent);
  color: var(--accent-fg);
}
.prose code {
  font-size: 0.85em;
  background: var(--hl);
  padding: 0 0.25em;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}
.prose pre {
  overflow-x: auto;
  padding: 1rem 1.25rem;
  background: var(--box);
  font-size: 0.875rem;
  line-height: 1.55;
}
.prose pre code {
  background: none;
  padding: 0;
  font-size: inherit;
}
/* Box-drawing diagrams (templates/shortcodes/diagram.html). Each character
   is --cell wide (whole pixels, so the lines land on the pixel grid), or
   narrower when that won't fit the column: --cols is the diagram's width in
   characters, and .prose is the container 100cqw measures. Berkeley Mono is
   0.6em wide. Its box and shade glyphs are exactly 1.2em tall, so at a line
   height of 1.2 they would just touch, and anti-aliasing leaves a faint gap
   in vertical lines; lines overlap by up to 1px instead. Nothing scrolls. */
.prose {
  container-type: inline-size;
}
.prose pre.diagram {
  --size: min(var(--cell, 8px), (100cqw - 1px) / var(--cols, 88));
  overflow: visible;
  margin: 1.75rem 0;
  padding: 0;
  background: none;
  font-size: calc(var(--size) / 0.6);
  line-height: calc(var(--size) * 2 - min(1px, var(--size) / 7));
  font-variant-ligatures: none;
}
.diagram .d-b { color: var(--ink-blue); }
.diagram .d-p { color: var(--ink-purple); }
.diagram .d-y { color: var(--ink-amber); }
.diagram .d-o { color: var(--ink-orange); }
.diagram .d-g { color: var(--ink-green); }
.diagram .d-r { color: var(--ink-red); }
.diagram .d-m { color: var(--ink-grey); }
.diagram .d-\* { font-weight: 700; }
/* A diagram shrunk to fit gets an "enlarge" button at its top left, which
   shows it full size, scrolling sideways in the column (static/
   diagram-zoom.js). In an ai block the button sits across from the tag. */
.diagram-enlarge {
  display: block;
  margin: 0 0 0.5rem;
  padding: 0 0.3em;
  border: 0;
  background: var(--selected);
  color: var(--fg);
  font: 700 0.75rem/1.5 var(--mono);
  cursor: pointer;
}
.diagram-enlarge[hidden] {
  display: none;
}
.prose > .diagram-enlarge {
  margin-top: 1.75rem;
}
.prose > .diagram-enlarge + pre.diagram {
  margin-top: 0;
}
.ai-diagram > .diagram-enlarge {
  position: absolute;
  top: 1.05rem;
  left: 1rem;
  margin: 0;
}
.diagram-enlarge:hover {
  background: var(--accent);
  color: var(--accent-fg);
}
.prose pre.diagram.enlarged {
  --size: var(--cell, 8px);
  overflow-x: auto;
  overflow-y: hidden;
}

/* A diagram with a caption (caption=), and one in an ai block (mark=true).
   In the ai block the "ai" tag gets a row of its own above the diagram, and
   the block is the container the diagram fits itself to. */
.prose .diagram-figure {
  margin: 1.75rem 0;
}
.prose .diagram-figure > pre.diagram {
  margin: 0;
}
.prose .ai-diagram {
  container-type: inline-size;
  margin: 1.75rem 0;
  padding: 2.6rem 1rem 1rem;
}
.prose .ai-diagram > pre.diagram,
.prose .ai-diagram > .diagram-figure {
  margin: 0;
}

.prose hr {
  border: 0;
  border-top: 1px solid var(--rule);
  margin: 2.5em 0;
}
.prose img,
.prose video {
  display: block;
  max-width: 100%;
  height: auto;
}
/* Videos (the video shortcode). --ratio is the video's width / height, set
   from its poster frame. The video is never taller than 42rem or most of the
   screen, so a portrait phone recording stays phone-sized; a landscape one
   still fills the column. The background shows until the poster loads. */
.prose .video video {
  width: min(100%, min(80vh, 42rem) * (var(--ratio)));
  width: min(100%, min(80svh, 42rem) * (var(--ratio)));
  aspect-ratio: var(--ratio);
  background: var(--box-head);
}
/* Captions: small, muted, under the image or diagram. */
.prose figcaption {
  margin-top: 0.4em;
  color: var(--muted);
  font-size: 0.875rem;
  line-height: 1.5;
}
.prose figcaption p {
  margin: 0 0 0.35em;
}
.prose figcaption p:last-child {
  margin-bottom: 0;
}
/* An AI-written caption (caption_ai=true) starts with the "ai" tag. */
.prose figcaption .ai-mark {
  margin-right: 0.5ch;
}
/* Figures (the figure shortcode). The image's width and height attributes
   reserve its space before it loads. */
.prose .figure {
  margin: 1.75rem 0;
}
.prose .figure img {
  background: var(--box-head);
}
/* A wide figure's image spans the window, up to 120rem, and its caption
   stays in the column. --gutter is the space left of the text column: the
   sidebar, gap and padding (18.5rem), plus half of what's left over once
   the 61rem layout is centred; on phones just the padding. 100vw counts a
   classic scrollbar too, which .site clips. Positioned so it passes over the
   sticky sidebar rather than under it. */
.prose .wide img {
  --gutter: max(18.5rem, (100vw - 61rem) / 2 + 17rem);
  position: relative;
  width: min(100vw, 120rem);
  max-width: none;
  margin-left: calc((100vw - min(100vw, 120rem)) / 2 - var(--gutter));
}
@media (max-width: 52rem) {
  .prose .wide img {
    --gutter: 1rem;
  }
}
/* Wide figures one after another form one band: the gap between them is a
   border in the page colour on the lower image rather than a margin, so the
   sticky sidebar stays covered all the way down instead of peeking through.
   The negative margin cancels the 1.75rem above (.figure's margin). */
.prose .wide + .wide {
  margin-top: -1.75rem;
}
.prose .wide + .wide img {
  box-sizing: content-box;
  border-top: 1.75rem solid var(--bg);
}
.prose table {
  display: block;
  overflow-x: auto;
  border-collapse: collapse;
}
.prose th,
.prose td {
  padding: 0.35rem 0.75rem;
  text-align: left;
  vertical-align: top;
}
.prose th {
  background: var(--box-head);
}
.prose td {
  background: var(--box);
  border-top: 1px solid var(--bg);
}
.prose .footnote-definition,
.prose .footnotes {
  color: var(--muted);
  font-size: 0.875rem;
}

/* Full-page posts: a cover photo and a tinted palette, both set from a post's
   front matter (templates/page.html, README.md). */

/* tint = "#…" puts class="tinted" and --tint on <html>. Every colour leans
   towards the tint; light-dark() picks the base colour for the current mode,
   so this one block covers light, dark and the toggle. The base colours are
   the ones above. Text and muted text keep their base colours so contrast
   holds. */
:root.tinted {
  --bg: color-mix(in oklab, var(--tint) 10%, light-dark(#ffffff, #121212));
  --box: color-mix(in oklab, var(--tint) 12%, light-dark(#f5f5f5, #1b1b1b));
  --box-head: color-mix(in oklab, var(--tint) 14%, light-dark(#ebebeb, #262626));
  --hl: color-mix(in oklab, var(--tint) 14%, light-dark(#e2e3ea, #2d2f38));
  --selected: color-mix(in oklab, var(--tint) 40%, light-dark(#bfc8e3, #3f4866));
  --rule: color-mix(in oklab, var(--tint) 20%, light-dark(#d4d4d4, #383838));
  --accent: color-mix(in oklab, var(--tint) 65%, light-dark(#161616, #e4e4e4));
  --track: var(--box);
  --thumb: color-mix(in oklab, var(--tint) 25%, light-dark(#cdcdcd, #3c3c3c));
  --thumb-hover: color-mix(in oklab, var(--tint) 30%, light-dark(#a8a8a8, #555555));
}

/* The cover fills the first screen and stays put while the page slides up
   over it. With reduced motion it scrolls away like everything else. */
.cover {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100svh;
  overflow: hidden;
  background: var(--box-head);
  container-type: size;

  /* Set inline by templates/page.html: the photo's width / height, and its
     focal point and title position as plain percentages (no % sign). */
  --cover-ratio: 1.5;
  --cover-x: 50;
  --cover-y: 50;
  --title-x: 21;
  --title-y: 46;
  --title-w: 30;

  /* The photo's size on screen. object-fit: cover scales it to cover the
     whole cover, so it is at least as big as the cover on both axes. */
  --photo-w: max(100cqw, 100cqh * var(--cover-ratio));
  --photo-h: max(100cqh, 100cqw / var(--cover-ratio));
}
.cover + .site {
  position: relative;
  min-height: 100vh;
  min-height: 100svh;
  background: var(--bg);
}
@media (prefers-reduced-motion: reduce) {
  .cover {
    position: relative;
  }
}
@media (prefers-reduced-motion: no-preference) {
  html:has(.cover) {
    scroll-behavior: smooth;
  }
}

.cover-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--cover-position, 50% 50%);
  filter: brightness(var(--cover-dim));
}

/* The site title sits where the sidebar's will be once the cover is gone. */
.cover-site {
  position: absolute;
  top: 5rem;
  left: max(1.5rem, (100% - 61rem) / 2);
  font-size: 1.25rem;
  font-weight: 700;
  text-decoration: none;
}

/* The title is pinned to a point on the photo (cover_title_position), so it
   stays on the same patch of sky whatever the screen crops: its left edge is
   at --title-x across the photo, its middle at --title-y down. It wraps at
   --title-w of the photo's width and scales with the photo like a slide, but
   never leaves the screen. */
.cover-title {
  --title-width: min(var(--photo-w) * var(--title-w) / 100, 100cqw - 2rem);
  position: absolute;
  left: clamp(
    1rem,
    (100cqw - var(--photo-w)) * var(--cover-x) / 100 + var(--photo-w) * var(--title-x) / 100,
    100cqw - 1rem - var(--title-width)
  );
  top: clamp(
    7rem,
    (100cqh - var(--photo-h)) * var(--cover-y) / 100 + var(--photo-h) * var(--title-y) / 100,
    100cqh - 6rem
  );
  width: var(--title-width);
  transform: translateY(-50%);
  font-size: clamp(1.25rem, var(--photo-w) * 0.022, 2.75rem);
  font-weight: 400;
  line-height: 1.45;
  text-wrap: balance;
}
.cover-title .hl {
  color: var(--accent);
}

.cover-next {
  position: absolute;
  bottom: 2rem;
  left: 50%;
  transform: translateX(-50%);
  font-weight: 700;
  text-decoration: none;
}

.cover a:hover {
  background: none;
}
.cover a:hover .hl {
  background: var(--accent);
  color: var(--accent-fg);
}

#post {
  scroll-margin-top: 5rem;
}

@media (max-width: 52rem) {
  .cover-site {
    top: 2rem;
    left: 1rem;
  }
  /* Too narrow to fit the title beside the photo's subject, so it goes at
     the top, under the site title. */
  .cover-title {
    top: 6rem;
    right: 1rem;
    left: 1rem;
    width: auto;
    transform: none;
    font-size: 1.5rem;
  }
  #post {
    scroll-margin-top: 2rem;
  }
}
