/* Benoît Frydman — main stylesheet.
   Native-first: color-scheme + light-dark() drive theming with zero JS;
   the optional JS theme toggle only sets color-scheme explicitly via
   [data-theme]. Publication filtering is pure CSS (:has()). */

:root {
  color-scheme: light dark;

  --font-serif: ui-serif, Georgia, "Iowan Old Style", "Palatino Linotype",
    "URW Palladio L", P052, serif;
  --font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
    Helvetica, Arial, sans-serif;

  --bg: light-dark(#faf8f4, #16150f);
  --bg-elevated: light-dark(#ffffff, #1d1c16);
  --fg: light-dark(#1c1a15, #eae7de);
  --fg-muted: light-dark(#5b5648, #b3ad9d);
  --border: light-dark(#ddd6c7, #38352a);
  --accent: light-dark(#3c4f7a, #9bb0dd);
  --accent-contrast: light-dark(#ffffff, #10131c);
  --shadow: light-dark(rgba(28, 26, 21, 0.08), rgba(0, 0, 0, 0.4));

  /* Reserved for unpublished works — the one thing in the corpus that
     exists nowhere else. Deliberately the only warm accent on the site. */
  /* Confirmation only ("Copied!") — never load-bearing on its own. */
  --ok: light-dark(#2f6b45, #7fc79b);

  --rare: light-dark(#8a5c0a, #e0b45c);
  --rare-bg: light-dark(#fdf5e4, #251d0d);
  --rare-contrast: light-dark(#ffffff, #201a09);

  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 1rem;
  --space-4: 1.5rem;
  --space-5: 2.5rem;
  --space-6: 4rem;

  --content-width: 46rem;
  --radius: 4px;
}

:root[data-theme="light"] {
  color-scheme: light;
}
:root[data-theme="dark"] {
  color-scheme: dark;
}

* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-sans);
  font-size: 1.0625rem;
  line-height: 1.65;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
}

h1,
h2,
h3 {
  font-family: var(--font-serif);
  font-weight: 600;
  line-height: 1.2;
  color: var(--fg);
}

h1 {
  font-size: clamp(1.9rem, 4vw, 2.75rem);
  margin: 0 0 var(--space-2);
}

h2 {
  font-size: clamp(1.4rem, 3vw, 1.9rem);
  margin: 0 0 var(--space-3);
  padding-bottom: var(--space-2);
  border-bottom: 1px solid var(--border);
}

p {
  margin: 0 0 var(--space-3);
}

a {
  color: var(--accent);
  text-decoration-thickness: from-font;
  text-underline-offset: 0.15em;
}

a:hover {
  text-decoration-thickness: 2px;
}

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

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

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  background: var(--bg-elevated);
  color: var(--fg);
  padding: 0.75em 1.25em;
  border-radius: 0 0 var(--radius) 0;
  box-shadow: 0 2px 8px var(--shadow);
}

.skip-link:focus {
  left: 0;
}

/* ---------- Header ---------- */

.site-header {
  border-bottom: 1px solid var(--border);
  background: var(--bg-elevated);
}

/* Column by default, one row only above HEADER_ROW_BREAKPOINT (960px) —
   a fixed viewport-width switch rather than organic flex-wrap. Wrapping
   driven by content width breaks at a different point per language
   (French labels and aria-strings aren't the same length as their
   English counterparts), so the header could legitimately show one row
   on /en/ and two on /fr/ at the identical viewport width — not a markup
   bug (the two are structurally identical, see CLAUDE.md), just content
   length. A width-only breakpoint means both languages always switch
   layout at exactly the same place. */
.header-inner {
  max-width: 64rem;
  margin: 0 auto;
  padding: var(--space-3) var(--space-4);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-3);
}

.site-identity {
  margin: 0;
  display: flex;
  flex-direction: column;
  line-height: 1.3;
}

.site-name-link {
  text-decoration: none;
  color: inherit;
}

.site-name {
  font-family: var(--font-serif);
  font-weight: 600;
  font-size: 1.15rem;
  color: var(--fg);
}

.site-role {
  font-size: 0.85rem;
  color: var(--fg-muted);
}

.site-nav ul {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin: 0;
  padding: 0;
}

.site-nav a {
  color: var(--fg);
  font-size: 0.95rem;
  text-decoration: none;
  border-bottom: 1px solid transparent;
}

.site-nav a:hover {
  border-bottom-color: var(--accent);
}

.header-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
}

@media (min-width: 960px) {
  .header-inner {
    flex-direction: row;
    align-items: center;
    gap: var(--space-3) var(--space-4);
  }

  .site-identity {
    flex: 1 1 14rem;
  }

  .header-controls {
    flex-wrap: nowrap;
    margin-left: auto;
  }
}

a.lang-toggle {
  font-size: 0.85rem;
  text-decoration: none;
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 0.3em 0.9em;
  color: var(--fg);
}

a.lang-toggle:hover {
  border-color: var(--accent);
  color: var(--accent);
}

/* JS-injected theme toggle (progressive enhancement; empty + invisible
   without JS, so it takes no visual space when absent). */
.theme-toggle-slot:empty {
  display: none;
}

.theme-toggle {
  display: inline-flex;
  border: 1px solid var(--border);
  border-radius: 999px;
  overflow: hidden;
}

.theme-toggle button {
  font: inherit;
  font-size: 0.8rem;
  border: 0;
  background: transparent;
  color: var(--fg-muted);
  padding: 0.3em 0.7em;
  cursor: pointer;
}

.theme-toggle button[aria-pressed="true"] {
  background: var(--accent);
  color: var(--accent-contrast);
}

/* ---------- Layout ---------- */

main {
  container-type: inline-size;
  container-name: page;
  max-width: 64rem;
  margin: 0 auto;
  padding: 0 var(--space-4);
}

section {
  padding: var(--space-6) 0;
  border-bottom: 1px solid var(--border);
}

main > section:last-of-type,
/* Work-page sections sit inside <article class="work">, one level deeper
   than the rule above reaches, so the last one kept its bottom border
   with nothing to divide it from — this covers that nesting too. */
.work > section:last-of-type {
  border-bottom: 0;
}

/* ---------- Compact "supporting" sections (work page) ----------
   Tags, citations and related works follow the primary content (access,
   abstract) and don't need the same 4rem of padding or a full-size h2 to
   make their point — added 2026-07-30 when the four expanded citation
   formats made every work page much longer below the summary than above
   it. */
.section-tight {
  padding: var(--space-4) 0;
}

.section-tight > h2,
.work-tag-group > h2,
.hero-fields > h2 {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--fg-muted);
  border-bottom: 0;
  padding-bottom: 0;
  margin: 0 0 var(--space-2);
}

.work-tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4) var(--space-5);
}

.work-tag-group {
  flex: 1 1 16rem;
  min-width: 0;
}

.work-tag-group .tag-list {
  margin-bottom: 0;
}

.section-intro {
  color: var(--fg-muted);
  max-width: var(--content-width);
}

/* ---------- Hero ---------- */

.hero {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  align-items: flex-start;
}

.hero-portrait {
  width: min(320px, 100%);
  flex-shrink: 0;
}

.hero-portrait picture,
.hero-portrait img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius);
  box-shadow: 0 8px 30px var(--shadow);
}

/* The "contact by email" pill directly under the portrait (2026-08-05),
   same rescaled treatment as the work page's own contact button
   (.work-contact-compact .btn) — see render_portrait_contact_button(). */
.hero-portrait-contact {
  margin-top: var(--space-2);
}

.hero-bio {
  max-width: var(--content-width);
}

.hero-fields {
  max-width: var(--content-width);
  margin-top: var(--space-3);
}

.hero-more {
  margin-top: var(--space-2);
  font-size: 0.95rem;
}

@container page (min-width: 640px) {
  .hero {
    flex-direction: row;
  }
}

/* ---------- How-to-use box (home page) ----------
   A collapsible callout between the shortened intro and the corpus tool —
   deliberately high-visibility (full border + left accent stripe + its own
   elevated surface, on top of the section's default padding) rather than a
   plain <details>, since a first-time visitor lands straight on a
   searchable database with no other orientation. Open by default; a
   returning visitor can collapse it. */
.howto-section {
  padding-top: var(--space-2);
  padding-bottom: var(--space-2);
}

/* Deliberately unboxed (2026-08-05, reversing the earlier "styled as a
   bordered/tinted card so it doesn't read as just another disclosure
   widget" choice) — the user asked for less visual weight here so the
   publications list sits higher on the page without scrolling. A plain
   <details>, same footprint as any other disclosure on the site. */
.howto {
  padding: 0;
}

.howto > summary {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  cursor: pointer;
  list-style: none;
  font-size: 0.95rem;
  color: var(--fg-muted);
}

.howto > summary::-webkit-details-marker {
  display: none;
}

.howto > summary .i {
  color: var(--fg-muted);
}

.howto > summary::after {
  content: "▾";
  margin-left: auto;
  font-size: 0.8em;
  opacity: 0.6;
}

.howto[open] > summary::after {
  content: "▴";
}

.howto-body {
  margin-top: var(--space-3);
}

.howto-intro {
  color: var(--fg-muted);
}

.howto-steps {
  margin: 0;
  padding-left: 1.15em;
}

.howto-steps li {
  margin-bottom: var(--space-2);
}

.howto-steps li:last-child {
  margin-bottom: 0;
}

.howto-steps a {
  font-weight: 600;
}

/* A distinct closing note, not a fifth numbered step — a caveat about
   locally-hosted copies (PDF backups, Markdown editions) rather than an
   instruction, so it reads as an aside instead of another thing to do. */
.howto-caveat {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  margin-top: var(--space-3);
  padding-top: var(--space-3);
  border-top: 1px solid var(--border);
  font-size: 0.85rem;
  font-style: italic;
  color: var(--fg-muted);
}

.howto-caveat .i {
  flex-shrink: 0;
  margin-top: 0.2em;
}

/* ---------- Icons ----------
   One hidden sprite per page; every icon is a <use> into it, sized here
   rather than per instance so the same symbol serves a 20px header link
   and a 16px in-button glyph. */

.icon-sprite {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

.i {
  width: 1.05em;
  height: 1.05em;
  flex: none;
  vertical-align: -0.15em;
  /* A <use> clones its target into a shadow tree whose inheritance comes
     from the <use> element itself, not from the <symbol>'s original
     <svg class="icon-sprite"> ancestor — so fill/stroke set there never
     reach an instance rendered elsewhere on the page. Declaring the line-
     icon defaults here, on the class every instance actually carries, is
     what makes them inherit correctly. The two filled marks (LinkedIn, X)
     are unaffected either way: they set fill/stroke directly on their own
     <path>/<rect>, which always wins over an inherited value. */
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* ---------- Buttons ----------
   Anything that performs an action — open a record, download a PDF,
   copy a citation — looks the same whether it is an <a> or a <button>. */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
  padding: 0.4em 0.9em;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-elevated);
  color: var(--fg);
  font: inherit;
  font-size: 0.88rem;
  line-height: 1.4;
  text-decoration: none;
  cursor: pointer;
}

.btn:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.btn-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-contrast);
  font-weight: 600;
}

.btn-primary:hover {
  background: var(--accent);
  color: var(--accent-contrast);
  filter: brightness(1.1);
}

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: 0 0 var(--space-2);
}

.btn.is-copied {
  border-color: var(--ok);
  color: var(--ok);
}

/* ---------- Publications / corpus: shared list component ---------- */

.corpus-cta {
  font-size: 0.95rem;
}

.corpus-cta a {
  font-weight: 600;
}

.pub-search-slot {
  flex: 1 1 15rem;
  max-width: 24rem;
  margin: 0;
}

.pub-search-slot input[type="search"] {
  width: 100%;
  font: inherit;
  font-size: 0.9rem;
  padding: 0.45em 0.9em;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-elevated);
  color: var(--fg);
}

/* ---------- Home page: 4 headline category buttons ----------
   A much lighter toolbar than the corpus page's own facet dropdowns: just
   these 4 big buttons and a prominent search box. The buttons are
   checkboxes, not radios (render_home_category_style() generates the
   matching CSS in build.py), so more than one can be active at once. */

.pub-toolbar-home {
  margin: var(--space-3) 0 var(--space-2);
}

.hc-buttons {
  display: grid;
  /* A grid, not a wrapping flex row: with exactly 4 items, flex-wrap always
     has some viewport width where 3 fit on a line and the 4th stretches out
     alone underneath. Grid steps deterministically between a 2x2 layout and
     a single row of 4, with no in-between odd state. */
  grid-template-columns: repeat(2, 1fr);
  width: 100%; /* a <fieldset>, even as a grid container, still shrink-wraps
    to its content's width in every browser tested — this is the one
    declaration that actually makes it span the full section width. */
  gap: var(--space-2);
  border: 0;
  margin: 0;
  padding: 0;
}

/* Placed right after the base rule (not in the header's consolidated
   min-width:960px block near the top of the file) so it wins the cascade:
   with equal specificity, source order decides, and a desktop override
   declared before the rule it overrides silently loses to it. */
@media (min-width: 960px) {
  .hc-buttons {
    grid-template-columns: repeat(4, 1fr);
  }
}

.hc-btn input {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.hc-btn label {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.4em;
  height: 100%;
  padding: var(--space-4) var(--space-3);
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--bg-elevated);
  cursor: pointer;
  text-align: center;
  user-select: none;
  transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}

.hc-btn label:hover {
  border-color: var(--accent);
  color: var(--accent);
  box-shadow: 0 4px 14px var(--shadow);
  transform: translateY(-1px);
}

/* A thin inset rule, the sober version of an old book cover's ruled
   border — shared by all four buttons, so each reads as a small plate
   rather than a flat card. */
.hc-btn label::before {
  content: "";
  position: absolute;
  inset: 5px;
  border: 1px solid var(--border);
  border-radius: 6px;
  opacity: 0.5;
  pointer-events: none;
}

.hc-btn input:checked + label::before {
  border-color: var(--accent-contrast);
  opacity: 0.35;
}

.hc-label {
  font-family: var(--font-serif);
  font-size: 1.3rem;
  font-weight: 600;
  letter-spacing: 0.01em;
}

.hc-count {
  font-size: 0.78rem;
  padding: 0.05em 0.7em;
  border-radius: 999px;
  background: var(--bg);
  color: var(--fg-muted);
  font-variant-numeric: tabular-nums;
}

.hc-btn input:checked + label {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-contrast);
  box-shadow: 0 4px 14px var(--shadow);
}

.hc-btn input:checked + label .hc-count {
  background: var(--accent-contrast);
  color: var(--accent);
  opacity: 0.9;
}

.hc-btn input:focus-visible + label {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.pub-search-slot-hero {
  margin: var(--space-3) 0 0;
  max-width: 34rem;
}

.pub-search-slot-hero input[type="search"] {
  width: 100%;
  font-size: 1.15rem;
  padding: 0.75em 1.1em;
}

/* The whole control strip is one wrapping row: search box, one dropdown
   per facet, the unpublished toggle, reset. It used to be five stacked
   fieldsets with every value visible at once, which pushed the list
   itself below the fold. */
/* Machine-readable copies of the corpus — moved up under the page intro
   (2026-08-04) so it reads as the treasure it is rather than a footnote
   below the search tool, and styled as an accent-bordered card, same
   language as the home page's how-to box. Links are real .btn pills with
   an icon each rather than a bare text list. */
.exports {
  margin: var(--space-4) 0 0;
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--accent);
  border-radius: var(--radius);
  background: var(--bg-elevated);
  box-shadow: inset 3px 0 0 var(--accent), 0 2px 10px var(--shadow);
}

.exports-label {
  margin: 0 0 var(--space-2);
  font-family: var(--font-serif);
  font-weight: 600;
  font-size: 1.05rem;
}

.exports-links {
  margin: 0;
}

.corpus-toolbar {
  margin-bottom: var(--space-3);
}

.pub-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin: var(--space-2) 0 0;
}

.chip-group {
  border: 0;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

.chip {
  display: inline-flex;
}

.chip input {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.chip label {
  display: inline-flex;
  align-items: baseline;
  gap: 0.4em;
  padding: 0.3em 0.85em;
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: 0.85rem;
  cursor: pointer;
  user-select: none;
}

.chip input:checked + label {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-contrast);
}

.chip input:focus-visible + label {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.chip-count {
  font-size: 0.78em;
  font-variant-numeric: tabular-nums;
  opacity: 0.65;
}

/* ---------- Facet dropdowns ----------
   A native <details> per facet, sharing name="facets" so opening one
   closes the others. The panel is absolutely positioned so opening a
   facet doesn't shove the list down the page. */

.facet {
  position: relative;
}

.facet > summary {
  display: inline-flex;
  align-items: baseline;
  gap: 0.35em;
  padding: 0.35em 0.85em;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-elevated);
  font-size: 0.85rem;
  cursor: pointer;
  list-style: none;
  user-select: none;
}

.facet > summary::-webkit-details-marker {
  display: none;
}

.facet > summary::after {
  content: "▾";
  font-size: 0.8em;
  opacity: 0.6;
}

.facet[open] > summary,
.facet > summary:hover {
  border-color: var(--accent);
  color: var(--accent);
}

/* The active value is written in by the generated CSS (one content:
   rule per option), so a closed dropdown still says what it filters. */
.facet-value::after {
  color: var(--accent);
  font-weight: 600;
}

.facet:has(input:not([id$="-all"]):checked) .facet-value::before {
  content: "·";
  margin-right: 0.35em;
  opacity: 0.5;
}

.facet:has(input:not([id$="-all"]):checked) > summary {
  border-color: var(--accent);
}

.facet-menu {
  position: absolute;
  z-index: 20;
  top: calc(100% + 0.35rem);
  left: 0;
  width: max-content;
  max-width: min(28rem, 90vw);
  max-height: 60vh;
  overflow-y: auto;
  padding: var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-elevated);
  box-shadow: 0 10px 30px var(--shadow);
}

.filter-reset {
  font: inherit;
  font-size: 0.85rem;
  padding: 0.35em 0.85em;
  border: 1px solid transparent;
  border-radius: var(--radius);
  background: none;
  color: var(--fg-muted);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

.filter-reset:hover {
  color: var(--accent);
}

/* Text search hides individual entries via a plain `hidden` attribute,
   set by scripts/site.js. No JS present = attribute never set = every
   entry stays visible. */
.entry[hidden] {
  display: none;
}

/* ---------- CSS-only publication filters ----------
   The rules themselves are NOT here: build.py generates one
   `main:has(#f-<group>-<value>:checked) .entry:not([data-…])` rule per
   value actually present in each page's data, into a small <style> block
   in that page's <head> (render_filter_style_block). Hand-writing them
   here meant a new category — or a new work type — silently losing its
   filter until someone remembered to add a rule. The chip styling above
   is the part that is genuinely static.

   Two invariants the generated rules depend on, kept here as a note:
   entries carry data-type / data-lang / data-year / data-cat /
   data-unpublished, and the checked radio must share an ancestor with
   the entries — hence `main:has(…)`, since the toolbar and the list are
   siblings, not nested. */

/* ---------- About page ---------- */

/* Centre Perelman / LinkedIn, directly under the portrait (moved 2026-08-05
   from an isolated section further down the page). First pass reused the
   work page's full-width stacked .work-access-compact pill treatment
   verbatim — on the About hero's wider portrait column that read as two
   ~320px bars, heavier than the H1 above them and louder than the
   "Écrire à…" contact CTA. Second pass (same day): natural-width pills in
   a wrapping row instead of a full-width stack, so they sit as a quiet
   line under the photo rather than a second block competing with it. */
.about-portrait-links {
  margin-top: var(--space-3);
}

.about-portrait-links ul {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
}

.about-portrait-links .btn {
  border-radius: 999px;
  padding: 0.42em 1.1em;
  font-size: 0.94rem;
}

/* A quieter variant of .btn — border/background only on hover — used for
   a personal/social link (LinkedIn) sitting next to an institutional one
   (Centre Perelman, plain .btn-secondary), so the two don't read as equal
   weight. Generic enough to reuse anywhere a link should look secondary
   to a neighboring .btn. */
.btn-ghost {
  border-color: transparent;
  background: transparent;
}

.btn-ghost:hover {
  border-color: var(--accent);
  background: var(--bg-elevated);
}

/* ---------- Contact ---------- */

.contact-cta-row {
  margin: var(--space-3) 0 var(--space-4);
}

.btn-contact-cta {
  padding: 0.7em 1.7em;
  font-size: 1.05rem;
  border-radius: 999px;
}

/* ---------- Footer ---------- */

.site-footer {
  border-top: 1px solid var(--border);
}

.footer-inner {
  max-width: 64rem;
  margin: 0 auto;
  padding: var(--space-4);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-4);
  color: var(--fg-muted);
  font-size: 0.85rem;
}

.footer-inner p {
  margin: 0;
}

/* ---------- Breadcrumbs (corpus + work pages) ---------- */

.breadcrumb {
  font-size: 0.85rem;
  color: var(--fg-muted);
  margin-bottom: var(--space-3);
}

/* ---------- Corpus page ----------
   One flat, sortable list of every work. Each row is a native <details>:
   the summary is the row, the body is the full field preview, so the
   whole thing opens and closes with zero JS. The row grid below and the
   sticky column strip share --corpus-cols so they stay aligned. */

.corpus-intro {
  padding-bottom: var(--space-4);
}

.corpus-page main > section {
  border-bottom: 0;
}

.corpus-page .publications {
  padding-top: 0;
}

.stat-tiles {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-4);
}

.stat-tiles .tile {
  flex: 1 1 8rem;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-elevated);
}

.stat-tiles .tile span {
  display: block;
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--fg-muted);
}

.stat-tiles .tile strong {
  font-family: var(--font-serif);
  font-size: 1.35rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.corpus-toolbar {
  margin-bottom: var(--space-3);
}

.corpus-toolbar .pub-filters {
  margin-bottom: var(--space-3);
  align-items: flex-end;
}

.filter-reset {
  font: inherit;
  font-size: 0.85rem;
  padding: 0.35em 0.9em;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-elevated);
  color: var(--fg-muted);
  cursor: pointer;
}

.filter-reset:hover {
  color: var(--fg);
  border-color: var(--fg-muted);
}

.corpus-status {
  margin: 0 0 var(--space-2);
  font-size: 0.85rem;
  color: var(--fg-muted);
}

.corpus-empty {
  margin: var(--space-4) 0;
  padding: var(--space-3);
  border: 1px dashed var(--border);
  border-radius: var(--radius);
  color: var(--fg-muted);
}

.corpus-empty[hidden] {
  display: none;
}

/* Row + column-strip geometry. The leading 1.2rem column holds the
   disclosure chevron (a real <summary> marker disappears once the
   summary becomes a grid container, so it is drawn here instead). */
.corpus-head,
.ce-row {
  display: grid;
  grid-template-columns: var(--corpus-cols);
  align-items: baseline;
  gap: var(--space-2);
  --corpus-cols: 1.2rem minmax(0, 1fr) 10rem 4rem 3rem;
}

.corpus-head {
  position: sticky;
  top: 0;
  z-index: 5;
  /* Right padding matches .corpus-list > .entry's own 8.5rem (reserved
     there for the row's labelled permalink pill): without it this grid is
     wider than a row's, and every fixed-width column (type/year/language)
     ends up shifted right of the content it's meant to label. */
  padding: var(--space-2) 8.5rem var(--space-2) 0;
  border-bottom: 1px solid var(--fg-muted);
  background: var(--bg);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--fg-muted);
}

.corpus-head::before {
  content: "";
}

/* JS upgrades each column label into a sort button in place. */
.corpus-head button {
  font: inherit;
  text-transform: inherit;
  letter-spacing: inherit;
  color: inherit;
  text-align: left;
  padding: 0.2em 0.3em;
  margin: -0.2em -0.3em;
  border: 0;
  border-radius: var(--radius);
  background: none;
  cursor: pointer;
}

.corpus-head button:hover {
  color: var(--fg);
  background: var(--bg-elevated);
}

.corpus-head button[aria-pressed="true"] {
  color: var(--accent);
  font-weight: 700;
}

.corpus-head button .arrow {
  font-size: 0.9em;
}

.corpus-list {
  padding: 0;
  margin: 0;
  list-style: none;
}

.corpus-list > .entry {
  position: relative;
  padding: 0 8.5rem 0 0;
  border-top: 1px solid var(--border);
}

.corpus-list > .entry:first-child {
  border-top: 0;
}

.corpus-list > .entry:hover {
  background: var(--bg-elevated);
}

/* The row's permalink: outside the <details> on purpose, so navigating
   never depends on expanding first and no interactive element is nested
   inside <summary> (assistive tech exposes those inconsistently). A
   labelled pill rather than a bare "→" (2026-08-04): the arrow alone read
   as decoration, not as a second, distinct way to leave the row — the
   icon (the same one on the "Full record" button inside the expanded
   body) plus the label make it read as its own link at a glance, before
   a reader has even opened the row. */
.ce-link {
  position: absolute;
  top: 0.6rem;
  right: 0;
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
  padding: 0.3em 0.75em;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--bg-elevated);
  text-decoration: none;
  color: var(--fg-muted);
  font-size: 0.78rem;
  white-space: nowrap;
}

.ce-link:hover,
.ce-link:focus-visible {
  border-color: var(--accent);
  color: var(--accent);
}

.ce-row {
  cursor: pointer;
  padding: 0.7rem 0;
  list-style: none;
}

.ce-row::-webkit-details-marker {
  display: none;
}

.ce-row::before {
  content: "›";
  color: var(--fg-muted);
  font-size: 1.1rem;
  line-height: 1;
  transition: transform 0.15s ease;
}

details[open] > .ce-row::before {
  transform: rotate(90deg);
}

.ce-row:hover .ce-title {
  color: var(--accent);
}

.ce-main {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  min-width: 0;
}

.ce-main-text {
  min-width: 0;
  flex: 1 1 auto;
}

.ce-title {
  display: block;
  font-weight: 600;
  text-wrap: pretty;
}

/* The interface-language rendering of a title, sitting under the title the
   work was actually published under. Deliberately one step down in size and
   in italic: the published title has to keep reading as the heading, and
   this as a gloss on it, not as an alternative to it. */
.ce-gloss {
  display: block;
  font-size: 0.88rem;
  font-style: italic;
  color: var(--fg-muted);
  text-wrap: pretty;
}

.ce-sub {
  display: block;
  font-size: 0.85rem;
  color: var(--fg-muted);
}

.ce-type,
.ce-year,
.ce-lang {
  font-size: 0.8rem;
  color: var(--fg-muted);
}

.ce-year,
.ce-lang {
  font-variant-numeric: tabular-nums;
}

/* ---------- Corpus row body (the inline full-field preview) ---------- */

/* The optional cover — moved here from the collapsed summary (2026-08-04):
   it now only appears once a reader opens the entry, sitting to the right
   of the field preview rather than crowding the always-visible title row.
   Only the ~25 works that have one get it; purely decorative
   (aria-hidden), the title text already carries the row's accessible
   name. */
.ce-body {
  display: flex;
  align-items: flex-start;
  gap: var(--space-4);
  padding: 0 0 var(--space-4) 1.2rem;
  max-width: calc(var(--content-width) + 9rem);
}

.ce-body-main {
  flex: 1 1 auto;
  min-width: 0;
  max-width: var(--content-width);
}

.ce-body-thumb {
  flex: none;
  display: block;
}

.ce-body-thumb picture,
.ce-body-thumb img {
  display: block;
  width: 6rem;
  height: 8.5rem;
  object-fit: cover;
  border-radius: 4px;
  box-shadow: 0 2px 8px var(--shadow);
}

/* Stated once, right above the abstract, only when the row's summary and
   keywords are actually a translation (2026-08-04) — reuses the work
   page's own provenance phrasing so the two say the same thing the same
   way. */
.ce-provenance {
  margin: 0 0 var(--space-2);
  font-size: 0.85rem;
  color: var(--fg-muted);
  font-style: italic;
}

.ce-summary {
  margin-bottom: var(--space-3);
}

.ce-empty {
  color: var(--fg-muted);
  font-style: italic;
}

.ce-tags {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-2);
  margin: 0 0 var(--space-2);
  padding: 0;
}

.ce-tags li {
  padding: 0.1em 0.7em;
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: 0.78rem;
  color: var(--fg-muted);
}

/* The "Cite" disclosure inside an expanded corpus row: styled as a
   button, so it sits on the same line as "Full record" and "Read the
   PDF" (2026-08-04) rather than as its own block above them. Opening it
   claims the full row width (flex-basis: 100%) so the four citation
   formats get room to breathe instead of squeezing into whatever space
   was left beside the other two buttons. */
.ce-actions .ce-cite {
  margin: 0;
}

.ce-actions .ce-cite[open] {
  flex-basis: 100%;
}

.ce-cite > summary {
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
  padding: 0.35em 0.85em;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-elevated);
  font-size: 0.85rem;
  cursor: pointer;
  list-style: none;
}

.ce-cite > summary::-webkit-details-marker {
  display: none;
}

.ce-cite > summary:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.ce-cite[open] > summary {
  margin-bottom: var(--space-2);
}

.ce-actions {
  margin: var(--space-3) 0 0;
}

/* ---------- Citation formats (corpus rows + work pages) ----------
   Button on the left, the exact text it copies on the right: the text is
   never hidden behind the button, so it can be read and selected by hand
   with no JS at all. */

.cite-formats {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  align-items: start;
  gap: var(--space-2) var(--space-3);
  margin-bottom: var(--space-2);
}

.cite-formats .btn-copy {
  width: 100%;
  justify-content: flex-start;
  min-width: 10rem;
}

.cite-formats pre {
  margin: 0;
  padding: 0.5em 0.8em;
  max-height: 9rem;
  overflow: auto;
  border-left: 2px solid var(--border);
  background: var(--bg-elevated);
  font-size: 0.8rem;
  line-height: 1.5;
  white-space: pre-wrap;
  word-break: break-word;
  color: var(--fg-muted);
}

.cite-hint {
  margin: 0;
  font-size: 0.8rem;
  color: var(--fg-muted);
}

/* ---------- Share row ---------- */

.share-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  margin-top: var(--space-5);
  padding-top: var(--space-3);
  border-top: 1px solid var(--border);
}

.share-label {
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--fg-muted);
}

.share-link {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  padding: 0.3em 0.7em;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-elevated);
  color: var(--fg-muted);
  font: inherit;
  font-size: 0.85rem;
  text-decoration: none;
  cursor: pointer;
}

.share-link:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.share-link.is-copied {
  border-color: var(--ok);
  color: var(--ok);
}

/* ---------- Unpublished works ----------
   The rarest thing in the corpus: never published, available nowhere
   else. Marked on three levels — a tinted row, a badge on the title, and
   its own filter chip — so it is impossible to scroll past unnoticed. */

.entry[data-unpublished] {
  background: var(--rare-bg);
  box-shadow: inset 3px 0 0 var(--rare);
}

.entry[data-unpublished]:hover {
  background: var(--rare-bg);
}

.ce-flag,
.chip-rare input:checked + label {
  background: var(--rare);
  color: var(--rare-contrast);
}

.ce-flag {
  display: inline-block;
  padding: 0.05em 0.55em;
  margin-right: 0.4em;
  border-radius: 999px;
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  vertical-align: 0.12em;
}

.chip-rare label {
  border-color: var(--rare);
  color: var(--rare);
}

.chip-rare input:checked + label {
  border-color: var(--rare);
}

.ce-note,
.work-flag {
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius);
  background: var(--rare-bg);
  box-shadow: inset 3px 0 0 var(--rare);
  font-size: 0.9rem;
}

.work-flag {
  max-width: var(--content-width);
}

/* A translated page's original is one click away — deliberately a
   distinct accent from the unpublished flag above (--rare is reserved for
   that one signal) so the two callouts are never mistaken for each other
   at a glance. */
.translation-notice {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius);
  background: var(--bg-elevated);
  box-shadow: inset 3px 0 0 var(--accent);
  font-size: 0.9rem;
  color: var(--fg-muted);
  max-width: var(--content-width);
}

.translation-notice .i {
  flex-shrink: 0;
  margin-top: 0.2em;
  color: var(--accent);
}

.translation-notice a {
  font-weight: 600;
  white-space: nowrap;
}

/* ---------- Work page ---------- */

/* Title block and cover side by side on wide screens, stacked below.
   The cover column keeps its width whether or not an image exists, so
   the heading doesn't reflow the day a cover is dropped in.
   `flex-wrap: wrap-reverse` is what puts the cover column above the
   title on narrow screens (it's the second element in the DOM, so it
   wraps onto its own line first without wrap-reverse). The gotcha:
   `wrap-reverse` also flips the flex container's cross-start/cross-end,
   so `align-items: flex-start` actually means "align to the bottom" —
   harmless while both columns were close in height, but the cover
   column grew (2026-08-04, the share row moved in under it) and the
   title visibly sank. `start` is the CSS Box Alignment keyword, not the
   flex-relative one, so it always means the physical top regardless of
   wrap-reverse. */
/* work-layout used to wrap only the title/abstract block and the cover
   column (.work-head); it now spans the whole article body (2026-08-04,
   later) — tags, full text, citations, share, edition note, prev/next all
   sit in .work-rest, a sibling of .work-head-text and .work-cover-col —
   specifically so the sidebar's grid area is as tall as the *entire*
   reading page, which is what lets it stick through the full scroll
   rather than stopping at the end of the abstract (see the sticky rule on
   .work-cover-col below). This is CSS Grid, not flex-wrap + order: a
   `display:flex; order:` reorder would move the sidebar's *tab stops* to
   wherever the CSS puts it, not just its pixels — a keyboard/screen-reader
   user would then have to pass the entire full-text article (up to 90+
   footnote links on some works) before ever reaching "Cite"/"Share"/
   "Download the PDF". Grid areas let the visual position move per
   breakpoint while the source order — head-text, aside, rest — never
   does; see the comment on .work-layout in work.template.html. */
.work-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) min(15rem, 100%);
  grid-template-areas:
    "head aside"
    "rest aside";
  column-gap: var(--space-4);
  align-items: start;
  margin-bottom: var(--space-4);
}

.work-head-text {
  grid-area: head;
  min-width: 0;
}

.work-rest {
  grid-area: rest;
  min-width: 0;
}

/* Cover image and the compact "access this text" pills share this column,
   stacked, so the ways to actually read the work sit right where the eye
   already is after looking at the cover — not a full section scrolled past
   further down the page. On wide screens (see the sticky rule further
   down) this column also follows the reader down through the full text:
   "unintrusive but helpful" was the ask, so it only ever holds what was
   already here (cover, access, contact, cite/share jump links) — no new
   content added just because it now stays on screen longer. */
.work-cover-col {
  grid-area: aside;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

@media (min-width: 960px) {
  .work-cover-col {
    position: sticky;
    top: var(--space-4);
    max-height: calc(100vh - var(--space-4) * 2);
    overflow-y: auto;
    /* Keeps the sticky column from visually merging with the page's own
       scrollbar/edge and gives a hovering scrollbar (on the rare tall
       cover + long access list) a sliver of room instead of overlapping
       the pills themselves. */
    padding-right: 2px;
  }
}

/* Narrow/tablet: one column. The cover/access/contact/share-jump block
   still shows visually *above* the title (matching the pre-2026-08-04
   mobile treatment, which used flex-wrap-reverse for the same effect) —
   only the pixels move here, never the .work-layout source order in the
   template, so tab order stays head-text → aside → rest at every width. */
@media (max-width: 959px) {
  .work-layout {
    grid-template-columns: 1fr;
    grid-template-areas:
      "aside"
      "head"
      "rest";
  }
}

.work-cover {
  margin: 0;
}

.work-cover picture,
.work-cover img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius);
  box-shadow: 0 8px 30px var(--shadow);
}

/* No cover yet: an empty frame holding only what the page already says
   (type and year). Deliberately not a generated stand-in image — nothing
   here could be mistaken for a picture of the work. */
.work-cover-empty {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--space-2);
  aspect-ratio: 3 / 4;
  padding: var(--space-4);
  border: 1px dashed var(--border);
  border-radius: var(--radius);
  background: var(--bg-elevated);
  text-align: center;
}

.cover-type {
  font-family: var(--font-serif);
  font-size: 1rem;
  color: var(--fg-muted);
  text-wrap: balance;
}

.cover-year {
  font-size: 0.85rem;
  letter-spacing: 0.12em;
  color: var(--fg-muted);
  font-variant-numeric: tabular-nums;
}

.work-kicker {
  font-family: var(--font-serif);
  font-style: italic;
  color: var(--accent);
  margin-bottom: var(--space-1);
}

/* The work's own published title, directly under the <h1> reading it in the
   interface language, labelled as the original it is. Sized between the
   heading and the byline: the reader's-language title leads, the citable
   original follows right after, then who wrote it. */
.work-title-gloss {
  font-size: 1.15rem;
  font-style: italic;
  color: var(--fg-muted);
  text-wrap: pretty;
  margin-bottom: var(--space-1);
}

.work-title-gloss-label {
  display: block;
  font-style: normal;
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--fg-muted);
}

.work-byline {
  color: var(--fg-muted);
  font-size: 1.05rem;
}

.work-meta {
  color: var(--fg-muted);
  font-size: 0.9rem;
}

.work-venue {
  font-style: italic;
}

/* On its own line, not run into .work-meta with a middle dot (2026-08-05)
   — same reasoning as .ce-provenance on the corpus/home row: a short factual
   aside reads better set apart than crowded onto the venue/year line. */
.work-provenance {
  margin: var(--space-1) 0 0;
  font-size: 0.85rem;
  font-style: italic;
  color: var(--fg-muted);
}

/* Keywords sit with the title, not with the supporting sections further
   down — a plain block, not a bordered <section>, so it reads as part of
   the heading rather than a fourth full-width block before the summary. */
.work-keywords-inline {
  margin-top: var(--space-3);
}

.work-keywords-inline h2 {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--fg-muted);
  margin: 0 0 var(--space-1);
}

.work-keywords-inline .tag-list {
  margin-bottom: 0;
}

/* The abstract moved up to sit with the title/keywords (2026-08-04),
   inside .work-head-text rather than as its own full-width section
   further down — same "keep it in the same glance as the cover" logic
   already applied to keywords and the access/contact/share pills. The
   generic <section> rule's 4rem top-and-bottom padding and full-bleed
   border were sized for a top-level page section, not something nested
   in a ~22rem text column beside a cover image — overridden down to a
   plain top gap. */
.work-head-text .work-abstract {
  padding: var(--space-4) 0 0;
  border-bottom: 0;
}

/* "Access this text" as a small pill box under the cover, not a full-width
   section scrolled past further down — the reader sees the ways to actually
   read the work in the same glance as the cover. Pills reuse the .btn
   markup render_access_section() already emits (same download attributes,
   same target/rel), just rescaled here rather than duplicated. */
.work-access-compact {
  padding: 0;
  border-bottom: 0;
}

.work-access-compact h2 {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--fg-muted);
  margin: 0 0 var(--space-2);
}

.work-access-compact .btn-row {
  flex-direction: column;
  align-items: stretch;
  margin-bottom: 0;
}

.work-access-compact .btn {
  border-radius: 999px;
  padding: 0.35em 0.9em;
  font-size: 0.78rem;
  justify-content: center;
  text-align: center;
}

.work-access-compact .access-note,
.work-access-compact .access-none {
  font-size: 0.78rem;
  margin-top: var(--space-2);
}

/* "Contact the Author" pill, same rescaled treatment as the access pills
   right above it — a reader with no public copy to reach for should be
   able to just ask, without scrolling down to find a contact link. */
.work-contact-compact .btn {
  width: 100%;
  border-radius: 999px;
  padding: 0.35em 0.9em;
  font-size: 0.78rem;
  justify-content: center;
  text-align: center;
}

/* Cite/share used to show their full option sets directly in the cover
   column; now (2026-08-04) that column just holds two small jump links —
   "instead of putting all the options below the cover we just link to #
   below ... where we already have cite me full info", same treatment for
   share — down to the full sections further down the page (#cite is the
   existing .work-citations card; #share is .work-share-full below). */
.work-jump-links {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.work-jump-links .btn {
  width: 100%;
  border-radius: 999px;
  padding: 0.35em 0.9em;
  font-size: 0.78rem;
  justify-content: center;
  text-align: center;
}

/* The full share-option row, now its own destination at the bottom of the
   page (#share) rather than packed into the cover column — same card
   treatment as .work-citations, just without the accent border, so the
   two read as a matched pair without competing for attention. */
.work-share-full {
  margin: var(--space-4) 0 0;
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-elevated);
}

.work-share-full h2 {
  display: flex;
  align-items: center;
  gap: 0.5em;
  font-size: 1.1rem;
  border-bottom: 0;
  padding-bottom: 0;
  margin-bottom: var(--space-2);
}

.work-share-full h2 .i {
  color: var(--accent);
}

.work-share-full .share-label {
  display: none;
}

/* The three share buttons used to sit at their plain inline-pill size
   inside this full-width card, leaving most of the row visibly empty —
   "small compared to their area" (2026-08-05). Grown to fill the row in
   even, equal-width shares rather than shrink-wrapping their labels, same
   card-filling instinct already applied to the export links above. */
.work-share-full .share-row {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
  gap: var(--space-3);
}

.work-share-full .share-link {
  flex: 1 1 8rem;
  justify-content: center;
  padding: 0.7em 1.2em;
  border-radius: 999px;
  font-size: 0.95rem;
}

.work-share-full .share-link .i {
  width: 1.2em;
  height: 1.2em;
}

.work-summary {
  max-width: var(--content-width);
}

.work-abstract p:last-child {
  margin-bottom: 0;
}

/* The abstract in the language the author wrote it in. Closed by default —
   the page's own language leads — and native, so it opens with no JS and
   costs no second request. */
.work-summary-original {
  margin-top: var(--space-3);
  border-top: 1px solid var(--border);
  padding-top: var(--space-2);
}

.work-summary-original > summary {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  cursor: pointer;
  font-size: 0.9rem;
  color: var(--fg-muted);
}

.work-summary-original > summary:hover {
  color: var(--accent);
}

.work-summary-original[open] > summary {
  margin-bottom: var(--space-2);
}

.tag-list {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: 0 0 var(--space-4);
  padding: 0;
}

.tag {
  display: inline-block;
  padding: 0.25em 0.8em;
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: 0.8rem;
  color: var(--fg-muted);
}

.tag-category {
  border-style: dashed;
}

/* Citing the work used to be a closed-by-default disclosure, tucked away
   with the other "supporting" sections — reopened and made prominent
   (2026-08-04, "show it proudly"): an accent-bordered card, the same
   visual language as the corpus page's "whole corpus, in one file" box,
   with no toggle to click through first. Sized down (same day, "a bit
   overboard") from a first pass that matched the full h1-scale h2 and
   noticeably enlarged the citation text — this reads as its own clearly
   marked destination without dominating the page below it. */
.work-citations {
  margin: var(--space-4) 0 0;
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--accent);
  border-radius: var(--radius);
  background: var(--bg-elevated);
  box-shadow: inset 3px 0 0 var(--accent), 0 2px 10px var(--shadow);
}

.work-citations h2 {
  display: flex;
  align-items: center;
  gap: 0.5em;
  font-size: 1.1rem;
  border-bottom: 0;
  padding-bottom: 0;
  margin-bottom: var(--space-2);
}

.work-citations h2 .i {
  color: var(--accent);
}

.access-none,
.access-note {
  color: var(--fg-muted);
  font-size: 0.9rem;
  margin-bottom: 0;
}

/* ---------- Work reading page: full text (2026-08-04) ---------- */

/* EB Garamond, self-hosted (./fonts/, subset to latin + latin-ext — covers
   fr/en/pt/es accents) — the same family as the Typst-built PDF editions,
   transposed for screen. Declared once, used only inside .work-article,
   so a browser that never renders a reading page never fetches it
   (font-display: swap plus the fact that nothing else on the site sets
   font-family: var(--font-edition)). One weight only: the editions and
   this build both avoid bold in running text, so there is no second
   weight file to self-host — see `.work-article strong` below. */
@font-face {
  font-family: "EB Garamond";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/eb-garamond-regular-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F, U+20AC, U+2122;
}
@font-face {
  font-family: "EB Garamond";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/eb-garamond-regular-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-024F, U+0300-036F, U+1E00-1EFF, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "EB Garamond";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/eb-garamond-italic-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F, U+20AC, U+2122;
}
@font-face {
  font-family: "EB Garamond";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/eb-garamond-italic-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-024F, U+0300-036F, U+1E00-1EFF, U+2C60-2C7F, U+A720-A7FF;
}

.work-article-section {
  margin-top: var(--space-5);
}

/* The full text is never machine-translated, so a page whose language
   isn't the work's original shows this in place of the article itself
   (2026-08-05) — same section, same heading, so a reader scanning
   straight to "Full text" finds the pointer exactly where the text
   would otherwise be, rather than only in the translation-notice
   further up the page. */
.work-article-elsewhere-note {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  max-width: var(--content-width);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-elevated);
  color: var(--fg-muted);
}

.work-article-elsewhere-note .i {
  flex-shrink: 0;
  margin-top: 0.2em;
  color: var(--accent);
}

.work-article-elsewhere-note a {
  font-weight: 600;
}

/* Measure ~65 characters at this size/family, ~19px body scaling down to
   the site's normal 1rem at 360px (see the narrow-viewport rule below).
   No first-line indent (a print convention that doesn't transfer to
   screen) — paragraphs separate by vertical space instead. Ragged right,
   not justified; `hyphens: auto` reads the page's own `lang` (no
   mixed-language content within one article, so no per-node override is
   needed). */
.work-article {
  max-width: 38rem;
  font-family: "EB Garamond", var(--font-serif);
  font-size: 1.1875rem;
  line-height: 1.6;
  text-align: left;
  hyphens: auto;
}

.work-article p {
  text-indent: 0;
  margin: 0 0 1.3em;
}

.work-article > *:last-child {
  margin-bottom: 0;
}

/* Section headings: small caps, letterspaced, centered — the roman-numeral
   + " – " pattern is preserved as ordinary text content (see
   preprocess_headings()/looks_like_noise_heading() in build.py), not
   generated here. Overrides the page-level h2 rule's bottom border/left
   alignment, which is sized for top-level section chrome, not in-article
   structure. */
.work-article h2,
.work-article h3 {
  font-family: "EB Garamond", var(--font-serif);
  font-variant-caps: small-caps;
  font-weight: 400;
  letter-spacing: 0.05em;
  text-align: center;
  border-bottom: 0;
  padding-bottom: 0;
  margin: 2.2em 0 1em;
}

.work-article h3 {
  font-size: 1em;
  font-style: italic;
}

.heading-anchor {
  margin-left: 0.5em;
  font-size: 0.7em;
  text-decoration: none;
  opacity: 0;
  color: var(--fg-muted);
}

.work-article h2:hover .heading-anchor,
.work-article h2:focus-within .heading-anchor,
.work-article h3:hover .heading-anchor,
.work-article h3:focus-within .heading-anchor {
  opacity: 1;
}

/* The Typst `***` divider (`#align(center)[\*#linebreak()\*\*]` in the
   source — see strip_typst_leftovers()), a plain thematic <hr> once
   converted: the rule itself is hidden and replaced with a centered
   asterism, generous space either side. */
.work-article hr {
  border: 0;
  height: 1.4em;
  margin: 2.2em 0;
  text-align: center;
  color: var(--fg-muted);
}

.work-article hr::before {
  content: "⁂";
  font-size: 1.2em;
}

/* No bold weight is self-hosted (see the @font-face block above) — a
   `#strong[...]` in the source (16 instances across the corpus) reads as
   italic rather than a browser-synthesized faux-bold, which would clash
   with a real italic face sitting right next to it. */
.work-article strong {
  font-weight: inherit;
  font-style: italic;
}

.work-article .small-caps {
  font-variant-caps: small-caps;
}

.work-article .underline {
  text-decoration: underline;
}

.work-article mark {
  background: light-dark(#fdf1c7, #4a3c14);
  color: inherit;
  padding: 0 0.15em;
}

.work-article blockquote {
  margin: 1.3em 0 1.3em 1.3em;
  padding-left: 1em;
  border-left: 2px solid var(--border);
  font-style: italic;
  color: var(--fg-muted);
}

/* Footnote markers: superscript links, each carrying a plain-text preview
   of its own note in `data-note` (set by postprocess_article_html()) for
   a CSS-only hover/focus popover — progressive enhancement only, since
   the endnotes list below stays the source of truth and the preview
   cannot carry the note's own markup (attr() is plain text). */
.work-article .footnote-ref {
  text-decoration: none;
  padding: 0 0.1em;
}

.work-article .footnote-ref[data-note] {
  position: relative;
  border-bottom: 1px dotted var(--fg-muted);
  cursor: help;
}

.work-article .footnote-ref[data-note]:hover::after,
.work-article .footnote-ref[data-note]:focus::after {
  content: attr(data-note);
  position: absolute;
  left: 50%;
  bottom: 100%;
  transform: translateX(-50%);
  width: max-content;
  max-width: min(22rem, 80vw);
  margin-bottom: 0.4em;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-elevated);
  box-shadow: 0 4px 20px var(--shadow);
  font-family: var(--font-sans);
  font-size: 0.8rem;
  font-style: normal;
  font-variant-caps: normal;
  line-height: 1.4;
  color: var(--fg);
  text-align: left;
  white-space: normal;
  z-index: 10;
}

/* The endnotes list itself (python-markdown's own `<div class="footnote">`
   structure, namespaced by work id and left otherwise as generated — see
   render_work_article()/postprocess_article_html()). */
.work-footnotes {
  margin-top: 3em;
  font-family: var(--font-sans);
  font-size: 0.88rem;
  color: var(--fg-muted);
}

.work-footnotes .footnote hr {
  border: 0;
  border-top: 1px solid var(--border);
  margin: 0 0 1.5em;
}

.work-footnotes ol {
  padding-left: 1.3em;
}

.work-footnotes li {
  margin-bottom: 0.8em;
}

.work-footnotes .footnote-backref {
  margin-left: 0.3em;
  text-decoration: none;
}

.work-edition-note {
  margin-top: var(--space-5);
  padding-top: var(--space-3);
  border-top: 1px solid var(--border);
  font-size: 0.85rem;
  font-style: italic;
  color: var(--fg-muted);
}

.work-prev-next {
  display: flex;
  justify-content: space-between;
  gap: var(--space-3);
  margin-top: var(--space-3);
}

/* A left/right arrow beside the text (2026-08-05), not just a plain link,
   so "previous"/"next" reads at a glance the way a printed book's own
   running header does, rather than relying on the label text alone. */
.prev-next-link {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  max-width: 45%;
  text-decoration: none;
}

.prev-next-link .i {
  flex-shrink: 0;
  width: 1.4em;
  height: 1.4em;
  color: var(--accent);
}

.prev-next-text {
  display: flex;
  flex-direction: column;
  gap: 0.2em;
  min-width: 0;
}

.prev-next-link.next {
  margin-left: auto;
  text-align: right;
}

.prev-next-link.next .prev-next-text {
  align-items: flex-end;
}

.prev-next-label {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--fg-muted);
}

.prev-next-title {
  font-family: var(--font-serif);
}

.prev-next-year {
  font-size: 0.72rem;
  color: var(--fg-muted);
  font-variant-numeric: tabular-nums;
}

/* Printed only — see the @media print block below. */
.work-print-url {
  display: none;
}

/* A long work's landing page lists its chapters instead of duplicating
   their text (see split_into_chapters() / render_chapter_toc() in
   build.py) — same section chrome as the full-text case, a plain
   numbered list of links in its place. */
.chapters-toc-list {
  list-style: none;
  margin: 0;
  padding: 0;
  max-width: 38rem;
}

.chapters-toc-list li {
  border-bottom: 1px solid var(--border);
}

.chapters-toc-list a {
  display: flex;
  gap: var(--space-3);
  padding: var(--space-2) 0;
  text-decoration: none;
  color: var(--fg);
}

.chapters-toc-list a:hover .toc-chapter-title {
  color: var(--accent);
}

.toc-chapter-label {
  flex: 0 0 auto;
  color: var(--fg-muted);
  font-variant-numeric: tabular-nums;
}

.toc-chapter-title {
  font-family: var(--font-serif);
}

/* A chapter page has no cover column, so its title block sits at full
   width rather than sharing .work-layout's flex row with anything. */
.chapter-head {
  max-width: var(--content-width);
  margin-bottom: var(--space-4);
}

/* ---------- Responsive ---------- */

/* Narrow viewports: the corpus columns stop being columns. The row wraps
   its metadata under the title, and the column strip becomes a plain row
   of sort buttons — still every sort key, just no longer aligned to
   anything. Queried against the `page` container, like the hero. */
@container page (max-width: 46rem) {
  .corpus-head,
  .ce-row {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.2rem var(--space-3);
  }

  .corpus-head::before {
    display: none;
  }

  .ce-main {
    flex: 1 1 calc(100% - 2.2rem);
  }

  .ce-body {
    padding-left: 0;
    flex-direction: column;
  }

  .ce-body-thumb picture,
  .ce-body-thumb img {
    width: 5rem;
    height: 7rem;
  }

  /* The permalink pill's text label is dropped below the desktop/tablet
     breakpoint: an icon-only circular button still reads as "go to the
     full record" (same icon as the button inside the expanded body), and
     the row needs its width back more than it needs the label spelled
     out here. */
  .corpus-list > .entry,
  .corpus-head {
    padding-right: 2.2rem;
  }

  .ce-link {
    top: 0.4rem;
    padding: 0.4em;
  }

  .ce-link-label {
    display: none;
  }

  /* The button/pre two-column grid (corpus row "Cite" panel and the work
     page's citation card alike) has no room to give the <pre> column at
     narrow widths — max-content sizes the button first and squeezes the
     text column down to almost nothing, wrapping it one character per
     line instead of by word. Stack them instead. */
  .cite-formats {
    grid-template-columns: minmax(0, 1fr);
  }

  /* The 38rem measure is a deliberate choice at desktop width, not a
     constraint the article needs to keep at 46rem and under — let it use
     the full column so the article doesn't develop a second, narrower
     measure inside an already-narrow one. */
  .work-article {
    max-width: 100%;
  }

  .work-prev-next {
    flex-direction: column;
    gap: var(--space-2);
  }

  .prev-next-link,
  .prev-next-link.next {
    max-width: 100%;
    margin-left: 0;
    text-align: left;
  }

  .prev-next-link.next .prev-next-text {
    align-items: flex-start;
  }
}

@media (max-width: 360px) {
  .header-inner,
  main,
  .footer-inner {
    padding-left: var(--space-3);
    padding-right: var(--space-3);
  }

  .work-article {
    font-size: 1.0625rem;
  }
}

/* ---------- Print ---------- */

@media print {
  .site-header,
  .theme-toggle-slot,
  .pub-search-slot,
  #pub-search-status,
  .pub-filters,
  .corpus-head,
  .ce-link,
  .lang-toggle,
  .skip-link {
    display: none !important;
  }

  body {
    background: #fff;
    color: #000;
  }

  a {
    color: #000;
    text-decoration: underline;
  }

  section {
    border-bottom: 0;
    padding: var(--space-3) 0;
  }

  /* Every entry visible regardless of any search/filter state. */
  .entry[hidden] {
    display: block !important;
  }

  /* Print the corpus as a bibliography: every row expanded, no chevrons,
     no row backgrounds, page breaks between works rather than inside. */
  .corpus-list > .entry {
    break-inside: avoid;
    padding-right: 0;
    background: none !important;
    box-shadow: none;
  }

  /* Both properties on purpose: the UA sheet hides a closed <details>'s
     content with content-visibility in current engines and with display
     in older ones. */
  .corpus-list .ce-body,
  .work-summary-original > div {
    display: block !important;
    content-visibility: visible !important;
  }

  .ce-row::before {
    display: none;
  }

  .ce-row {
    padding-bottom: 0;
  }

  .cite-formats pre {
    max-height: none;
    overflow: visible;
  }

  .btn-copy,
  .share-row,
  .cite-hint {
    display: none !important;
  }

  /* Work reading page: nav/actions/chrome hidden, the text prints
     cleanly, and the page's own URL prints in its place at the bottom
     (screen-only otherwise — see .work-print-url above). */
  .breadcrumb,
  .work-cover-col,
  .work-share-full,
  .heading-anchor,
  .footnote-ref[data-note]::after {
    display: none !important;
  }

  .work-article {
    max-width: 100%;
    font-size: 11pt;
  }

  .work-print-url {
    display: block;
    margin-top: var(--space-4);
    font-size: 9pt;
    color: #000;
  }
}
