/* David Samuel — personal page. Type: Academica (Storm Type Foundry,
   licensed webfonts), Montserrat (OFL) for sans, Monaspace Xenon (OFL)
   for code. */

@font-face {
  font-family: "Academica";
  src: url("fonts/Academica-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Academica";
  src: url("fonts/Academica-RegularItalic.woff2") format("woff2");
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}

@font-face {
  font-family: "Academica";
  src: url("fonts/Academica-Bold.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

@font-face {
  /* subset to the characters code snippets actually use — 6 kB */
  font-family: "Monaspace Xenon";
  src: url("fonts/MonaspaceXenon-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Montserrat";
  src: url("fonts/Montserrat-Medium.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Montserrat";
  src: url("fonts/Montserrat-Bold.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

:root {
  color-scheme: light;

  --bg: #ffffff;
  --ink: #080624;
  --muted: #585585;
  --accent: #d90021;
  --highlight: #fdefea;
  --marker: #f4ddd4; /* deeper cut of --highlight for the thin stroke */
  --surface: #ededf2;
  --viz-font: 1rem; /* figure text; smaller on small screens (media query) */

  --serif: "Academica", "Charter", Cambria, Georgia, serif;
  --sans: "Montserrat", ui-sans-serif, sans-serif;
  --mono: "Monaspace Xenon", ui-monospace, monospace;

  --margin-width: 16rem; /* sidenote column, hung --margin-gap off the text */
  --margin-gap: 1.75rem;
}

* {
  margin: 0;
  box-sizing: border-box;
}

/* iOS inflates text on rotation; the typesetter's measurements must own the size */
html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

/* footnote jumps glide, unless the reader asked for less motion */
@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }
}

/* 19px against the 42rem measure ≈ 73 characters per line; size and column
   are both rem (they follow the browser default) — never scale them together */
body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--serif);
  font-size: 1.1875rem; /* 19px */
  line-height: 1.55;
  max-width: 42rem;
  margin: 0 auto;
  padding: 1.5rem 1.25rem 3rem;
}

/* hyperlinks carry no color of their own — the underline marks them */
a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 0.2em;
  text-decoration-thickness: 1px;
}

/* the marker stroke under emphasis and hovered links, seated on the
   underline. Background + vertical padding add no layout size (horizontal
   padding would break the justified measurements); a.hover mirrors hover
   across the typesetter's per-line clones of a wrapped link. */
a:hover,
a.hover,
a:focus-visible,
em {
  color: var(--accent);
  background-image: linear-gradient(var(--marker), var(--marker));
  background-repeat: no-repeat;
  background-size: calc(100% + 0.3em) 0.3em;
  background-position: -0.15em 100%;
  padding-bottom: 0.1em;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

em {
  font-style: italic;
}

/* selection wears the marker tint (the paler --highlight would vanish) */
::selection {
  background: var(--marker);
}

/* no-JS justification fallback; must fully stand down once .jst is set —
   text-wrap would out-cascade the lower-specificity .jst nowrap below */
#about p:not(.jst),
#teaching p:not(.jst),
.pub-title:not(.jst),
.project-title:not(.jst),
.pub-meta:not(.jst),
.pub-abstract:not(.jst),
.project-desc:not(.jst),
.post > p:not(.post-date):not(.jst),
.footnotes p:not(.jst),
.viz-tip-text:not(.jst),
figcaption:not(.jst) {
  text-align: justify;
  text-wrap: pretty;
  -webkit-hyphens: auto;
  hyphens: auto;
}

/* typeset lines (js/typeset.js): one rendered line per span; breaks and
   hyphens are generated content, so copied text stays untouched */
.jst {
  white-space: nowrap;
}

.jst .line + .line::before {
  content: "\A";
  white-space: pre;
}

.jst .shy::after {
  content: "-";
}

/* Header: name on the left, menu on the right */

.top {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-family: var(--sans);
  font-size: 0.9em; /* em: the header follows the body size */
}

h1 {
  font-size: inherit;
  font-weight: 700;
}

/* the name is a link home, but dressed as plain text */
h1 a {
  text-decoration: none;
}

h1 a:hover,
h1 a:focus-visible {
  color: inherit;
  background: none;
  padding-bottom: 0;
}

.menu {
  display: flex;
  gap: 1.25rem;
}

.menu a {
  font-weight: 500;
}

/* the prose marker stroke, but painted inside the box: the menu links are
   blockified flex items, where paint padding would grow the header */
.menu a:hover,
.menu a:focus-visible {
  background-position: -0.15em calc(100% - 0.15em);
  padding-bottom: 0;
}

section {
  margin-top: 3.5rem;
}

#about {
  margin-top: 3rem; /* = .post: pages open at the same height */
}

.contacts {
  margin-top: 1.25rem;
}

h2 {
  position: relative;
  font-family: var(--sans);
  font-size: 0.9em; /* em: never smaller than the text it heads */
  font-weight: 700;
  border-bottom: 2px solid var(--muted);
  margin-bottom: 1rem;
}

.mark {
  display: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

@media (min-width: 69rem) {
  .mark {
    display: block;
    position: absolute;
    right: calc(100% + 0.5rem);
    top: 0.1em;
    width: 1.4em;
    height: 1.4em;
    color: var(--muted);
  }
}

.pub,
.project {
  margin-bottom: 1.75rem;
}

/* tight leading: a wrapped title must read as one line of thought; the
   margin gives back the removed half-leading */
.pub-title,
.project-title {
  font-weight: 700;
  font-size: 1rem;
  line-height: 1.25;
  margin-bottom: 0.175em; /* half of the 0.35em of leading taken out */
}

.pub-meta {
  font-style: italic;
  line-height: 1.25;
  font-size: 1rem;
  margin-top: 0.35em;
  color: var(--muted);
}

.pub-abstract,
.project-desc {
  margin-top: 0.5rem;
  font-size: 1rem;
}

/* the teaching paragraph reads as section detail, like the abstracts */
#teaching p {
  font-size: 1rem;
}

.venue {
  display: block;
  font-weight: 400; /* the surrounding title is bold */
  font-size: 0.9rem;
  margin-top: 0.7rem;
  margin-bottom: 0.35em;
  color: var(--muted);
}

.post {
  position: relative; /* anchor for the absolutely-positioned sidenotes */
  margin-top: 3rem;
}

.post h2 {
  font-family: var(--serif);
  font-size: 2.625rem;
  letter-spacing: -0.015em;
  line-height: 1.1;
  border-bottom: none;
  margin-bottom: 1rem;
  text-align: center;
}

.post h3 {
  font-size: 1.9rem;
  letter-spacing: -0.01em; /* less than the title: nearer its cut size */
  line-height: 1.1;
  margin-top: 4rem;
  margin-bottom: 1rem;
}

/* caption type: date line, figure captions */
.post-date,
figcaption {
  font-size: 1rem;
  line-height: 1.3; /* full-column measure: tighten less than the notes */
  margin-bottom: 3rem;
  color: var(--muted);
}

.post-date {
  margin-bottom: 1rem;
  text-align: center;
}

.post p + p {
  margin-top: 1.25rem;
}

/* the chip's side tint is offset shadows (no layout width) plus a small
   real margin the justifier absorbs; the box must never grow vertically —
   margin-note lines pass within 1px of it */
code {
  font-family: var(--mono);
  font-size: 0.8em;
  background: var(--surface);
  box-shadow: 0.2em 0 0 var(--surface), -0.2em 0 0 var(--surface);
  margin: 0 0.12em;
  -webkit-hyphens: none;
  hyphens: none;
}

.post blockquote {
  margin: 1rem 1.25rem 1.25rem; /* bottom = the p + p gap it interrupts */
}

/* the BibTeX block: code on the figures' surface panel */
pre {
  background: var(--surface);
  border-radius: 0.45rem;
  padding: 0.8rem 1rem;
  margin-top: 1.25rem;
  line-height: 1.2;
  overflow-x: auto; /* never let a long URL widen the page */
}

pre code {
  font-size: 0.9rem;
  background: none;
  box-shadow: none;
  margin: 0;
}

/* footnotes, authored inline (js/footnotes.js rewrites them); without JS
   the spans render as muted parentheticals: */
.fn {
  font-size: 1rem;
  color: var(--muted);
}

.fn::before {
  content: "\00a0(";
}

.fn::after {
  content: ")";
}

sup {
  line-height: 0; /* keep raised markers from opening up the line spacing */
}

/* print-style markers: bold sans numerals, one on the line and one
   opening its note */
.fnref {
  font-family: var(--sans);
  font-size: 0.8rem;
  font-weight: 700;
  color: var(--muted);
}

/* marker links keep the plain numeral look; hover only tints them */
.fnref a {
  text-decoration: none;
}

.fnref a:hover,
.fnref a.hover,
.fnref a:focus-visible {
  color: var(--accent);
  background: none;
  padding-bottom: 0;
}

.footnotes {
  margin-top: 2.5rem;
  border-top: 1px solid var(--muted);
  padding-top: 1.25rem;
  font-size: 1rem;
  line-height: 1.2; /* short measure: much tighter than the captions */
  color: var(--muted);
}

.footnotes p + p {
  margin-top: 1rem;
}

/* the numeral is a label beside the note, not its first word */
.footnotes .fnref {
  margin-right: 0.25em;
}

/* sidenote mode: .side only means JS is alive; this media query decides */
@media (min-width: 80rem) {
  .footnotes.side {
    margin-top: 0;
    border-top: none;
    padding-top: 0;
  }

  .footnotes.side p {
    position: absolute; /* top is set per-note by js/footnotes.js */
    left: calc(100% + var(--margin-gap));
    width: var(--margin-width);
    margin-top: 0;
  }

  .footnotes.side .fnback {
    display: none;
  }

  /* the note sits beside the line; the marker has nowhere to lead */
  .fnref a {
    pointer-events: none;
  }
}

.viz {
  position: relative;
  margin: 2rem 0;
}

/* the panel holds the controls and the plot; the caption sits below it */
.viz-panel {
  background: var(--surface);
  border-radius: 0.45rem;
  padding: 1rem 0.85rem 0.9rem; /* the scripts subtract this when sizing */
}

/* panels are created once, so the fade marks arrival without re-flashing */
@media (prefers-reduced-motion: no-preference) {
  .viz-panel {
    animation: viz-appear 0.4s ease-out;
  }

  @keyframes viz-appear {
    from { opacity: 0; }
  }
}

.viz svg {
  display: block;
  width: 100%;
  height: auto;
}

/* figure dropdowns (js/viz-select.js) in the snippet card's chrome;
   js/divergence-tree.js reads this font and chrome to size the tree root */
.viz-select {
  position: relative;
  display: inline-flex;
  align-items: center;
  white-space: nowrap;
  user-select: none;
  -webkit-user-select: none;
  font: 700 15px var(--serif);
  color: var(--ink);
  height: 33px;
  padding: 0 22px 0 9px;
  border: 1px solid rgba(97, 94, 141, 0.4); /* the snippet card's chrome */
  border-radius: 0.35rem;
  background-color: var(--bg);
  box-shadow: 0 2px 10px rgba(27, 25, 59, 0.12);
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="10" height="6"><path d="M1 1l4 4 4-4" fill="none" stroke="%23615e8d" stroke-width="1.5" stroke-linecap="round"/></svg>');
  background-repeat: no-repeat;
  background-position: right 7px center;
  cursor: pointer;
}

.viz-select:hover,
.viz-select:focus-visible,
.viz-select[aria-expanded="true"] {
  color: var(--accent);
  border-color: rgba(217, 0, 33, 0.45);
  background-color: var(--highlight);
}

/* the dropdown popup; back to the page's ink and weight, current choice bold */
.viz-options {
  position: absolute;
  top: calc(100% + 5px);
  left: 0;
  z-index: 2; /* over its own figure's tooltips */
  min-width: 100%;
  max-width: 80vw;
  max-height: 60vh; /* the prompt lists are long: scroll, as the OS popup did */
  overflow-y: auto;
  padding: 4px 0;
  list-style: none;
  font-size: 15px; /* all popups match, even under the bigger tree root */
  font-weight: 400;
  color: var(--ink);
  border: 1px solid rgba(97, 94, 141, 0.4);
  border-radius: 0.35rem;
  background: var(--bg);
  box-shadow: 0 6px 20px rgba(27, 25, 59, 0.15);
}

.viz-options li {
  padding: 4px 22px 4px 9px; /* the closed control's inset */
  overflow: hidden;
  text-overflow: ellipsis;
}

.viz-options li[aria-selected="true"] {
  font-weight: 700;
}

.viz-options li.active {
  color: var(--accent);
  background: var(--highlight);
}

.viz-prompt {
  position: absolute;
}

.viz-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 1.25rem;
  margin-bottom: 0.75rem;
}

/* an over-wide figure (the trees) scrolls inside its panel; the root
   dropdown lives in the scroller so it travels with the tree */
.viz-scroll {
  position: relative;
  overflow-x: auto;
}

/* the width attribute rules here, so the drawing can overflow and scroll */
.viz-scroll svg {
  width: auto;
}

/* endnote back-arrows (hidden in sidenote mode) */
.fnback {
  text-decoration: none;
}

.viz-fallback {
  font-size: 1rem;
  color: var(--muted);
}

.viz figcaption {
  margin-top: 0.5rem;
}

.viz-tip {
  position: absolute;
  z-index: 1;
  width: 26rem;
  max-width: 92%;
  background: var(--bg);
  border: 1px solid rgba(97, 94, 141, 0.4);
  border-radius: 0.45rem;
  padding: 0.7rem 0.9rem;
  font-size: 1rem; /* the caption size: the floor for text in a figure */
  line-height: 1.2; /* the margin notes' leading: an annotation, one block */
  box-shadow: 0 6px 20px rgba(27, 25, 59, 0.15);
  pointer-events: none; /* hover mode: never steal the pointer from the plot */
}

.viz-tip.pinned {
  pointer-events: auto; /* pinned by a click: the title link is clickable */
}

/* one-line tooltip (the benchmark figures): sized by its content */
.viz-tip-mini {
  width: auto;
  white-space: nowrap;
  padding: 0.35rem 0.65rem;
}

.viz-tip .viz-tip-title {
  margin-top: 0.35rem;
  font-style: italic; /* set apart by style, never by a smaller size */
  color: var(--muted);
}

/* hover/touch-reveal (js/reveal.js): a circle at --x/--y is cut out of the
   fore image while .uncover is set. The mask must not exist at rest —
   WebKit collapses a zero-radius mask to fully transparent. */
.reveal {
  position: relative;
  width: min(28rem, 100%); /* 2/3 of the text column, horizontally centered */
  margin: 2rem auto 2rem;
  /* vertical swipes keep scrolling the page; other touches reveal */
  touch-action: pan-y;
  /* a long press must keep revealing, not open the save-image callout */
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}

.reveal img {
  display: block;
  width: 100%;
  height: auto;
}

.reveal .fore {
  position: absolute;
  top: 0;
  left: 0;
}

.reveal.uncover .fore {
  /* the 1px stop is anti-aliasing, not a fade — the rim reads as sharp */
  -webkit-mask-image: radial-gradient(circle at var(--x, 50%) var(--y, 50%),
      transparent calc(3rem - 1px), #000 3rem);
  mask-image: radial-gradient(circle at var(--x, 50%) var(--y, 50%),
      transparent calc(3rem - 1px), #000 3rem);
}

.reveal figcaption {
  margin-top: 0.5rem;
}

/* small screens: smaller body and figure type. Must stay at the end of
   the file — these override equal-specificity rules by order alone. */
@media (max-width: 32rem) {
  body {
    font-size: 1.0625rem; /* 17px */
  }

  :root {
    --viz-font: 13px;
  }

  .viz-select,
  .viz-options {
    font-size: 13px;
  }
}
