/* publications.css — REVISION-2 pass (Oct 2026). Loaded AFTER site.css and the shared redesign files in every
   page head; later rules win at equal specificity.
   Owner: Publications (REVISION-2 §R1, §R3, §R4, §R5 Publications, §R7 light only, §R11 two-tone cards,
   §R14 wide screens; DESIGN-SPEC §2.0 cascade, §7 ownership). Light theme only: nothing here reads html.dark (§R7).

   Every page links this file, so every rule is scoped to #pub-hero, .filter-bar or #pub-list (they exist only on
   publications.html). The cards use their own .pub-* classes (not .card / .editorial-row), so nothing here fights
   the §2.0 !important ledger and the file carries no !important at all.

   21st.dev patterns (scratchpad/inspiration/README.md + REVISION-2 §R3):
   - 24338 Neomorphism Metric Card — outer dual shadow + inset well: the cards, the pressed filter wells, the
     year groove and the current page.
   - 3176 Animated 3D Card (saved) — hover lift: translateY(-4px) + the deeper clay shadow, 320ms.
   - 8224 Gradient Card (saved) — tinted surfaces: the alternating blue (A) / gold (B) clay cards of §R11.
   - 2318 Squishy card — the press: scale(.98–.99) + inset shadow on pills, the toggle, and a card whose title
     link is being pressed.
   - 29425 Tabs with Count Badge (saved) — the "n papers" count chip beside the year numeral.
   - 28463 Search Bar with Category Filter — search, year and type as one joined control group in the clay bar. */


/* ---------------------------------------------------------------- 0. Local tokens
   The clay tokens live in type.css (REVISION-2 §R3, §R11). Each falls back to its light §R3/§R11 value, so the
   page renders the same whether or not the shared tokens have landed. The two tone surfaces are the exception:
   they read --clay-a / --clay-b with no fallback (§R11c), and only those surface tokens are consumed, so a
   shared token of another shape can never void a card's shadow stack. */
.filter-bar, #pub-list {
  --pub-clay: var(--clay, #F3F6FA);
  --pub-clay-blue: var(--clay-blue, #E6EEFB);
  --pub-well: var(--bg, #E8EDF5);
  --pub-radius: var(--clay-radius, 1.5rem);
  --pub-shadow: var(--clay-shadow,
    14px 14px 30px -6px rgb(23 42 82 / .17), -10px -10px 24px -6px rgb(255 255 255 / .95),
    inset 3px 3px 7px rgb(255 255 255 / .9), inset -5px -5px 12px rgb(23 42 82 / .07));
  --pub-shadow-hover: var(--clay-shadow-hover,
    22px 22px 44px -8px rgb(23 42 82 / .23), -12px -12px 28px -6px rgb(255 255 255 / 1),
    inset 3px 3px 7px rgb(255 255 255 / .95), inset -6px -6px 14px rgb(23 42 82 / .09));
  --pub-pressed: var(--clay-pressed, inset 6px 6px 12px rgb(23 42 82 / .14), inset -6px -6px 12px rgb(255 255 255 / .9));
  --pub-media-shadow: var(--clay-media-shadow, inset 0 0 0 1px rgb(255 255 255 / .35), 0 8px 18px -10px rgb(23 42 82 / .35));
  /* small raised pills (§R3 "Pills/chips") and a shallow pressed well */
  --pub-mini: var(--clay-chip-shadow, 3px 3px 6px rgb(23 42 82 / .12), -3px -3px 6px rgb(255 255 255 / .9));
  --pub-mini-hover: 5px 5px 10px rgb(23 42 82 / .16), -4px -4px 9px rgb(255 255 255 / .95);
  --pub-well-shadow: inset 3px 3px 6px rgb(23 42 82 / .13), inset -3px -3px 6px rgb(255 255 255 / .85);
  --pub-ink-strong: var(--ink-strong, #0C2340);
  --pub-accent: var(--accent-ink, #1D428A);
  --pub-ease: var(--ease-out, cubic-bezier(.2, .8, .2, 1));
  /* §R11 two-tone cards: light Marquette blue clay (A) / light gold clay (B). The surfaces come only from the
     type.css tokens (§R11c: no hard-coded tone hexes) and carry no top bar or inset accent (§R11b): the
     blue-vs-cream hue plus the clay shadow separate neighbours. Meta text on both tones uses the darker
     #4A5670 (6.6:1 on A #EDF3FC, 6.9:1 on B #FEF7E4; --ink-2 would be 5.5:1 / 5.7:1). */
  --pub-tone-a: var(--clay-a);
  --pub-tone-b: var(--clay-b);
  --pub-tone-ink-2: #4A5670;
  /* the current pager page: a pressed navy clay key (cards.css --clay-key-pressed) */
  --pub-navy: var(--clay-navy, #0B3466);
  --pub-navy-pressed: var(--clay-key-pressed,
    0 1px 1px rgb(0 20 50 / .2), inset 0 3px 7px rgb(0 0 0 / .45), inset 0 -1px 1px rgb(255 255 255 / .08));
}


/* ---------------------------------------------------------------- 1. Frame + hero
   §R14: the hero slab, the filter panel and the list share ONE frame at every width — the site container
   (--container-wide, site.css: min(94vw, 1920px)) centred, never closer to the page edge than --gutter. It is
   the type.css --page-inset token that .page-hero and the nav.css footer slab consume (the fallback repeats its
   expression), so all three edges land on the same pixel (2560 → 320px each side, 1920 → 57.6px, 1440 → 43.2px,
   1024 → 30.7px, 375 → 16px). The id rule out-specifies the shared .page-hero inset
   only to pin this page's slab to the frame; the slab skin, its title/lede/pills grid and the pill skin stay
   shared (type.css .page-hero, cards.css .page-hero .topic-pill). The two content wrappers drop site.css
   .container-standard's 1600px cap and 24px padding, which put the cards 24px inside the slab edge. */
#pub-hero.page-hero,
.filter-bar > .container-standard,
#pub-list {
  max-width: none;
  margin-inline: var(--page-inset, max(var(--gutter, 1rem), (100% - var(--container-wide, min(94vw, 1920px))) / 2));
}
.filter-bar > .container-standard,
#pub-list { padding-inline: 0; }


/* ---------------------------------------------------------------- 2. Filter bar
   The band stays sticky ≥ 768px (site.css 826 / 3588) but is transparent and borderless; the controls sit on one
   clay panel that floats over the cards like the nav capsule. The band ignores the pointer so the clear strips
   around the panel never swallow clicks meant for content scrolling beneath. No glass (§R3). */
.filter-bar {
  padding-block: .875rem .5rem;
  border: 0;
  background: transparent;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  pointer-events: none;
}
.filter-bar .filter-bar__panel {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .625rem 1.25rem;
  padding: .625rem;
  border-radius: 1.25rem;
  background: var(--pub-clay);
  box-shadow: var(--pub-shadow);
  pointer-events: auto;
}
.filter-bar .filter-bar__inner {
  flex: 1 1 38rem;
  min-width: 0;
  gap: .5rem;
  padding: 0;
}

/* Controls: the clay-well skin, its 3:1 control boundary (WCAG 1.4.11) and the focus halo are shared
   (type.css `.filter-bar :is(input, select)`); here only the hover edge, the open option sheet and the icons. */
.filter-bar .filter-bar__control {
  letter-spacing: 0;
  transition: border-color 200ms var(--pub-ease), box-shadow 200ms var(--pub-ease);
}
.filter-bar .filter-bar__control:hover:not(:focus) { border-color: color-mix(in oklab, var(--pub-accent) 60%, var(--line-ctl)); }
.filter-bar select.filter-bar__control option { background: var(--pub-clay); color: var(--ink); }
.filter-bar .filter-bar__icon { color: var(--ink-2); }

/* Result count: Host Grotesk tabular, at the right end of the panel row (wraps under the form when narrow). */
.filter-bar .filter-bar__count {
  flex: 0 1 auto;
  margin: 0 0 0 auto;
  padding: 0 .5rem;
  font: 500 .875rem/1.4 var(--font-sans);
  color: var(--ink-2);
  font-variant-numeric: lining-nums tabular-nums;
}
.filter-bar .filter-bar__count strong { font-weight: 700; color: var(--pub-ink-strong); }
.filter-bar .filter-bar__query { margin-left: .25rem; }
@media (max-width: 47.99em) {
  .filter-bar { padding-block: .75rem .25rem; }
  .filter-bar .filter-bar__count { margin-left: 0; }
}

/* Focus clearance (WCAG 2.4.11). ≥ 768px the bar sticks under the capsule (top --nav-h), so nav.css's
   nav-h + 1rem scroll-padding still lets Shift+Tab land on a card control hidden behind the bar. While focus
   is inside the list, pad past the bar's live height (publications.js publishes --pub-filter-h; the fallback
   is its two-row height). Specificity (1,1,1) beats nav.css `html:has(:focus-visible)`. */
@media (min-width: 48em) {
  html:has(#pub-list :focus-visible) {
    scroll-padding-top: calc(var(--nav-h, 66px) + var(--pub-filter-h, 7.25rem) + 1rem);
  }
}


/* ---------------------------------------------------------------- 3. List frame + year groups
   A year = one full-width heading line (Bricolage numeral, "n papers" chip, a pressed groove that runs to the
   edge) over a card grid. No sticky column, no rules, no indices (§R1, §R5). */
#pub-list {
  padding-block: clamp(1rem, .8rem + .8vw, 1.5rem) var(--section-py, clamp(2rem, 1.4rem + 2.4vw, 3.5rem));
}
#pub-list .pub-years { display: grid; row-gap: clamp(2rem, 1.6rem + 1.4vw, 2.75rem); }

#pub-list .pub-year__head {
  display: flex;
  align-items: center;
  gap: .875rem;
  margin: 0 0 1.125rem;
  padding: 0;
  border: 0;
}
#pub-list .pub-year__title {
  margin: 0;
  font: 700 clamp(1.75rem, 1.5rem + 1vw, 2.375rem)/1 var(--font-display);
  letter-spacing: -0.025em;
  color: var(--pub-ink-strong);
  font-variant-numeric: lining-nums tabular-nums;
}
#pub-list .pub-year__count {
  flex: none;
  display: inline-flex;
  align-items: center;
  min-height: 1.75rem;
  padding: .25rem .8rem;
  border-radius: 999px;
  background: var(--pub-clay-blue);
  box-shadow: var(--pub-mini);
  font: 600 .8125rem/1 var(--font-sans);
  color: var(--pub-accent);
  font-variant-numeric: lining-nums tabular-nums;
  white-space: nowrap;
}
#pub-list .pub-year__groove {
  flex: 1 1 auto;
  min-width: 1.5rem;
  height: .5rem;
  border-radius: 999px;
  box-shadow: var(--pub-well-shadow);
}

/* Grid: 1 column, 2 at ≥ 1024px, 3 at ≥ 1800px (§R14: a wider frame gets more columns, not stretched cards).
   The year head above it is a block outside the grid, so it always spans the whole frame.
   No row may hold a lone card or an empty cell, so the year's FIRST card (its newest paper) widens to absorb the
   remainder, decided in CSS from the year's card count (`:last-child:nth-child(…)` = count, so it holds after
   filtering and paging): 2 columns — an odd count spans the row; 3 columns — count 3n+1 spans the row, 3n+2
   spans two of the three. The <li> is a size container, so the card itself switches to its wide layout from
   its own width (section 4) wherever it ends up spanning.
   The grid carries .tone-alt (§R11); the <li> is only a layout wrapper, so whatever the shared alternation
   helper paints on it is cleared here and the tone is painted on the card inside it (section 4). */
#pub-list .pub-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1rem;
  margin: 0;
  padding: 0;
  list-style: none;
}
#pub-list .pub-grid > .pub-grid__item {
  display: flex;
  min-width: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
  container: pub-cell / inline-size;
}
@media (min-width: 48em) {
  #pub-list .pub-grid { gap: 1.25rem; }
}
@media (min-width: 64em) and (max-width: 112.49em) {
  #pub-list .pub-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  #pub-list .pub-grid:has(> :last-child:nth-child(odd)) > :first-child { grid-column: 1 / -1; }
}
@media (min-width: 112.5em) {
  #pub-list .pub-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  #pub-list .pub-grid:has(> :last-child:nth-child(3n+1)) > :first-child { grid-column: 1 / -1; }
  #pub-list .pub-grid:has(> :last-child:nth-child(3n+2)) > :first-child { grid-column: span 2; }
}


/* ---------------------------------------------------------------- 4. Card
   Borderless clay: a tinted surface, outer dual shadow + inner highlight/shade. Hover lifts (3176); pressing the
   title link presses the card (2318). All motion and shadow steps are guarded (§2.0 rule 6).
   §R11: cards alternate blue clay (A, odd) / gold clay (B, even) card by card within each year grid, keyed on
   the <li>'s :nth-child so it holds after filtering and paging (one column); at 1024–1799px the two-column grid
   turns that into a checkerboard so cards stacked in one column never share a tone either. Three columns (an odd
   count) need no remap: plain odd/even already reads A B A / B A B, with or without a two- or three-wide lead
   (the lead is always item 1, so the single cards after it keep a checkerboard). No top bar, no inset
   accent (§R11b): the tone surface and the plain clay stack alone. Chips and buttons inside sit on white clay
   (never gold-on-gold), and meta text darkens to --pub-tone-ink-2. */
#pub-list .pub-card {
  --pub-pad-y: var(--card-pad, clamp(1.125rem, 1rem + .6vw, 1.5rem));
  --pub-pad-x: calc(var(--pub-pad-y) + .25rem);
  --pub-clamp: 3;
  --pub-surface: var(--pub-clay);
  --pub-meta: var(--ink-2);
  --pub-chip-bg: var(--pub-clay);
  position: relative;
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-width: 0;
  padding: var(--pub-pad-y) var(--pub-pad-x);
  border: 0;
  border-radius: var(--pub-radius);
  background: var(--pub-surface);
  box-shadow: var(--pub-shadow);
  color: var(--ink);
  transition: transform 320ms var(--pub-ease), box-shadow 320ms var(--pub-ease);
}
#pub-list .tone-alt > :nth-child(odd) > .pub-card {
  --pub-surface: var(--pub-tone-a);
  --pub-meta: var(--pub-tone-ink-2);
  --pub-chip-bg: #FFFFFF;
}
#pub-list .tone-alt > :nth-child(even) > .pub-card {
  --pub-surface: var(--pub-tone-b);
  --pub-meta: var(--pub-tone-ink-2);
  --pub-chip-bg: #FFFFFF;
}
/* Two columns (1024–1799px): plain odd/even would paint vertical stripes (each column one tone), so the order
   flips every second row into a checkerboard — A B / B A for an even count; A(wide), B A / A B for an odd one
   (its rows start one item later). Neighbours across a row and down a column then always differ. */
@media (min-width: 64em) and (max-width: 112.49em) {
  #pub-list .tone-alt:has(> :last-child:nth-child(even)) > :nth-child(4n+3) > .pub-card { --pub-surface: var(--pub-tone-b); }
  #pub-list .tone-alt:has(> :last-child:nth-child(even)) > :nth-child(4n+4) > .pub-card { --pub-surface: var(--pub-tone-a); }
  #pub-list .tone-alt:has(> :last-child:nth-child(odd)) > :nth-child(4n+4) > .pub-card { --pub-surface: var(--pub-tone-a); }
  #pub-list .tone-alt:has(> :last-child:nth-child(odd)) > :nth-child(4n+5) > .pub-card { --pub-surface: var(--pub-tone-b); }
}
@media (prefers-reduced-motion: no-preference) {
  #pub-list .pub-card:hover { transform: translateY(-4px); box-shadow: var(--pub-shadow-hover); }
  #pub-list .pub-card:has(.pub-card__link:active) {
    transform: translateY(0) scale(.99);
    box-shadow: var(--pub-pressed);
  }
}

/* Figure (none in the data today): inset 10px from the card edge, 16:10, its own radius and media shadow. */
#pub-list .pub-card__media {
  aspect-ratio: 16 / 10;
  margin: calc(.625rem - var(--pub-pad-y)) calc(.625rem - var(--pub-pad-x)) 1rem;
  overflow: hidden;
  border-radius: 1rem;
  box-shadow: var(--pub-media-shadow);
  background: var(--pub-well);
}
#pub-list .pub-card__media > img { display: block; width: 100%; height: 100%; object-fit: cover; }

/* Title — Bricolage 600 (--font-display), navy-cast ink; the link turns accent with its underline on card hover. */
#pub-list .pub-card__title {
  margin: 0;
  font: 600 clamp(1.0625rem, 1rem + .3vw, 1.25rem)/1.3 var(--font-display);
  letter-spacing: -0.012em;
  color: var(--pub-ink-strong);
  text-wrap: pretty;
  overflow-wrap: break-word;
  hyphens: manual;
  -webkit-hyphens: manual;
}
#pub-list .pub-card__link {
  color: inherit;
  text-decoration: underline;
  text-decoration-color: transparent;
  text-decoration-thickness: 1.5px;
  text-underline-offset: .2em;
  transition: color 220ms var(--pub-ease), text-decoration-color 220ms var(--pub-ease);
}
#pub-list .pub-card:hover .pub-card__link,
#pub-list .pub-card__link:focus-visible { color: var(--pub-accent); text-decoration-color: currentColor; }
#pub-list .pub-card__link:focus-visible { outline: 2px solid var(--pub-accent); outline-offset: 3px; border-radius: .25rem; }
#pub-list .pub-arrow {
  display: inline;
  width: .72em;
  height: .72em;
  margin-left: .3em;
  vertical-align: .02em;
  color: var(--pub-meta);
  transition: color 220ms var(--pub-ease), transform 220ms var(--pub-ease);
}
#pub-list .pub-card:hover .pub-card__link .pub-arrow { color: currentColor; }
#pub-list .pub-nowrap { white-space: nowrap; }   /* last title word + arrow (publications.js withArrow) */
@media (prefers-reduced-motion: no-preference) {
  #pub-list :is(.pub-card__link, .pub-btn):is(:hover, :focus-visible) .pub-arrow { transform: translate(2px, -2px); }
}

/* Authors — Host Grotesk meta; the director's name bold in heading ink. */
#pub-list .pub-card__authors {
  margin: .5rem 0 0;
  font: 400 .875rem/1.5 var(--font-sans);
  color: var(--pub-meta);
}
#pub-list .pub-card__authors strong { font-weight: 650; color: var(--pub-ink-strong); }

/* Chips — small raised clay pills; white clay inside a tone card (§R11), accent ink for the type. */
#pub-list .pub-card__chips {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem;
  margin: .75rem 0 0;
  padding: 0;
  list-style: none;
}
#pub-list .pub-chip {
  display: inline-flex;
  align-items: center;
  min-height: 1.625rem;
  padding: .25rem .7rem;
  border-radius: 999px;
  background: var(--pub-chip-bg);
  box-shadow: var(--pub-mini);
  font: 600 .75rem/1.2 var(--font-sans);
  letter-spacing: .01em;
  color: var(--pub-meta);
}
#pub-list .pub-chip--type { color: var(--pub-accent); }

/* Abstract — body ink, clamped to three lines until the card opens (publications.js toggles .is-open). */
#pub-list .pub-card__abstract {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: var(--pub-clamp);
  line-clamp: var(--pub-clamp);
  overflow: hidden;
  max-width: 72ch;
  margin: .875rem 0 0;
  font: 400 .9375rem/1.6 var(--font-sans);
  color: var(--ink);
}
#pub-list .pub-card.is-open .pub-card__abstract {
  display: block;
  -webkit-line-clamp: unset;
  line-clamp: none;
  overflow: visible;
}

/* Foot — toggle left, actions right, pinned to the card bottom so paired cards line their actions up. */
#pub-list .pub-card__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: .5rem .75rem;
  margin-top: auto;
  padding-top: 1rem;
}
#pub-list .pub-card__foot:not(:has(> :not([hidden]))) { display: none; }
#pub-list .pub-card__toggle {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  min-height: 2.25rem;
  margin-left: -.75rem;
  padding: .35rem .75rem;
  border: 0;
  border-radius: 999px;
  background: transparent;
  box-shadow: none;
  font: 600 .8125rem/1 var(--font-sans);
  color: var(--pub-accent);
  cursor: pointer;
  transition: box-shadow 200ms var(--pub-ease), background-color 200ms var(--pub-ease);
}
#pub-list .pub-card__toggle[hidden] { display: none; }
#pub-list .pub-card__toggle:hover { background: var(--pub-chip-bg); box-shadow: var(--pub-mini); }
#pub-list .pub-card__toggle:active { box-shadow: var(--pub-pressed); }
#pub-list .pub-card__chev { width: 1rem; height: 1rem; transition: transform 220ms var(--pub-ease); }
#pub-list .pub-card__toggle[aria-expanded="true"] .pub-card__chev { transform: rotate(180deg); }

#pub-list .pub-card__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem;
  margin: 0 0 0 auto;
  padding: 0;
  list-style: none;
}
#pub-list .pub-btn {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  min-height: 2.25rem;
  padding: .35rem 1rem;
  border: 0;
  border-radius: 999px;
  background: var(--pub-chip-bg);
  box-shadow: var(--pub-mini);
  font: 600 .8125rem/1 var(--font-sans);
  color: var(--pub-accent);
  text-decoration: none;
  white-space: nowrap;
  transition: box-shadow 200ms var(--pub-ease), transform 200ms var(--pub-ease), color 200ms var(--pub-ease);
}
#pub-list .pub-btn .pub-arrow { margin-left: .1em; color: currentColor; }
#pub-list .pub-btn--quiet,
#pub-list .pub-btn--project { color: var(--pub-meta); font-weight: 500; }
#pub-list .pub-btn--project { white-space: normal; text-align: left; line-height: 1.25; }
#pub-list .pub-btn:hover { color: var(--pub-ink-strong); }
#pub-list :is(.pub-btn, .pub-card__toggle):focus-visible { outline: 2px solid var(--pub-accent); outline-offset: 2px; }
/* Tap targets: both pills are 36px tall to keep the foot compact; an invisible ::after grows the hit area to
   44px (4px above and below, 2px each side: half the .5rem gaps, so neighbours never overlap), the same
   pattern as people.css .roster-card__link. */
#pub-list :is(.pub-btn, .pub-card__toggle) { position: relative; }
#pub-list :is(.pub-btn, .pub-card__toggle)::after {
  content: "";
  position: absolute;
  inset: -4px -2px;
  border-radius: inherit;
}
@media (prefers-reduced-motion: no-preference) {
  #pub-list .pub-btn:hover { transform: translateY(-1px); box-shadow: var(--pub-mini-hover); }
  #pub-list .pub-btn:active { transform: scale(.98); box-shadow: var(--pub-pressed); }
}

/* Phones: a little less side padding so "Read full abstract" and "View paper" share one line (297px column). */
@media (max-width: 29.99em) {
  #pub-list .pub-card { --pub-pad-x: var(--pub-pad-y); }
  #pub-list .pub-card__foot { column-gap: .5rem; }
  #pub-list .pub-card__toggle { margin-left: -.6rem; padding-inline: .6rem; }
  #pub-list .pub-btn { padding-inline: .85rem; }
}

/* Wide lead (≥ 1024px): title block left, abstract right (five lines), foot across. Keyed on the card's own
   width through its pub-cell container (section 3), so it applies to exactly the lead that spans a row or two of
   three columns. 56rem (896px) sits between the widest single cell (836px, two columns at 1799px) and the
   narrowest spanning cell (963px, a full row at 1024px). The lead is the year's first card, so it takes tone A. */
@media (min-width: 64em) {
  @container pub-cell (min-width: 56rem) {
    #pub-list .pub-card {
      --pub-clamp: 5;
      display: grid;
      grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr);
      grid-template-rows: auto auto auto 1fr auto;
      grid-template-areas:
        "media   abstract"
        "title   abstract"
        "authors abstract"
        "chips   abstract"
        "foot    foot";
      column-gap: clamp(2rem, 1rem + 2vw, 3rem);
    }
    #pub-list .pub-card > .pub-card__media { grid-area: media; margin-right: 0; }
    #pub-list .pub-card > .pub-card__title { grid-area: title; }
    #pub-list .pub-card > .pub-card__authors { grid-area: authors; }
    #pub-list .pub-card > .pub-card__chips { grid-area: chips; align-self: start; }
    #pub-list .pub-card > .pub-card__abstract { grid-area: abstract; align-self: start; margin-top: .125rem; }
    #pub-list .pub-card > .pub-card__foot { grid-area: foot; }
  }
  /* A full row at ≥ 1600px: the abstract column stops at its reading measure (72ch at 15px ≈ 700px) and the
     title block takes the rest, so neither column ends in a wide empty strip. */
  @container pub-cell (min-width: 100rem) {
    #pub-list .pub-card { grid-template-columns: minmax(0, 1fr) minmax(0, 46rem); }
  }
}
/* A two-of-three lead shares its row with a single card whose abstract sits under its title, so that row runs
   taller than the lead's five lines need; the lead shows more of its abstract instead of an empty band. */
@media (min-width: 112.5em) {
  #pub-list .pub-grid:has(> :last-child:nth-child(3n+2)) > :first-child > .pub-card { --pub-clamp: 8; }
}


/* ---------------------------------------------------------------- 5. Pagination
   blog.css styles both editorial pagers (news + this list); here the #pub-list version at the same (1,x,x)
   specificity, later file: raised clay pills, and the current page as a pressed NAVY key with white numerals
   (12.4:1 text, 11.4:1 fill against its clay siblings), so the state never rests on a shadow alone.
   publications.js tags the page links outside current ±1 (and last) .pagination__far and adds a narrow "…"
   (.pagination__gap--narrow) where those are skipped; phones show only that compact set (section 5b). */
#pub-list .pagination--editorial {
  gap: .5rem;
  margin-top: 2.25rem;
  font: 600 .875rem/1 var(--font-sans);
  font-variant-numeric: lining-nums tabular-nums;
}
#pub-list .pagination--editorial .pagination__gap--narrow { display: none; }
#pub-list .pagination--editorial a,
#pub-list .pagination--editorial .pagination__nav {
  border: 0;
  border-radius: 999px;
  background: var(--pub-clay);
  box-shadow: var(--pub-mini);
  color: var(--pub-ink-strong);
  font: inherit;
  transition: box-shadow 200ms var(--pub-ease), color 200ms var(--pub-ease), transform 200ms var(--pub-ease);
}
#pub-list .pagination--editorial a:hover { background: var(--pub-clay); border-color: transparent; color: var(--pub-accent); }
#pub-list .pagination--editorial [aria-current="page"] {
  border-radius: 999px;
  background: var(--pub-navy);
  box-shadow: var(--pub-navy-pressed);
  color: #FFFFFF;
  font-weight: 700;
}
#pub-list .pagination--editorial [aria-disabled="true"] { box-shadow: none; background: transparent; }
@media (prefers-reduced-motion: no-preference) {
  #pub-list .pagination--editorial a:hover { transform: translateY(-1px); box-shadow: var(--pub-mini-hover); }
  #pub-list .pagination--editorial a:active { transform: scale(.97); box-shadow: var(--pub-pressed); }
}

/* 5a. Tablets and touch screens: 44px keys (WCAG 2.5.8 comfort target), same as the news pager. */
@media (max-width: 1023.98px), (pointer: coarse) {
  #pub-list .pagination--editorial :is(a, [aria-current="page"], .pagination__nav) { min-width: 2.75rem; height: 2.75rem; }
}

/* 5b. Phones (< 640px): one row that never wraps, 44px tap targets, and only prev · current ±1 · last · next
   (far links hidden, narrow "…" shown). Prev/next are chevron-only below 480px (blog.css keeps their words for
   screen readers). */
@media (max-width: 39.99em) {
  #pub-list .pagination--editorial { flex-wrap: nowrap; gap: .25rem; }
  #pub-list .pagination--editorial :is(a, [aria-current="page"], .pagination__nav) {
    min-width: 2.75rem;
    height: 2.75rem;
    padding-inline: .6rem;
  }
  #pub-list .pagination--editorial :is(.pagination__far, .pagination__gap--wide) { display: none; }
  #pub-list .pagination--editorial .pagination__gap--narrow {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.25rem;
    height: 2.75rem;
    padding-inline: 0;
  }
}


/* ---------------------------------------------------------------- 6. Footnote + empty state */
#pub-list .pub-footnote {
  max-width: 40rem;
  margin: 2.25rem auto 0;
  text-align: center;
  font: 400 .875rem/1.55 var(--font-sans);
  color: var(--ink-2);
}
#pub-list .pub-footnote a {
  font-weight: 600;
  color: var(--pub-accent);
  text-decoration: underline;
  text-decoration-color: color-mix(in oklab, currentColor 35%, transparent);
  text-underline-offset: .2em;
}
#pub-list .pub-footnote a:hover { text-decoration-color: currentColor; }

/* Empty state — one clay panel with an inset icon well (24338). */
#pub-list .pub-empty {
  max-width: 40rem;
  margin: 1rem auto 0;
  padding: clamp(2rem, 1.6rem + 2vw, 3rem) clamp(1.25rem, 1rem + 2vw, 2.5rem);
  border-radius: var(--pub-radius);
  background: var(--pub-clay);
  box-shadow: var(--pub-shadow);
  text-align: center;
}
#pub-list .pub-empty__icon {
  display: grid;
  place-items: center;
  width: 3.5rem;
  height: 3.5rem;
  margin: 0 auto 1rem;
  border-radius: 1.125rem;
  background: var(--pub-well);
  box-shadow: var(--pub-well-shadow);
  color: var(--pub-accent);
}
#pub-list .pub-empty__title {
  margin: 0;
  font: 650 clamp(1.375rem, 1.25rem + .6vw, 1.75rem)/1.2 var(--font-display);
  letter-spacing: -0.02em;
  color: var(--pub-ink-strong);
  text-wrap: balance;
}
#pub-list .pub-empty__text {
  max-width: 28rem;
  margin: .5rem auto 0;
  font: 400 .9375rem/1.55 var(--font-sans);
  color: var(--ink-2);
}
#pub-list .pub-empty__cta { margin-top: 1.5rem; }


/* ---------------------------------------------------------------- 7. Forced colors
   Shadows and tinted fills drop out in forced-colors mode, so the clay surfaces get a system-colour edge back
   and the current pager page an outline it can be told apart by. */
@media (forced-colors: active) {
  #pub-list :is(.pub-card, .pub-chip, .pub-btn, .pub-year__count, .pub-empty, .pagination--editorial a),
  .filter-bar .filter-bar__panel {
    border: 1px solid CanvasText;
  }
  #pub-list .pagination--editorial [aria-current="page"] {
    border: 1px solid CanvasText;
    outline: 2px solid Highlight;
    outline-offset: 2px;
  }
  #pub-list .pub-year__groove { border: 1px solid GrayText; }
}
