/* site.css --- sxml-publish default stylesheet
   Modern minimal (Quartz / Astro Starlight bucket). Classless-first:
   styled by tag and ox-html's own classes, no utility framework. */

/* --- Fonts (self-hosted, Latin subset, variable weight) ------------ */
@font-face {
  font-family: "Source Serif 4";
  font-style: normal;
  font-weight: 200 900;
  font-display: swap;
  src: url("/static/fonts/source-serif-normal.woff2") format("woff2");
}
@font-face {
  font-family: "Source Serif 4";
  font-style: italic;
  font-weight: 200 900;
  font-display: swap;
  src: url("/static/fonts/source-serif-italic.woff2") format("woff2");
}
@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/static/fonts/ibm-plex-sans-normal.woff2") format("woff2");
}
@font-face {
  font-family: "IBM Plex Sans";
  font-style: italic;
  font-weight: 400 700;
  font-display: swap;
  src: url("/static/fonts/ibm-plex-sans-italic.woff2") format("woff2");
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/static/fonts/jetbrains-mono-normal.woff2") format("woff2");
}

/* --- Design tokens ------------------------------------------------ */
:root {
  --paper: #F7F7F4;
  --ink:   #1B1B18;
  --accent:#2B4A6B;
  --muted: #6B6B65;
  --rule:  #E4E1D8;

  --code-bg: color-mix(in oklch, var(--paper) 92%, var(--ink));

  /* Syntax highlighting (org-html-htmlize-output-type 'css); kept to
     a small, muted set rather than a full-rainbow scheme. */
  --syn-keyword:  var(--accent);
  --syn-string:   #5c7a4a;
  --syn-comment:  var(--muted);
  --syn-constant: #a2542f;
  --syn-fn:       #7a4a8a;

  --font-serif: "Source Serif 4", Charter, Georgia, serif;
  --font-sans:  "IBM Plex Sans", system-ui, sans-serif;
  --font-mono:  "JetBrains Mono", ui-monospace, monospace;

  --ratio: 1.125;        /* major second */
  --step-0:  1.2rem;
  --step-1:  calc(var(--step-0) * var(--ratio));
  --step-2:  calc(var(--step-1) * var(--ratio));
  --step-3:  calc(var(--step-2) * var(--ratio));
  --step-4:  calc(var(--step-3) * var(--ratio));
  --step-5:  calc(var(--step-4) * var(--ratio));
  --step--1: calc(var(--step-0) / var(--ratio));

  --measure: 88ch;
  --gutter:  22ch;
}

@media (prefers-color-scheme: dark) {
  :root {
    --paper:  #1A1B1E;
    --ink:    #E8E6DF;
    --accent: #7FA8CE;
    --rule:   #2A2A2E;

    --syn-keyword:  var(--accent);
    --syn-string:   #9dc48d;
    --syn-comment:  var(--muted);
    --syn-constant: #d99a6c;
    --syn-fn:       #c79fe0;
  }
}

/* Manual override via the nav theme toggle (templates/layouts.el sets
   data-theme on <html>, persisted to localStorage); takes precedence
   over prefers-color-scheme in both directions. */
:root[data-theme="dark"] {
  --paper:  #1A1B1E;
  --ink:    #E8E6DF;
  --accent: #7FA8CE;
  --rule:   #2A2A2E;

  --syn-keyword:  var(--accent);
  --syn-string:   #9dc48d;
  --syn-comment:  var(--muted);
  --syn-constant: #d99a6c;
  --syn-fn:       #c79fe0;
}
:root[data-theme="light"] {
  --paper: #F7F7F4;
  --ink:   #1B1B18;
  --accent:#2B4A6B;
  --muted: #6B6B65;
  --rule:  #E4E1D8;

  --syn-keyword:  var(--accent);
  --syn-string:   #5c7a4a;
  --syn-comment:  var(--muted);
  --syn-constant: #a2542f;
  --syn-fn:       #7a4a8a;
}

/* --- Reset -------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html { font-size: 100%; scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-serif);
  font-size: var(--step-0);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

/* --- Centered single column --------------------------------------- */
/* This site has no TOC/backlinks sidebar (layout/site only emits
   .page > article), unlike sxml-publish's notes-oriented layout/base. */
.page {
  max-width: var(--measure);
  margin: 4rem auto;
  padding: 0 1.5rem;
}

/* --- Wiki notes (three columns) ------------------------------------ */
/* The TOC and the sidebar are siblings of the article, not wrappers
   around it, so the middle column can keep the same measure as every
   other page on the site and the outer two can be pinned independently.
   Both outer columns are sticky and scroll on their own; below 64rem
   they stop being columns and stack under the note, TOC first. */
.page.note-layout {
  display: grid;
  grid-template-columns: 14rem minmax(0, var(--measure)) 16rem;
  gap: 2.5rem;
  justify-content: center;
  max-width: 100rem;
}

/* Explicit columns: a note without headlines omits .toc entirely, and
   without this, grid auto-placement would slide .note and .note-side
   left into the gap rather than leaving column 1 empty. */
.note-layout > .toc { grid-column: 1; }
.note-layout > .note { grid-column: 2; }
.note-layout > .note-side { grid-column: 3; }

.note-layout > .toc,
.note-layout > .note-side {
  position: sticky;
  top: 2rem;
  align-self: start;
  max-height: calc(100vh - 4rem);
  overflow-y: auto;
  font-family: var(--font-sans);
  font-size: var(--step--1);
  line-height: 1.4;
}

.note-layout .toc h2,
.note-layout .note-side h2 {
  font-size: var(--step--1);
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--muted);
  margin: 0 0 .5rem;
}

.note-layout .toc ul,
.note-layout .note-side ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

.note-layout .toc li { margin: .15rem 0; }
.note-layout .toc a { color: var(--muted); }
.note-layout .toc a:hover { color: var(--accent); }
.toc-2 { padding-left: .75rem; }
.toc-3 { padding-left: 1.5rem; }
.toc-4, .toc-5, .toc-6 { padding-left: 2.25rem; }

.note-side section + section { margin-top: 1.75rem; }
.note-side .backlink-list li,
.note-side .ref-list li { margin-bottom: .6rem; }
.note-side .context {
  display: block;
  color: var(--muted);
  font-size: .85em;
}

/* Aliases and tags under the note title. */
.note-meta {
  display: flex;
  gap: .5rem;
  flex-wrap: wrap;
  align-items: baseline;
  margin: .25rem 0 1.5rem;
  font-family: var(--font-sans);
  font-size: var(--step--1);
  color: var(--muted);
}
.note-meta .aliases { font-style: italic; }

/* A link to a note that exists in the vault but is not published, or to
   an id that no longer resolves.  Deliberately not an <a>. */
.dead-link {
  color: var(--muted);
  text-decoration: underline dotted;
  cursor: help;
}

/* --- Graph -------------------------------------------------------- */
.graph-holder {
  border: 1px solid var(--rule);
  border-radius: 4px;
  overflow: hidden;
}
.graph-svg { display: block; width: 100%; height: auto; }
.graph-node { cursor: pointer; }
.graph-node text { font-family: var(--font-sans); pointer-events: none; }
.graph-node:hover circle { stroke: var(--accent); stroke-width: 2; }

.note-graph.full .graph-holder { margin: 1.5rem 0; }

.notes-list {
  list-style: none;
  padding: 0;
  columns: 18rem 3;
  column-gap: 2rem;
}
.notes-list li {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  break-inside: avoid;
  padding: .1rem 0;
}
.notes-list .degree {
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: var(--step--1);
}
.notes-intro { color: var(--muted); }

@media (max-width: 64rem) {
  .page.note-layout {
    grid-template-columns: minmax(0, 1fr);
    max-width: var(--measure);
  }
  .note-layout > .toc,
  .note-layout > .note-side {
    position: static;
    max-height: none;
    overflow: visible;
  }
  /* Source order is TOC, note, sidebar; on a narrow screen the note
     itself has to come first. */
  .note-layout > .toc { order: 2; }
  .note-layout > .note { order: 1; }
  .note-layout > .note-side { order: 3; }
}

/* --- Headings ---------------------------------------------------- */
h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-sans);
  font-weight: 500;
  letter-spacing: -0.01em;
  line-height: 1.2;
}
h1 { font-size: var(--step-5); margin: 0 0 .5rem; }
h2 { font-size: var(--step-3); margin: 2.5rem 0 .75rem; }
h3 { font-size: var(--step-2); margin: 2rem 0 .5rem; }
h4, h5, h6 { font-size: var(--step-1); margin: 1.5rem 0 .5rem; }

/* Outline sections (ox-html wraps each headline + body in a div). */
.outline-2, .outline-3, .outline-4, .outline-5 { margin-top: 1rem; }
.section-number-2, .section-number-3, .section-number-4, .section-number-5 {
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

/* TODO/DONE keyword badges on headlines. */
.todo, .done {
  display: inline-block;
  font-family: var(--font-sans);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: .04em;
  padding: 0 .4em;
  border-radius: 3px;
  vertical-align: middle;
}
.todo { color: var(--accent); border: 1px solid var(--accent); }
.done { color: var(--muted); border: 1px solid var(--rule); text-decoration: line-through; }

/* Inline timestamps, e.g. <2024-01-01 Mon>. */
.timestamp-wrapper, .timestamp {
  font-family: var(--font-mono);
  font-size: .92em;
  color: var(--muted);
}

/* --- Metadata strip ---------------------------------------------- */
.note-meta {
  font-family: var(--font-sans);
  font-size: var(--step--1);
  color: var(--muted);
  border-bottom: 1px solid var(--rule);
  padding-bottom: .5rem;
  margin-bottom: 2rem;
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
}

/* --- Sidenotes (signature) --------------------------------------- */
.sidenote {
  float: right;
  clear: right;
  width: var(--gutter);
  margin-right: calc(-1 * var(--gutter) - 3rem);
  font-family: var(--font-sans);
  font-size: var(--step--1);
  color: var(--muted);
  line-height: 1.4;
}
@media (max-width: 78rem) {
  .sidenote {
    float: none;
    margin: 1rem 0;
    padding-left: 1rem;
    border-left: 2px solid var(--rule);
    width: auto;
  }
}

/* --- Links ------------------------------------------------------- */
a {
  color: var(--accent);
  text-decoration: none;
}
a[data-wikilink] { text-decoration-style: dotted; }

a:hover {
  text-decoration-color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* --- Prose: paragraphs, emphasis, blockquote, verse --------------- */
p { margin: 1em 0; }
strong, b { font-weight: 600; }
em, i { font-style: italic; }
.underline { text-decoration: underline; }

blockquote {
  margin: 1.5rem 0;
  padding: .25rem 0 .25rem 1.25rem;
  border-left: 3px solid var(--rule);
  color: var(--muted);
  font-style: italic;
}
blockquote p:first-child { margin-top: 0; }
blockquote p:last-child { margin-bottom: 0; }

p.verse {
  margin: 1.5rem 0;
  padding-left: 1.25rem;
  border-left: 3px solid var(--rule);
  font-family: var(--font-serif);
  white-space: pre-line;
}

hr {
  border: none;
  border-top: 1px solid var(--rule);
  margin: 3rem 0;
}

/* --- Lists and description lists ---------------------------------- */
ul, ol, .org-ul, .org-ol { padding-left: 1.5em; }
li { margin: .3em 0; }

dl.org-dl { margin: 1.5rem 0; }
dl.org-dl dt {
  font-family: var(--font-sans);
  font-weight: 500;
  color: var(--ink);
}
dl.org-dl dd { margin: 0 0 .75rem 1.5rem; color: var(--muted); }

/* --- Tables --------------------------------------------------------
   ox-html emits presentational border/cellpadding attributes; reset
   them and take over via CSS. */
table {
  border-collapse: collapse;
  width: 100%;
  margin: 1.5rem 0;
  font-size: var(--step--1);
}
table, th, td { border: none; }
th, td {
  padding: .5rem .75rem;
  border-bottom: 1px solid var(--rule);
  text-align: left;
}
th {
  font-family: var(--font-sans);
  font-weight: 600;
  border-bottom: 2px solid var(--ink);
}

/* --- Figures -------------------------------------------------------- */
.figure {
  margin: 2rem 0;
  text-align: center;
}
.figure img { max-width: 100%; height: auto; border-radius: 4px; }
.figure .figure-number {
  font-family: var(--font-sans);
  font-weight: 600;
  color: var(--muted);
}
.figure p:last-child {
  font-family: var(--font-sans);
  font-size: var(--step--1);
  color: var(--muted);
  margin-top: .5rem;
}

/* --- Code ---------------------------------------------------------- */
pre, code { font-family: var(--font-mono); font-size: .92em; }
code { background: var(--code-bg); padding: .1em .3em; border-radius: 3px; }
pre {
  background: var(--code-bg);
  padding: 1rem;
  overflow-x: auto;
  border-radius: 4px;
  line-height: 1.5;
}
pre code { background: none; padding: 0; }
.org-src-container { margin: 1.5rem 0; }

/* Syntax highlighting classes emitted by htmlize when
   `org-html-htmlize-output-type' is `css' (recommended; see
   examples/publish-config.el). Falls back to plain unstyled <pre>
   text otherwise, since htmlize's default 'inline-css mode bakes in
   colors that can't respond to dark mode. */
.org-keyword        { color: var(--syn-keyword); }
.org-string, .org-doc { color: var(--syn-string); }
.org-comment         { color: var(--syn-comment); font-style: italic; }
.org-constant, .org-type { color: var(--syn-constant); }
.org-function-name, .org-builtin { color: var(--syn-fn); }
.org-warning         { color: var(--syn-constant); font-weight: 600; }

/* --- Footnotes -------------------------------------------------------- */
#footnotes {
  margin-top: 3rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--rule);
  font-size: var(--step--1);
}
h2.footnotes {
  font-family: var(--font-sans);
  font-size: var(--step-0);
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--muted);
  margin-top: 0;
}
.footdef { display: flex; gap: .5em; margin: .5em 0; }
.footpara { margin: 0; }
.footnum, .footref { text-decoration: none; }

/* --- Backlinks --------------------------------------------------- */
.backlinks {
  margin-top: 4rem;
  padding-top: 2rem;
  border-top: 1px solid var(--rule);
}
.backlinks h2 {
  font-size: var(--step-1);
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--muted);
}
.backlink { margin-bottom: 1rem; }
.backlink p { margin: .25rem 0 0; color: var(--muted); font-size: var(--step--1); }

/* --- Tag chips --------------------------------------------------- */
.tag,
.keyword-badge {
  display: inline-block;
  border: 1px solid var(--rule);
  border-radius: .3rem;
  padding: .1rem .5rem;
  /* Explicit, not inherited: tags sit inside headings, where they would
     otherwise pick up the heading's font size. */
  font-family: var(--font-sans);
  font-size: var(--step--1);
  line-height: 1.5;
  text-decoration: none;
  color: var(--ink);
}
.tag:hover,
.keyword-badge:hover { border-color: var(--accent); color: var(--accent); }

/* Nerd Font glyphs typed directly in org content are traced to inline
   <svg> at publish time (lisp/nerd-icons.el); size/align them like the
   data-icon glyphs above instead of the font's own metrics. */
.icon.nerd-icon { display: inline-block; line-height: 1; }
.icon.nerd-icon::before { content: none; }
.icon.nerd-icon svg {
  width: 1em;
  height: 1em;
  vertical-align: -0.125em;
  fill: currentColor;
}

/* --- Header nav icons (github/linkedin/...) ----------------------- */
nav.social { display: flex; gap: .75rem; align-items: center; }
.icon-link .icon {
  display: inline-block;
  vertical-align: middle;
}
.icon-link { color: var(--muted); text-decoration: none; font-size: var(--step--1); }
.icon-link:hover { color: var(--accent); }

/* --- Post metadata ------------------------------------------------- */
.post-meta { display: flex; gap: .5rem; align-items: center; margin: .5rem 0 1.5rem; color: var(--muted); }

/* --- Talks (single-page, one entry per headline) ------------------- */
.talk-meta {
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
  align-items: center;
  margin: .25rem 0 1rem;
  color: var(--muted);
  font-size: var(--step--1);
}

/* --- Projects (card columns) ---------------------------------------- */
/* The <article> is itself the column container (see pac/article in
   lisp/ox-pac.el): .project-card children flow into the columns,
   everything else at that level -- the h1 and the intro paragraph --
   spans the full width.
   Multi-column, not grid: a grid lays cards out in *rows*, so an uneven
   pair always leaves a hole under the shorter one.  Multicol stacks each
   column independently, letting cards keep their natural height and tile
   flush against each other.  The trade-off is reading order -- content
   flows down column one, then down column two.
   Falls back to a single column below ~40rem, since `columns' drops a
   column rather than squeezing one narrower than `column-width'. */
article.projects {
  columns: 17rem 2;
  column-gap: 1.5rem;
}
article.projects > :not(.project-card) { column-span: all; }

.project-card {
  /* Keep a card whole rather than letting it split across the column
     break -- this is what makes the tiling look deliberate. */
  break-inside: avoid;
  display: flex;
  flex-direction: column;
  gap: .5rem;
  margin-bottom: 1.5rem;
  padding: 1rem;
  border: 1px solid var(--rule);
  border-radius: .5rem;
  transition: border-color .15s ease;
}
.project-card:hover { border-color: var(--accent); }

.project-image {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: .3rem;
  margin: 0;
}

.project-title {
  font-size: var(--step-1);
  margin: 0;
}

.project-tags { display: flex; flex-wrap: wrap; gap: .35rem; }

/* No flex-grow anywhere in the card: with multicol each card is only as
   tall as its content, so nothing needs to absorb slack. */
.project-blurb { color: var(--muted); }
.project-blurb p { margin: 0; }

.project-links { display: flex; flex-wrap: wrap; gap: .75rem; }
.project-links p { margin: 0; }

.project-more { font-size: var(--step--1); }
.project-more > summary {
  cursor: pointer;
  color: var(--muted);
  font-family: var(--font-sans);
}
.project-more > summary:hover { color: var(--accent); }
.project-more[open] > summary { margin-bottom: .5rem; }
.project-more h2, .project-more h3, .project-more h4 {
  font-size: var(--step-0);
  margin: 1rem 0 .25rem;
}
.project-more :first-child { margin-top: 0; }
.project-more img, .project-more svg { max-width: 100%; }

/* --- Homepage hero -------------------------------------------------- */
.hero { text-align: center; margin-bottom: 2rem; }
.hero-photo {
  width: 128px;
  height: 128px;
  border-radius: 50%;
  object-fit: cover;
  margin-bottom: 1rem;
}
.hero-name { margin: 0; font-size: var(--step-4); }
.hero-tagline { margin: .25rem 0 0; color: var(--muted); }

/* --- Homepage intro ------------------------------------------------ */
.icon-padded { margin-right: .4rem; }
.intro-columns { display: flex; flex-wrap: wrap; gap: 2rem; margin-top: 1.5rem; }
.intro-col { flex: 1 1 240px; }
.intro-edu-item { display: flex; gap: .75rem; margin-bottom: .75rem; }
.intro-edu-sub { display: block; color: var(--muted); font-size: var(--step--1); }

/* --- hfile:/xkcd:/repo-link inline elements ------------------------- */
a.hfile::before { content: "\2913 "; }
img.xkcd { max-width: 100%; }
.repo-link { font-weight: 600; }

/* --- TOC --------------------------------------------------------- */
.toc {
  position: sticky;
  top: 2rem;
  align-self: start;
  font-family: var(--font-sans);
  font-size: var(--step--1);
  line-height: 1.5;
}
.toc ol { list-style: none; padding: 0; margin: 0; }
.toc a { color: var(--muted); text-decoration: none; }
.toc a:hover { color: var(--accent); }

/* --- Header / nav ------------------------------------------------ */
header.site {
  max-width: 108ch;
  margin: 2rem auto 0;
  padding: 0 1.5rem;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-family: var(--font-sans);
}
header.site .brand { font-weight: 500; text-decoration: none; color: var(--ink); font-size: var(--step-1); }
header.site nav a {
  margin-left: 1.25rem;
  color: var(--ink);
  text-decoration: none;
  font-size: var(--step-1);
}
header.site nav a:hover { color: var(--accent); }

.theme-toggle {
  margin-left: 1.25rem;
  width: 1.75rem;
  height: 1.75rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: 1px solid var(--rule);
  border-radius: 999px;
  color: var(--muted);
  font-size: var(--step--1);
  line-height: 1;
  cursor: pointer;
}
.theme-toggle:hover { border-color: var(--accent); color: var(--accent); }
.theme-toggle::before { content: "\1F319"; } /* crescent moon: click to go dark */
@media (prefers-color-scheme: dark) {
  .theme-toggle::before { content: "\2600"; } /* sun: click to go light */
}
:root[data-theme="dark"] .theme-toggle::before { content: "\2600"; }
:root[data-theme="light"] .theme-toggle::before { content: "\1F319"; }

/* --- Footer ------------------------------------------------------ */
footer.site-footer {
  max-width: 108ch;
  margin: 4rem auto 2rem;
  padding: 2rem 1.5rem 0;
  border-top: 1px solid var(--rule);
  font-family: var(--font-sans);
  font-size: var(--step--1);
  color: var(--muted);
}

/* --- Motion -------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

/* --- Print ----------------------------------------------------------
   Drop chrome that means nothing on paper; keep prose full-width. */
@media print {
  /* Force light colors on paper regardless of the OS dark-mode
     setting; a dark background at print time just wastes toner. */
  :root {
    --paper: #FFFFFF;
    --ink: #000000;
    --accent: #2B4A6B;
    --muted: #4A4A46;
    --rule: #CCCCCC;
    --code-bg: #F2F2F2;
  }
  header.site, footer.site-footer, .toc, .backlinks, script { display: none; }
  .page {
    grid-template-columns: 1fr;
    max-width: var(--measure);
    margin: 0 auto;
  }
  a { color: var(--ink); text-decoration: none; }
  a[href]::after { content: " (" attr(href) ")"; font-size: .8em; color: var(--muted); }
  pre, blockquote { break-inside: avoid; }
}
