/* =========================================================
   Uriah Daugaard — site stylesheet
   Cream + ink-green visual system, with terracotta accent.
   Type pairing: Cormorant Garamond (serif, also used letterspaced for the
   wordmark and page subtitles), Cookie (decorative numerals only),
   Inter (UI / metadata), JetBrains Mono (code-like labels).
   ========================================================= */

:root{
  --cream:        #fbf6e8;
  --cream-rgb:    251,246,232; /* same, as channels, for per-rule alphas */
  --cream-2:      #f3ecd6;   /* slightly deeper for surfaces */
  --ink:          #1f3a2f;   /* primary text + headings */
  --ink-2:        #2c4a3d;   /* secondary text */
  --ink-3:        #5a6f64;   /* tertiary / metadata */
  --sage:         #3a6a52;   /* script + script-like accents */
  --sage-rgb:     58,106,82;  /* same, as channels, for per-rule alphas */
  --terracotta:   #a74536;   /* "current/active" + small highlights */
  --gold:         #b08538;   /* small distinctions (Elton, etc.) — borders/fills */
  --gold-rgb:     176,133,56; /* same, as channels, for per-rule alphas */
  --gold-fill:    transparent;
  /* Distinction badges are set at 10-11px, and --gold as a *text* colour
     measures 3.11:1 on --cream and 2.84:1 on --cream-2 — under the 4.5:1 these
     sizes need, and under even the 3:1 large-text floor on the hover band. The
     token is therefore split: --gold keeps the border and fill (where contrast
     is not a legibility question), --gold-text carries the lettering at
     4.97:1 / 4.55:1. Dark mode needs no split; #d4af52 is 8.5:1 there. */
  --gold-text:    #86652b;
  /* Deliberately not rebound in dark mode. Artwork authored against a light page
     (the pipeline schematic) is laid on this, so it keeps the background it was
     drawn for instead of losing its black linework into the dark one. */
  --plate:        #fbf6e8;
  --rule:         rgba(31,58,47,.18);
  --rule-2:       rgba(31,58,47,.08);
  /* Page width, single source of truth. Every block container on every page
     resolves its own max-width from this, so the whole site narrows or widens
     from one line. The text column inside it is --max minus the 56px gutters on
     each side; the section rail measures its gutter position off that. */
  --max:          1020px;
  --text:         calc(var(--max) - 112px);
}

:root[data-theme="dark"]{
  --cream:        #0f1a1c;   /* deep ink page bg */
  --cream-rgb:    15,26,28;
  --cream-2:      #16242a;   /* surface */
  --ink:          #e9e0c8;   /* ivory primary */
  --ink-2:        #c9bfa3;   /* secondary */
  /* Was #8a8270, which measured 4.17:1 on --cream-2 — an AA failure at the
     9-12px this tone is actually used at (record metadata, the Lab panels,
     the sibling-paper rail). #9f9888 is 6.18:1 on the page and 5.55:1 on the
     surface, and stays clear of --ink-2 so the three-tone hierarchy holds. */
  --ink-3:        #9f9888;   /* tertiary */
  --sage:         #d4af52;   /* gold accent (replaces sage) */
  --sage-rgb:     212,175,82;
  --terracotta:   #e0a060;   /* warmer current/active */
  --gold:         #d4af52;
  --gold-text:    #d4af52;   /* no split needed here — 8.5:1 on --cream */
  --gold-rgb:     212,175,82;
  /* Dark mode rebinds --sage to gold, so a gold *outline* no longer separates a
     distinction badge from ordinary accent text. Distinctions keep their meaning
     here by being filled rather than by finding a fourth hue — the warm range is
     already carrying --sage and --terracotta. */
  --gold-fill:    rgba(212,175,82,.13);
  --rule:         rgba(212,175,82,.25);
  --rule-2:       rgba(212,175,82,.10);
}

/* Light only until the toggle says otherwise, matching the boot script in
   _quarto.yml: `light dark` handed the UA scrollbar, caret and selection colours
   to the browser's own dark preference while every authored pixel stayed cream. */
html{color-scheme:light}
html[data-theme="dark"]{color-scheme:dark}

/* Skip link. First focusable thing in the document (see _partials/nav.html), and
   off-screen rather than display:none — a hidden element takes no focus, which is
   the one thing this has to do. Every page's <main> carries id="main". */
.skip{
  position:absolute;left:-9999px;top:0;z-index:60;
  background:var(--ink);color:var(--cream);
  font-family:'Inter',sans-serif;font-size:13px;
  padding:10px 16px;border-radius:0 0 4px 0;text-decoration:none;
}
.skip:focus{left:0}

/* Keyboard focus. Nothing here authored one, so every control fell back to the
   UA ring — and Quarto's Bootstrap bundle ships `button:focus:not(:focus-visible)
   {outline:0}`, so the dark default ring landed invisibly on the near-black
   `.btn` pill. `:focus-visible` keeps it off mouse clicks. `:where()` holds the
   specificity at zero so any component can still override it. */
:where(a, button, summary, input, select, textarea, [tabindex]):focus-visible{
  outline:2px solid var(--terracotta);
  outline-offset:3px;
  border-radius:2px;
}
/* Filled controls: the terracotta ring has too little separation from --ink and
   --sage fills, so those get the page colour instead, ringed outside the pill. */
.btn:focus-visible,
.rp-cite .actions a.primary:focus-visible,
.ab-cta .actions a.primary:focus-visible,
.rp-toc .list a[aria-current="page"]:focus-visible{
  outline-color:var(--cream);
  outline-offset:-4px;
}

/* Respect a stated preference for less motion: everything animated here is
   decoration (hover bands, card lifts, drawer slide), so there is nothing to
   lose by stopping it. */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.001ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.001ms !important;
    scroll-behavior:auto !important;
  }
}

/* Suppress Quarto's auto-rendered title block — every page provides its own H1. */
#title-block-header,.quarto-title-block{display:none}

/* Quarto's Bootstrap bundle rules every h2 with
   `border-bottom:1px solid #dee2e6; padding-bottom:.5rem`.
   That underline is not part of this design — #dee2e6 is a grey that appears
   nowhere in the palette, and it collides with the rules the page draws for
   itself (.kv, .talks, .pj-section …). The padding is left in place so that
   removing the line does not reflow anything. */
h2,.h2{border-bottom:none}

*{box-sizing:border-box}
html,body{margin:0;padding:0}
body{
  background:var(--cream);
  color:var(--ink);
  font-family:'Cormorant Garamond', Georgia, serif;
  font-size:20px;
  line-height:1.55;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
}

/* ---- top bar -------------------------------------------- */
.site-bar{
  display:grid;
  grid-template-columns:1fr auto 1fr;
  align-items:center;
  padding:22px 56px;
  border-bottom:1px solid var(--rule);
  font-family:'Inter',sans-serif;
  font-size:13px;
  letter-spacing:.01em;
  color:var(--ink);
  background:var(--cream);
  position:sticky; top:0; z-index:20;
  backdrop-filter:saturate(140%) blur(2px);
}
.site-bar .nav-l, .site-bar .nav-r{display:flex;gap:26px;align-items:center}
/* A nav item that runs out of room should crowd its neighbours — visibly wrong,
   and fixed by the breakpoint below — rather than quietly fold onto a second
   line and double the height of the bar. */
.site-bar .nav-l a, .site-bar .nav-r a{white-space:nowrap}
.site-bar .nav-l{justify-content:flex-start}
.site-bar .nav-r{justify-content:flex-end}
.site-bar a{color:var(--ink);text-decoration:none}
.site-bar a:hover{color:var(--sage)}
/* Active nav item. The bar is one static file shared by every page, so the
   current page identifies itself with data-page on <html> (set from the page's
   YAML header) instead of a server- or script-applied class. :where() keeps the
   specificity at exactly what `.site-bar a.on` used to weigh, so hover still
   resolves the same way. */
:where(:root[data-page="home"])     .site-bar a[data-nav="home"],
:where(:root[data-page="projects"]) .site-bar a[data-nav="projects"],
:where(:root[data-page="research"]) .site-bar a[data-nav="research"],
:where(:root[data-page="lab"])      .site-bar a[data-nav="lab"],
:where(:root[data-page="talks"])    .site-bar a[data-nav="talks"],
:where(:root[data-page="contact"])  .site-bar a[data-nav="contact"]{color:var(--terracotta)}

/* theme toggle */
.theme-toggle{
  background:none;border:1px solid var(--rule);border-radius:999px;
  width:34px;height:34px;cursor:pointer;
  display:inline-flex;align-items:center;justify-content:center;
  color:var(--ink-2);
  margin-left:14px;padding:0;
  transition:color .15s,border-color .15s,background .15s;
}
.theme-toggle:hover{color:var(--sage);border-color:var(--sage)}
:root[data-theme="dark"] .theme-toggle{color:var(--sage);border-color:rgba(212,175,82,.4)}
.theme-toggle .ico-light,.theme-toggle .ico-dark{display:none;line-height:0}
.theme-toggle .ico-light svg,.theme-toggle .ico-dark svg{display:block}
.theme-toggle .ico-light{display:inline-flex}
:root[data-theme="dark"] .theme-toggle .ico-light{display:none}
:root[data-theme="dark"] .theme-toggle .ico-dark{display:inline-flex}

/* narrow-only tools cluster (hamburger + theme) — hidden on desktop */
.bar-tools{display:none}
.site-bar .wordmark{
  text-align:center;
  font-family:'Cormorant Garamond',serif;
  font-size:17px;
  line-height:1.05;
  color:var(--ink);
}
.site-bar .wordmark .b{
  font-family:'Cormorant Garamond',serif;
  font-size:15px;
  font-weight:600;
  letter-spacing:.11em;
  color:var(--sage);
  display:block;
  margin-top:7px;
}

/* ---- footer -------------------------------------------- */
.site-foot{
  margin-top:120px;
  padding:36px 56px 48px;
  border-top:1px solid var(--rule);
  display:grid;
  grid-template-columns:1fr auto 1fr;
  align-items:center;
  font-family:'Inter',sans-serif;
  font-size:12px;
  color:var(--ink-3);
  letter-spacing:.04em;
}
.site-foot .l{justify-self:start}
.site-foot .c{justify-self:center}
.site-foot .r{justify-self:end}
.site-foot a{color:var(--ink-3);text-decoration:none;margin-left:18px}
.site-foot a:hover{color:var(--sage)}

/* Quarto's layout stylesheet rules every direct child of #quarto-content with
   `padding-top:14px`, dropping to 0 under `@media (max-width:991.98px)`. That is
   an id selector, so it outranks `.site-bar` and `.site-foot` above and quietly
   replaced their top padding: the bar ended up with 14px of top against 22px of
   bottom (0 against 22 on narrow viewports, which is why its contents looked
   stuck to the top edge), and the footer lost 36px down to 14px. Restore the
   intended values at a specificity that actually wins. */
#quarto-content > .site-bar{padding-top:22px}
#quarto-content > .site-foot{padding-top:36px}

/* ---- generic page scaffold ----------------------------- */
.page{max-width:var(--max);margin:0 auto;padding:0 56px}
.page-narrow{max-width:780px;margin:0 auto;padding:0 56px}

/* Interior-page header: the title on one line with the page's lede stacked
   under it. Only the home page is centred — it is a masthead. Every other page
   gives the reader a left edge to come back to.

   This was a two-column grid, title beside lede. Both columns then had to be
   held narrow to share the 968px — `width:max-content` here and a character cap
   on the H1 — which forced short titles to wrap for no reason and left the row
   looking half-empty once a lede was trimmed. Stacked, the title gets the whole
   column and the lede gets a measure chosen for reading rather than for what was
   left over.

   Research still has its own copy of this (.rs-header), which already matches
   these metrics; this is the shared version they should all converge on.
   Work used to have one too (.pj-header) and now uses this directly. */
.page-head{
  max-width:var(--max);margin:48px auto 0;padding:0 56px;
}
.page-head .titles .page-title{margin:0;text-wrap:balance}
/* 66ch ≈ 750px ≈ 81 characters. `ch` is the width of "0", 0.477em in Cormorant
   against a ~0.39em average letter, so the real line is about 22% longer than
   the number reads. Sized to hold a two-sentence lede on two lines. */
.page-head .lead{
  font-family:'Cormorant Garamond',serif;font-size:24px;line-height:1.55;
  color:var(--ink-2);margin:16px 0 0;max-width:66ch;text-wrap:pretty;
}
.page-head .lead em{color:var(--sage);font-style:italic}
@media (max-width:900px){
  .page-head{margin-top:32px;padding:0 24px}
  .page-head .lead{font-size:22px;margin-top:14px}
}

/* ---- section rail --------------------------------------- */

/* The "on this page" rail, used by Publications and Work. It lived in
   research.css while it had one caller; it is shared now, and the scrollspy that
   drives it (site.js) was always generic: it binds to `.rs-toc`, reads that
   rail's own hrefs, and throws on a href with no matching section rather than
   leaving the entry inert. A third page needs markup and nothing else.

   Two forms, same markup. Wide viewports get the vertical rail in the right
   gutter. Everything narrower gets a horizontal strip stuck under the site bar,
   which is the form defined here as the base: the gutter needs
   (100vw - 908)/2 >= 164px to hold the labels clear of the text, i.e. a 1240px
   viewport, and hiding the rail below that left every window between the mobile
   breakpoint and 1240px with no wayfinding at all. */
.rs-toc{
  /* Minus 1px, and a deliberately low fallback: the strip must never leave a gap
     under the bar, because page content scrolls through one. Erring towards a
     1px overlap is invisible, and the fallback applies only for the frames
     before site.js publishes the measured height, where too small hides the
     strip briefly rather than showing text sliding through a slot. */
  position:sticky;top:calc(var(--bar-h,56px) - 1px);z-index:15;
  background:var(--cream);border-bottom:1px solid var(--rule);
  font-family:'Inter',sans-serif;
}
/* Quarto's layout stylesheet gives every direct child of #quarto-content
   `padding-top:14px`, and its bundle a further `margin-top:20px` on <main>.
   Both sit above the strip while it is in flow and neither is there once it
   sticks, so the band between bar and strip measured 20px taller at the top of
   the page than anywhere else, with page content sliding through the gap.
   Zeroed for the rail pages only; the 48px on `.page-head` below more than
   covers the loss. */
:root[data-page="research"] #quarto-content > main,
:root[data-page="projects"] #quarto-content > main{padding-top:0;margin-top:0}
/* `--bar-h` is published by site.js off the bar's measured height: it changes
   with breakpoint (the wordmark tagline is dropped between 901 and 1120px) and
   again when the webfont swaps in, so a hard-coded value per breakpoint would be
   wrong for the first paint on every one of them. The fallback is the bar at its
   shortest, so an unstyled first frame errs towards overlap rather than a gap. */
.rs-toc ul{
  list-style:none;margin:0 auto;padding:9px 56px;max-width:var(--max);
  display:flex;gap:24px;
  /* Narrow viewports scroll the strip sideways rather than wrapping it onto a
     second line and doubling the height of a sticky element. */
  overflow-x:auto;scrollbar-width:none;
}
.rs-toc ul::-webkit-scrollbar{display:none}
/* The page title, which the rail carries as its first entry, is redundant here:
   the strip sits directly above the H1 it would name. */
.rs-toc li.top{display:none}
/* The type metrics belong on the anchor, not only on `.t` inside it. `.rs-toc`
   sets no font-size, so the anchor's strut was inheriting the body's 20px/1.55
   and giving every row a 31px line box no matter how small the label was set.
   That made the strip nearly twice its intended height. */
.rs-toc a{
  position:relative;display:block;padding:4px 0 7px;
  font-size:10px;line-height:1;
  text-decoration:none;white-space:nowrap;
}
.rs-toc .t{
  font-size:10px;letter-spacing:.16em;text-transform:uppercase;font-weight:500;
  line-height:1;color:var(--ink-3);transition:color .28s ease;
}
/* The tick becomes the underline under the active label. Colour alone did not
   carry it in light mode: --sage against --ink-3 is a small enough step at 10px
   that no entry read as selected. */
.rs-toc .tick{
  display:block;position:absolute;left:0;right:0;bottom:0;height:2px;
  background:var(--sage);
  transform:scaleX(0);transform-origin:left center;
  transition:transform .28s cubic-bezier(.4,0,.2,1);
}
.rs-toc a:hover .t{color:var(--ink-2)}
.rs-toc a:hover .tick{transform:scaleX(.35)}
.rs-toc a[aria-current="true"] .t{color:var(--sage);font-weight:600}
.rs-toc a[aria-current="true"] .tick{transform:scaleX(1)}

@media (min-width:1240px){
  /* Fixed in the gutter rather than sticky in a column: these pages are a stack
     of independently centred blocks, so there is no grid column for a sticky
     child to sit in. `right` is measured off the text edge, not the viewport,
     which keeps the gap between rail and text constant at every width. `top`
     sits the rail level with the top of the page title; `.rs-header` and
     `.page-head` carry identical metrics, so one value serves both. */
  .rs-toc{
    position:fixed;top:140px;
    right:max(16px, calc((100vw - var(--text))/2 - 148px));
    width:124px;z-index:10;
    background:none;border-bottom:none;
  }
  .rs-toc ul{
    padding:0;max-width:none;overflow:visible;
    flex-direction:column;gap:15px;
  }
  /* The page title is separated from the sections by a hairline, so the rail
     reads as "the page, then its sections" rather than as a flat list of peers.
     It is also the one entry allowed to wrap inside the 124px column. */
  .rs-toc li.top{display:block;padding-bottom:15px;border-bottom:1px solid var(--rule-2)}
  .rs-toc a{
    display:grid;grid-template-columns:1fr 22px;align-items:center;gap:10px;
    padding:0;
  }
  .rs-toc .t{line-height:1.45;text-align:right;text-wrap:balance;font-weight:500}
  .rs-toc a[aria-current="true"] .t{font-weight:500}
  /* The tick is scaled rather than resized: animating width relayouts the grid
     row on every frame, transform does not. */
  .rs-toc .tick{
    position:static;height:1px;background:var(--rule);
    transform:scaleX(.5);transform-origin:right center;
    transition:transform .28s cubic-bezier(.4,0,.2,1),background-color .28s ease;
  }
  .rs-toc a:hover .tick{transform:scaleX(.8)}
  .rs-toc a[aria-current="true"] .tick{transform:scaleX(1);background:var(--sage)}
}

/* Jump targets on both rail pages. Shared here rather than repeated as an id
   list in each page stylesheet. The offset has to clear whichever form of the
   rail is on screen: bar plus strip below 1240px, bar alone above it. */
[id^="sec-"]{scroll-margin-top:calc(var(--bar-h,64px) + 58px)}
@media (min-width:1240px){
  [id^="sec-"]{scroll-margin-top:120px}
}

/* Anchor jumps otherwise land beneath the sticky bar. Listed per page rather
   than set on `html`, because this file loads everywhere and only these two
   pages have anchors to jump to. The prefers-reduced-motion block above
   overrides it back to auto with !important. */
:root[data-page="research"],
:root[data-page="projects"]{scroll-behavior:smooth}

.eyebrow{
  font-family:'Inter',sans-serif;
  font-size:11px;
  letter-spacing:.18em;
  text-transform:uppercase;
  color:var(--sage);
  font-weight:500;
}

.h-display{
  font-family:'Cormorant Garamond',serif;
  font-weight:500;
  font-size:88px;
  line-height:.95;
  letter-spacing:.005em;
  color:var(--ink);
  margin:0;
}

h1.page-title{
  font-family:'Cormorant Garamond',serif;
  font-weight:500;
  font-size:64px;
  line-height:1;
  letter-spacing:.005em;
  color:var(--ink);
  margin:64px 0 8px;
}
h2.section{
  font-family:'Cormorant Garamond',serif;
  font-weight:500;
  font-size:34px;
  margin:56px 0 14px;
  color:var(--ink);
  letter-spacing:.005em;
}
h2.section + .section-sub{
  font-family:'Inter',sans-serif;
  font-size:12px;
  letter-spacing:.16em;
  text-transform:uppercase;
  color:var(--sage);
  margin:0 0 24px;
  font-weight:500;
}

h3.subsection{
  font-family:'Cormorant Garamond',serif;
  font-weight:500;
  font-size:22px;
  margin:24px 0 10px;
  font-style:italic;
  color:var(--ink);
}

p{margin:0 0 14px;font-size:21px;line-height:1.6;color:var(--ink-2);text-wrap:pretty}
p.lede{font-size:24px;line-height:1.5;color:var(--ink);max-width:60ch}

a.inline{color:var(--ink);border-bottom:1px solid var(--rule)}
a.inline:hover{color:var(--terracotta);border-bottom-color:var(--terracotta)}

ul.clean{list-style:none;margin:0;padding:0}
ul.clean li{padding:6px 0;font-size:20px;color:var(--ink-2);border-top:1px solid var(--rule-2)}
ul.clean li:first-child{border-top:none}

/* ---- generic table-like "Now" block --------------------- */
.kv{
  border-top:1px solid var(--rule);
}
.kv .row{
  display:grid;
  grid-template-columns:110px 1fr;
  column-gap:32px;
  padding:18px 0;
  border-bottom:1px solid var(--rule-2);
  align-items:baseline;
}
.kv .k{
  font-family:'Inter',sans-serif;
  font-size:11px;
  letter-spacing:.16em;
  text-transform:uppercase;
  color:var(--sage);
  font-weight:500;
  line-height:1.6;
}
.kv .v{
  font-family:'Cormorant Garamond',serif;
  font-size:19px;
  line-height:1.7;
  color:var(--ink);
  display:block;
}
.kv .v > span{white-space:nowrap}
.kv .v > span:not(:last-child)::after{
  content:"";
  display:inline-block;
  width:4px;
  height:4px;
  border-radius:50%;
  background:var(--sage);
  opacity:.7;
  margin:0 .55em;
  vertical-align:middle;
  position:relative;
  top:-0.1em;
}
@media (max-width:900px){
  .kv .v{line-height:1.65}
}

/* ---- chip / pill --------------------------------------- */
.chip{
  display:inline-block;
  font-family:'Inter',sans-serif;
  font-size:11px;
  letter-spacing:.12em;
  text-transform:uppercase;
  color:var(--sage);
  padding:3px 8px;
  border:1px solid var(--rule);
  border-radius:999px;
  font-weight:500;
}
.chip.gold{color:var(--gold-text);border-color:rgba(var(--gold-rgb),.4);background:var(--gold-fill)}

/* ---- buttons ------------------------------------------- */
.btn{
  display:inline-flex; align-items:center; gap:10px;
  padding:9px 16px;
  background:var(--ink);
  color:var(--cream);
  font-family:'Inter',sans-serif;
  font-size:13px;
  font-weight:500;
  text-decoration:none;
  border-radius:999px;
  letter-spacing:.02em;
}
.btn:hover{background:var(--sage)}
.btn.ghost{background:transparent;color:var(--ink);border:1px solid var(--rule)}
.btn.ghost:hover{border-color:var(--sage);color:var(--sage)}
.btn .arrow{font-size:14px}

/* ---- card grid (used for research highlights, lab demos) */
.card-grid{
  display:grid;
  grid-template-columns:repeat(3, 1fr);
  gap:28px;
}
.card{
  background:var(--cream-2);
  border:1px solid var(--rule);
  border-radius:6px;
  overflow:hidden;
  display:flex; flex-direction:column;
  text-decoration:none; color:inherit;
  transition: transform .25s ease, box-shadow .25s ease;
}
.card:hover{transform:translateY(-2px);box-shadow:0 8px 24px rgba(31,58,47,.10)}
.card .thumb{
  aspect-ratio:4/3;
  background-color:var(--cream-2);
  background-size:cover; background-position:center; background-repeat:no-repeat;
  border-bottom:1px solid var(--rule);
}
.card .body{padding:16px 18px 20px}
.card .body h3,.card .body h4{
  font-family:'Cormorant Garamond',serif;
  font-weight:500; font-size:20px;
  margin:0 0 8px;
  color:var(--ink);
  line-height:1.2;
}
.card .body p{font-size:18px;line-height:1.5;color:var(--ink-2);margin:0 0 14px}
.card .meta{
  font-family:'Inter',sans-serif;font-size:11px;letter-spacing:.12em;
  text-transform:uppercase;color:var(--sage);margin-bottom:6px;font-weight:500;
}

/* ---- publication entry --------------------------------- */
/* Each entry is one record in three parts — authors, title, then a metadata rail
   of venue + chips — instead of a single run of prose. The parts are separated
   by size and colour rather than by rules or boxes, so the list keeps a
   bibliography's density while gaining a rhythm you can scan. */
.pub{
  position:relative;
  display:grid;
  grid-template-columns:68px 1fr;
  gap:22px;
  padding:13px 0 15px;
  border-top:1px solid var(--rule-2);
  font-family:'Cormorant Garamond',serif;
}
.pub:first-of-type{border-top:1px solid var(--rule)}

/* Whole-row hover. The tint is painted by a pseudo-element inset past the text
   column rather than by margins on .pub itself, so the row reads as a band while
   the hairline separators stay aligned with the rest of the page. */
.pub::before{
  content:"";
  position:absolute;inset:0 -18px;z-index:-1;
  border-radius:2px;background:transparent;
  transition:background-color .18s ease;
}
@media (hover:hover){
  .pub:hover::before{background:var(--cream-2)}
  .pub:hover .yr{color:var(--sage)}
  .pub:hover .yr::after{background:var(--sage)}
}

/* The year anchors the gutter: mono numerals and a hairline tick, giving the
   column a repeating beat that marks where each record begins. */
.pub .yr{
  font-family:'JetBrains Mono', ui-monospace, monospace;
  font-size:15px;letter-spacing:.01em;font-weight:400;
  color:var(--ink-3);padding-top:6px;
  transition:color .18s ease;
}
.pub .yr::after{
  content:"";display:block;width:20px;height:1px;
  margin-top:9px;background:var(--rule);
  transition:background-color .18s ease;
}

/* .body is the flex container for every part of the record: authors and title
   take a full line each, and the venue, any distinction and the chips share the
   last one. */
.pub .body{
  display:flex;flex-wrap:wrap;align-items:baseline;
  column-gap:10px;row-gap:4px;
  font-size:18px;line-height:1.5;color:var(--ink-2);
}
/* --ink-2 rather than --ink-3: at 16px the lighter tone measured 5.0:1 on cream
   and 4.6:1 on the hover band — passing, but with nothing to spare. The title
   still leads on size and weight. */
.pub .body .au{
  flex:1 0 100%;
  font-size:16px;line-height:1.4;color:var(--ink-2);
}
.pub .body .au strong{color:var(--ink);font-weight:600}
/* Roman, not italic: at 20px in --ink the title carries the entry on size and
   colour alone. Italic recedes, and a heavier weight is not available — only
   400/500/600 of Cormorant are loaded. */
.pub .body .ti{
  flex:1 0 100%;
  font-size:20px;line-height:1.3;
  font-weight:500;font-style:normal;color:var(--ink);
  margin-bottom:4px;text-wrap:pretty;
}
/* Venue as a label rather than prose, in the same small uppercase Inter the rest
   of the site uses for metadata; --ink-3 leaves --sage to the chips, which are
   the only things on that line you can actually click. */
.pub .body .vn{
  font-family:'Inter',sans-serif;font-weight:500;
  font-size:11px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--ink-3);margin-right:4px;
}
/* display:contents dissolves the wrapper into .body so the chips join the venue
   on the metadata line. */
.pub .body .links{display:contents}
.pub .body .links a{
  font-family:'Inter',sans-serif;font-size:11px;letter-spacing:.06em;
  color:var(--sage);text-decoration:none;
  border:1px solid var(--rule);padding:2px 8px;border-radius:999px;
}
.pub .body .links a:hover{border-color:var(--sage);background:var(--cream-2)}
/* The one chip that keeps you on the site — the long-form write-up — so it is
   marked out from the doi/data links, which all leave. */
.pub .body .links a.deep{
  color:var(--ink);border-color:rgba(var(--gold-rgb),.45);background:var(--gold-fill);
}
.pub .body .links a.deep:hover{border-color:var(--gold);background:var(--cream-2)}

/* Abstract disclosure. A native <details>, so it works without JavaScript and is
   keyboard-operable for free. It deliberately does NOT wear the chip pill: the
   chips beside it (doi, data + code) all navigate away, and a fourth pill reads
   as one more link off the page. A rotating triangle and plain label say
   "this opens here" instead. It sits on its own line under the chips. */
/* .body is a flex container, so the disclosure claims its own full-width row
   below the venue + chips line. */
.pub .abs{flex:1 0 100%;margin-top:6px}
.pub .abs > summary{
  list-style:none;cursor:pointer;user-select:none;width:max-content;
  font-family:'Inter',sans-serif;font-size:11px;letter-spacing:.1em;
  text-transform:uppercase;font-weight:500;
  color:var(--ink-3);
  transition:color .15s;
}
.pub .abs > summary::-webkit-details-marker{display:none}
/* Drawn rather than a glyph, so it is identical in every font. */
.pub .abs > summary::before{
  content:"";display:inline-block;
  width:0;height:0;margin-right:8px;
  border-left:5px solid currentColor;
  border-top:4px solid transparent;
  border-bottom:4px solid transparent;
  transform-origin:30% 50%;
  transition:transform .18s ease;
}
.pub .abs[open] > summary::before{transform:rotate(90deg)}
.pub .abs > summary:hover{color:var(--sage)}
.pub .abs[open] > summary{color:var(--sage)}
.pub .abs-body{
  margin-top:10px;padding-left:14px;
  border-left:2px solid var(--rule);
  max-width:74ch;
}
.pub .abs-body p{
  font-family:'Cormorant Garamond',serif;
  font-size:19px;line-height:1.6;color:var(--ink-2);
  margin:0 0 8px;text-wrap:pretty;
}
.pub .abs-body p:last-child{margin-bottom:0}
.pub .body .badge{
  display:inline-block;font-family:'Inter',sans-serif;font-size:11px;
  letter-spacing:.1em;text-transform:uppercase;color:var(--gold-text);
  border:1px solid rgba(var(--gold-rgb),.35);background:var(--gold-fill);
  padding:1px 8px;border-radius:999px;
  margin-left:8px;font-weight:500;
}
.pub .body .ja{color:var(--terracotta);font-family:'Inter',sans-serif;
  font-size:11px;letter-spacing:.08em;text-transform:uppercase;font-weight:500;
  margin-left:8px;}

/* ---- talks list ---------------------------------------- */
/* Same three-part record as the publication list: year in a mono gutter, the
   talk title carrying the row, then a metadata rail. See the "publication
   entry" block above — the two lists are deliberately the same instrument. */
.talks .item{
  position:relative;
  padding:13px 0 15px;border-top:1px solid var(--rule-2);
  display:grid;grid-template-columns:68px 1fr;gap:22px;align-items:start;
}
.talks .item:first-of-type{border-top:1px solid var(--rule)}
.talks .item::before{
  content:"";position:absolute;inset:0 -18px;z-index:-1;
  border-radius:2px;background:transparent;
  transition:background-color .18s ease;
}
@media (hover:hover){
  .talks .item:hover::before{background:var(--cream-2)}
  .talks .item:hover .when{color:var(--sage)}
  .talks .item:hover .when::after{background:var(--sage)}
}
.talks .item .when{
  font-family:'JetBrains Mono', ui-monospace, monospace;
  font-size:15px;letter-spacing:.01em;font-weight:400;
  color:var(--ink-3);padding-top:6px;
  transition:color .18s ease;
}
.talks .item .when::after{
  content:"";display:block;width:20px;height:1px;
  margin-top:9px;background:var(--rule);
  transition:background-color .18s ease;
}
.talks .item .what{font-family:'Cormorant Garamond',serif;font-size:20px;color:var(--ink-2);line-height:1.5}
/* The talk title, roman and on its own line — the same move as .pub .ti. */
.talks .item .what > em,
.talks .item .what > strong{
  display:block;
  font-size:20px;line-height:1.3;font-style:normal;font-weight:500;
  color:var(--ink);margin-bottom:5px;text-wrap:pretty;
}
.talks .item .what .where{
  display:block;margin-top:2px;color:var(--ink-2);font-size:17px;line-height:1.45;
}
/* The venue name reads as a label; the rest of the line stays prose. */
.talks .item .what .where strong{
  font-family:'Inter',sans-serif;font-weight:500;
  font-size:11px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--ink-3);margin-right:2px;
}
.talks .item .badge{
  display:inline-block;font-family:'Inter',sans-serif;font-size:10px;
  letter-spacing:.12em;text-transform:uppercase;color:var(--gold-text);
  border:1px solid rgba(var(--gold-rgb),.35);background:var(--gold-fill);
  padding:1px 7px;border-radius:999px;
  margin-left:6px;font-weight:500;vertical-align:middle;
}

/* ---- two-column block ---------------------------------- */
.cols-2{display:grid;grid-template-columns:1fr 1fr;gap:48px;align-items:start}
.cols-2.thirds{grid-template-columns:2fr 1fr}

/* ---- plates row ---------------------------------------- */
.plates{
  display:flex;justify-content:center;align-items:flex-start;gap:32px;
  margin: 64px auto 28px;
}
.plate{display:flex;flex-direction:column;align-items:center;gap:10px;width:200px}
.plate img{width:160px;height:160px;object-fit:contain}
.plate .lbl{
  font-family:'Cormorant Garamond',serif;font-style:italic;
  font-size:13px;color:var(--ink-3);text-align:center;line-height:1.3;
}
.plate .lbl b{
  font-family:'Cormorant Garamond',serif;font-style:italic;
  font-size:13px;letter-spacing:0;text-transform:none;color:var(--ink-2);
  font-weight:500;
}

/* ---- hamburger + drawer (narrow only) ------------------ */
.nav-toggle{
  display:none;
  background:none;border:none;padding:8px;cursor:pointer;
  width:40px;height:40px;
}
.nav-toggle span{
  display:block;width:22px;height:1.5px;margin:5px auto;
  background:var(--ink);transition:transform .2s, opacity .2s;
}
.nav-toggle.is-open span:nth-child(1){transform:translateY(6.5px) rotate(45deg)}
.nav-toggle.is-open span:nth-child(2){opacity:0}
.nav-toggle.is-open span:nth-child(3){transform:translateY(-6.5px) rotate(-45deg)}
.nav-drawer{
  position:fixed;top:auto;right:18px;z-index:25;
  background:var(--cream-2);border:1px solid var(--rule);
  border-radius:6px;
  padding:14px 18px;
  min-width:200px;
  box-shadow:0 10px 28px rgba(0,0,0,.08);
  margin-top:-18px;
}
.nav-drawer nav{display:flex;flex-direction:column;gap:2px;font-family:'Inter',sans-serif;font-size:14px}
.nav-drawer a{color:var(--ink);text-decoration:none;padding:8px 4px;line-height:1.2;border-radius:4px}
/* Active item in the drawer — see the matching note on `.site-bar a`. */
:where(:root[data-page="home"])     .nav-drawer a[data-nav="home"],
:where(:root[data-page="projects"]) .nav-drawer a[data-nav="projects"],
:where(:root[data-page="research"]) .nav-drawer a[data-nav="research"],
:where(:root[data-page="lab"])      .nav-drawer a[data-nav="lab"],
:where(:root[data-page="talks"])    .nav-drawer a[data-nav="talks"],
:where(:root[data-page="contact"])  .nav-drawer a[data-nav="contact"]{color:var(--terracotta)}
.nav-drawer a:hover{color:var(--sage)}

/* ---- responsive bits ------------------------------------ */

/* Between the drawer breakpoint and ~1120px the bar's three columns stop
   fitting. The two nav groups need ~500px between them and the tagline alone is
   ~340px at 15px with .11em tracking, so past 1120px something has to give. The
   tagline is the decorative half of the wordmark and the links are the
   functional half, so the tagline is what goes — the full horizontal nav then
   survives all the way down to the drawer instead of the links wrapping into
   two-line stacks. */
@media (min-width:901px) and (max-width:1120px){
  .site-bar{padding:22px 32px;gap:24px}
  .site-bar .nav-l,.site-bar .nav-r{gap:18px}
  .site-bar .wordmark .b{display:none}
}

@media (max-width:900px){
  .site-bar{padding:22px 20px;grid-template-columns:1fr auto;gap:14px;text-align:left}
  .site-bar .wordmark{
    grid-column:1;justify-self:start;text-align:left;
  }
  .site-bar .nav-l,.site-bar .nav-r{display:none}
  /* Matches the 24px the page containers drop to at this breakpoint (see
     research.css and projects.css); at the base 56px the strip's first label
     started 32px right of the H1 underneath it. */
  .rs-toc ul{padding-left:24px;padding-right:24px}
  .bar-tools{display:flex;align-items:center;gap:10px;grid-column:2;justify-self:end}
  .bar-tools .theme-toggle{margin-left:0}
  .nav-toggle{display:block}
  .page,.page-narrow{padding:0 24px}
  .h-display{font-size:56px}
  .h-script{font-size:32px}
  h1.page-title{font-size:42px}
  /* Two columns, not one. The thumbnails are aspect-ratio:4/3, so a single
     full-width card just below the 3-up breakpoint renders an 850px card with a
     640px-tall image — larger than the same card at any other width. Dropping to
     one column only pays off once the column itself is narrow. */
  .card-grid{grid-template-columns:repeat(2, 1fr)}
  .plates{gap:18px;margin:32px auto 8px;flex-wrap:nowrap}
  .plate{width:auto;gap:6px;flex:0 1 auto;max-width:33%}
  .plate img{width:64px;height:64px}
  .plate .lbl{font-size:8px}
  .plate .lbl b{font-size:11px}
  .cols-2,.cols-2.thirds{grid-template-columns:1fr;gap:24px}
  .kv .row{grid-template-columns:1fr;gap:4px}
  .talks .item{grid-template-columns:1fr;gap:6px}
  .pub{grid-template-columns:1fr}
  .site-foot{grid-template-columns:1fr;gap:14px;text-align:center}
  .site-foot .l,.site-foot .r{justify-self:center}
}

/* Below this the two-column card grid leaves each card too narrow to read, and
   a single column is finally the smaller of the two. Must stay after the 900px
   block: same specificity, so source order decides. */
@media (max-width:620px){
  .card-grid{grid-template-columns:1fr}
}
