/* Self-hosted variable subsets of Inter and Space Grotesk.
   No third-party requests at runtime; the .htaccess CSP forbids them.
   Subsets are unicode-range gated, so only what the page needs is fetched. */

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(../fonts/inter-var-greek.woff2) format('woff2');
  unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
}

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(../fonts/inter-var-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(../fonts/inter-var-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 500 700;
  font-display: swap;
  src: url(../fonts/space-grotesk-var-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 500 700;
  font-display: swap;
  src: url(../fonts/space-grotesk-var-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ==========================================================================
   The Goodwin Group — design system
   Bold scientific: near-black chrome, one vivid accent, card-led content.
   Everything is driven by the tokens in :root; there is no CSS framework.
   ========================================================================== */

/* -------------------------------------------------------------- 1. tokens */

/* Every colour that differs between themes is declared ONCE with light-dark().
   `color-scheme` is what selects the branch, so the three theme states all work
   from this single block: an explicit choice stamps data-theme on <html>, and
   the default "system" setting stamps nothing and follows the OS. */

:root {
  color-scheme: light dark;

  /* Neutrals — a slightly cool grey ramp so the accent stays the only hue.
     These are theme-independent; the chrome (header, hero, footer) is
     deliberately near-black in both themes and reads from this ramp. */
  --ink-900: #0b0e14;
  --ink-800: #141926;
  --ink-600: #3b4356;
  --ink-500: #5b6478;
  --ink-400: #838da4;
  --ink-300: #b3bccd;
  --ink-200: #d8dee9;
  --ink-100: #eceff5;
  --ink-050: #f6f8fb;
  --white: #fff;

  /* Surfaces */
  --bg:            light-dark(#fff,     #0b0e14);
  --bg-sunken:     light-dark(#f6f8fb,  #0f131c);
  --bg-raised:     light-dark(#fff,     #141926);
  --border:        light-dark(#d8dee9,  #262e40);
  --border-strong: light-dark(#b3bccd,  #38425a);

  /* A light plate for artwork that carries its own white background —
     journal TOC graphics, structure figures. Muted in dark mode so the
     plate does not glare against a near-black page. */
  --panel:         light-dark(#fff,     #cfd6e0);

  /* Text. All three clear WCAG AA on both --bg and --bg-sunken. */
  --text:              light-dark(#10141d, #e8edf6);
  --text-soft:         light-dark(#3b4356, #a2adc2);
  --text-faint:        light-dark(#5b6478, #7c879c);
  --text-inverse:      #f2f5fa;
  --text-inverse-soft: #a9b4c8;
  --text-inverse-faint: #8592aa;

  /* Accent — green. `-ink` is the >=4.5:1 variant for body links;
     `-glow` is the high-contrast variant used on the dark chrome. */
  --accent:          light-dark(#15803d, #22c55e);
  --accent-ink:      light-dark(#166534, #4ade80);
  --accent-hover:    light-dark(#14532d, #86efac);
  --accent-soft:     light-dark(#dcfce7, #0d2a18);
  --accent-contrast: light-dark(#fff,    #0b0e14);
  --accent-glow:     #4ade80;

  /* Category hues for news chips */
  --c-paper-bg:     light-dark(#dcfce7, #0d2a18);
  --c-paper-fg:     light-dark(#14532d, #86efac);
  --c-preprint-bg:  light-dark(#fef3c7, #3a2c0c);
  --c-preprint-fg:  light-dark(#92400e, #fcd34d);
  --c-group-bg:     light-dark(#cffafe, #0d3b36);
  --c-group-fg:     light-dark(#155e75, #5eead4);
  --c-event-bg:     light-dark(#dbeafe, #11284f);
  --c-event-fg:     light-dark(#1d4ed8, #93c5fd);
  --c-funding-bg:   light-dark(#ede9ff, #241f4d);
  --c-funding-fg:   light-dark(#5b21b6, #c4b5fd);
  --c-positions-bg: light-dark(#fce7f3, #3d1029);
  --c-positions-fg: light-dark(#a3175c, #f9a8d4);
  --c-news-bg:      light-dark(#eceff5, #1c2333);
  --c-news-fg:      light-dark(#3b4356, #a2adc2);

  /* Raised chrome surfaces — the white tints used on the near-black
     header, hero and footer. Two steps, not the six that had drifted. */
  --chrome-fill:        rgb(255 255 255 / 8%);
  --chrome-fill-hover:  rgb(255 255 255 / 16%);
  --chrome-line:        rgb(255 255 255 / 14%);
  --chrome-line-strong: rgb(255 255 255 / 22%);

  /* Type */
  --font-body: Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
               "Helvetica Neue", Arial, sans-serif;
  --font-display: "Space Grotesk", var(--font-body);
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  /* Fluid type scale (360px -> 1200px viewport), constant 1.20 ratio.
     --step--2 exists for the smallest metadata: chips, counts, captions. */
  --step--2: clamp(0.69rem, 0.67rem + 0.09vw, 0.75rem);
  --step--1: clamp(0.83rem, 0.80rem + 0.13vw, 0.90rem);
  --step-0:  clamp(1.00rem, 0.96rem + 0.18vw, 1.08rem);
  --step-1:  clamp(1.20rem, 1.14rem + 0.26vw, 1.30rem);
  --step-2:  clamp(1.44rem, 1.34rem + 0.44vw, 1.73rem);
  --step-3:  clamp(1.73rem, 1.56rem + 0.74vw, 2.22rem);
  --step-4:  clamp(2.07rem, 1.80rem + 1.19vw, 2.86rem);
  --step-5:  clamp(2.49rem, 2.06rem + 1.87vw, 3.73rem);

  /* Line height */
  --lh-body:    1.65;
  --lh-prose:   1.55;
  --lh-snug:    1.35;
  --lh-heading: 1.12;
  --lh-flat:    1.2;

  /* Space */
  --sp-1: 0.25rem; --sp-2: 0.5rem;  --sp-3: 0.75rem; --sp-4: 1rem;
  --sp-5: 1.5rem;  --sp-6: 2rem;    --sp-7: 3rem;

  --measure: 68ch;
  --wrap: 76rem;

  --radius: 10px;
  --radius-lg: 16px;
  --radius-pill: 999px;

  /* light-dark() is a colour function, so it wraps the shadow's colour only —
     never the whole box-shadow value. */
  --shadow-sm: 0 1px 2px  light-dark(rgb(11 14 20 / 6%),  rgb(0 0 0 / 40%)),
               0 1px 3px  light-dark(rgb(11 14 20 / 4%),  rgb(0 0 0 / 24%));
  --shadow-md: 0 4px 12px light-dark(rgb(11 14 20 / 8%),  rgb(0 0 0 / 45%)),
               0 2px 4px  light-dark(rgb(11 14 20 / 4%),  rgb(0 0 0 / 28%));
  --shadow-lg: 0 12px 32px light-dark(rgb(11 14 20 / 12%), rgb(0 0 0 / 55%)),
               0 4px 8px   light-dark(rgb(11 14 20 / 6%),  rgb(0 0 0 / 32%));

  /* Vertical rhythm. Lower these two to tighten the whole site;
     raise them to open it up. Nearly all vertical space derives from them. */
  --section-y: clamp(1.75rem, 3.2vw, 3rem);   /* above/below each band   */
  --row-y: 0.85rem;                           /* above/below list rows   */

  /* Motion */
  --dur-fast: 0.15s;
  --dur: 0.18s;
  --dur-slow: 0.4s;
  --ease: cubic-bezier(0.4, 0, 0.2, 1);

  /* Stacking */
  --z-nav: 200;
  --z-header: 100;
  --z-sticky: 5;

  --header-h: 4rem;
}

/* The explicit toggle. Switching color-scheme is all that is needed —
   every token above resolves through light-dark() from here. */
:root[data-theme="dark"]  { color-scheme: dark; }
:root[data-theme="light"] { color-scheme: light; }

/* ---------------------------------------------------------- 2. base reset */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--step-0);
  line-height: var(--lh-body);
  font-synthesis-weight: none;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, h5, h6 {
  margin: 0 0 var(--sp-3);
  font-family: var(--font-display);
  font-weight: 700;
  line-height: var(--lh-heading);
  letter-spacing: -0.02em;
  text-wrap: balance;
}

h1 { font-size: var(--step-4); }
h2 { font-size: var(--step-3); }
h3 { font-size: var(--step-2); }
h4 { font-size: var(--step-1); }

p { margin: 0 0 var(--sp-4); text-wrap: pretty; }
p:last-child { margin-bottom: 0; }

a { color: var(--accent-ink); text-decoration-thickness: 1px; text-underline-offset: 0.15em; }
a:hover { color: var(--accent-hover); text-decoration-thickness: 2px; }

img, video, svg { max-width: 100%; height: auto; display: block; }

ul, ol { margin: 0 0 var(--sp-4); padding-left: 1.35em; }
li { margin-bottom: var(--sp-2); }
li::marker { color: var(--accent); }

hr { border: 0; border-top: 1px solid var(--border); margin: var(--sp-7) 0; }

sub, sup { line-height: 0; }

code, kbd { font-family: var(--font-mono); font-size: 0.9em; }

::selection { background: var(--accent); color: var(--accent-contrast); }

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

/* The header, hero and footer are near-black in both themes, where the light
   accent only reaches 3.85:1. The glow variant gets there at 11.09:1. */
.site-header :focus-visible,
.hero :focus-visible,
.site-footer :focus-visible { outline-color: var(--accent-glow); }

/* One motion block for the whole site. Durations collapse rather than being
   removed, so state-carrying transforms — the burger turning into an X —
   still land, they just land instantly. Purely decorative movement is
   switched off outright. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  .btn:hover, .btn:active { transform: none; }
  .card:hover .card__media img { transform: none; }
  /* A banner held still while the page slides over it is parallax, and parallax
     is a common trigger for motion sickness. Let it scroll with the page, and
     re-crop it: detached from the viewport, `cover` sizes against the hero
     again. Two classes deep on purpose — this block sits above the .hero__media
     rule, so at equal specificity that rule would win. */
  .hero .hero__media {
    background-attachment: scroll;
    background-position: center 35%;
  }
}

.skip-link {
  position: absolute;
  left: var(--sp-4);
  top: -100%;
  z-index: var(--z-nav);
  padding: var(--sp-3) var(--sp-4);
  background: var(--accent);
  color: var(--accent-contrast);
  border-radius: 0 0 var(--radius) var(--radius);
  font-weight: 600;
  text-decoration: none;
  transition: top var(--dur-fast) var(--ease);
}
.skip-link:focus { top: 0; color: var(--accent-contrast); }

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

/* -------------------------------------------------------------- 3. layout */

.wrap { width: min(100% - 2 * var(--sp-5), var(--wrap)); margin-inline: auto; }

.section { padding-block: var(--section-y); }
.section--sunken { background: var(--bg-sunken); }

.prose { max-width: var(--measure); }
.prose :is(h2, h3) { margin-top: var(--sp-6); }
.prose > :first-child { margin-top: 0; }

/* Section heading: small accent eyebrow above a large display title. */
.section-head { margin-bottom: var(--sp-4); }
/* Section heads that repeat down a single page — the publication sections —
   need air above them to separate one run of entries from the next. */
.section-head--repeat { margin-top: var(--sp-4); }
.eyebrow {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin: 0 0 var(--sp-3);
  font-family: var(--font-display);
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent-ink);
}
.eyebrow::before {
  content: "";
  width: 1.75rem; height: 3px;
  background: var(--accent);
  border-radius: 2px;
  flex: none;
}
.section-head p { color: var(--text-soft); max-width: var(--measure); }

.section-foot { margin-top: var(--sp-6); display: flex; flex-wrap: wrap; gap: var(--sp-3); }

/* -------------------------------------------------------- 4. header / nav */

.site-header {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
  background: var(--ink-900);
  border-bottom: 1px solid var(--chrome-line);
}
.site-header::after {
  content: "";
  display: block;
  height: 3px;
  background: linear-gradient(90deg, var(--accent) 0%, var(--accent-glow) 55%, transparent 100%);
}

.site-header__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  min-height: var(--header-h);
}

.wordmark {
  display: inline-flex;
  align-items: baseline;
  gap: 0.4rem;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--step-0);
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--text-inverse);
  text-decoration: none;
  white-space: nowrap;
}
.wordmark:hover { color: var(--text-inverse); }
.wordmark__mark {
  height: 1.6em;
  width: auto;
  flex: none;
  align-self: center;          /* an SVG has no baseline to sit on */
  color: var(--accent-glow);
}

.nav__list {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
  margin: 0; padding: 0;
  list-style: none;
}
.nav__list li { margin: 0; }

.nav__link {
  display: block;
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--radius);
  color: var(--text-inverse-soft);
  font-size: var(--step--1);
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
  transition: color var(--dur-fast) var(--ease), background-color var(--dur-fast) var(--ease);
}
.nav__link:hover { color: var(--text-inverse); background: var(--chrome-fill); }
.nav__link[aria-current="page"] {
  color: var(--text-inverse);
  background: var(--chrome-fill);
  box-shadow: inset 0 -2px 0 var(--accent-glow);
}

.header__actions { display: flex; align-items: center; gap: var(--sp-2); }

.nav__toggle {
  display: none;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  background: var(--chrome-fill);
  border: 1px solid var(--chrome-line);
  border-radius: var(--radius);
  color: var(--text-inverse);
  font: inherit;
  font-size: var(--step--1);
  font-weight: 600;
  cursor: pointer;
}
.nav__toggle:hover { background: var(--chrome-fill-hover); }
.nav__burger { position: relative; width: 16px; height: 10px; flex: none; }
.nav__burger span {
  position: absolute; left: 0;
  width: 100%; height: 2px;
  background: currentColor; border-radius: 2px;
  transition: transform var(--dur) var(--ease), opacity var(--dur) var(--ease);
}
.nav__burger span:nth-child(1) { top: 0; }
.nav__burger span:nth-child(2) { top: 4px; }
.nav__burger span:nth-child(3) { top: 8px; }
[aria-expanded="true"] .nav__burger span:nth-child(1) { transform: translateY(4px) rotate(45deg); }
[aria-expanded="true"] .nav__burger span:nth-child(2) { opacity: 0; }
[aria-expanded="true"] .nav__burger span:nth-child(3) { transform: translateY(-4px) rotate(-45deg); }

@media (max-width: 61.999rem) {
  .nav__toggle { display: inline-flex; }
  .nav {
    position: absolute;
    inset-inline: 0;
    top: 100%;
    background: var(--ink-800);
    border-bottom: 1px solid var(--chrome-line);
    box-shadow: var(--shadow-lg);
    display: none;
  }
  .nav[data-open="true"] { display: block; }
  .nav__list {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: var(--sp-3) 0 var(--sp-5);
    width: min(100% - 2 * var(--sp-5), var(--wrap));
    margin-inline: auto;
  }
  .nav__link { padding: var(--sp-3); border-radius: var(--radius); font-size: var(--step-0); }
  .nav__link[aria-current="page"] { box-shadow: inset 3px 0 0 var(--accent-glow); }}

/* ---------------------------------------------------------------- 5. hero */

.hero {
  position: relative;
  display: grid;
  align-content: center;
  /* The banner is attached to the viewport (see .hero__media), so the photo is
     sized to the window. If the hero kept a fixed height it would frame a
     smaller and smaller slice of that photo as the window grew — on a tall
     monitor the group disappeared entirely and only the planting was left.
     Sizing the hero in vh keeps the slice proportional, so the same part of
     the photograph shows on a laptop and on a large display. */
  min-height: 62vh;
  background: var(--ink-900);
  color: var(--text-inverse);
  overflow: hidden;
  isolation: isolate;
}
/* The banner photograph. `fixed` attaches it to the viewport rather than to the
   page, so it stays put and the hero acts as a window onto it while everything
   scrolls over the top. The background is still clipped to this element's box,
   which is what makes this safe — a fixed <img> would not be, and would show
   through every transparent band further down the page.

   Because it is attached to the viewport, `cover` sizes the photo against the
   window rather than against the hero, so the crop is set here and not on the
   image. To change the banner, change this one URL — it is relative to this
   stylesheet, in assets/css/, not to the page. */
.hero__media {
  position: absolute;
  inset: 0;
  z-index: -2;
  background-image: url(../../img/group/group_photos/2026-08-26.webp);
  background-attachment: fixed;
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
}
/* iOS Safari does not honour `fixed` here and scrolls the photo as it always
   did, which is a fair degradation rather than a break. */
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  /* Dark enough for white text on the left, lighter on the right so the
     group photo is actually visible. */
  background:
    linear-gradient(100deg, rgb(11 14 20 / 93%) 0%, rgb(11 14 20 / 80%) 42%,
                    rgb(11 14 20 / 42%) 100%),
    linear-gradient(180deg, rgb(11 14 20 / 45%) 0%, transparent 35%,
                    rgb(11 14 20 / 72%) 100%),
    radial-gradient(70% 90% at 12% 0%, rgb(21 128 61 / 48%) 0%, transparent 65%);
}
.hero__inner { padding-block: clamp(var(--sp-7), 8vw, 5.5rem); }
.hero h1 { font-size: var(--step-5); max-width: 17ch; margin-bottom: var(--sp-4); color: var(--text-inverse); }
.hero h1 em { font-style: italic; color: var(--accent-glow); }
.hero__actions { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-top: var(--sp-6); }

/* Compact head for interior pages */
.pagehead {
  position: relative;
  padding-block: calc(var(--section-y) * 1.15);
  background:
    radial-gradient(60% 120% at 8% 0%, rgb(21 128 61 / 30%) 0%, transparent 60%),
    var(--ink-900);
  color: var(--text-inverse);
}
.pagehead h1 { color: var(--text-inverse); max-width: 20ch; }
.pagehead p { max-width: 58ch; color: var(--text-inverse-soft); font-size: var(--step-1); }
.pagehead .eyebrow { color: var(--accent-glow); }
.pagehead .eyebrow::before { background: var(--accent-glow); }

/* -------------------------------------------------------------- 6. button */

.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 0.7rem 1.15rem;
  border: 1px solid transparent;
  border-radius: var(--radius);
  font-family: var(--font-body);
  font-size: var(--step--1);
  font-weight: 600;
  line-height: var(--lh-flat);
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease),
              transform var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(0); }

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

.btn--ghost {
  background: var(--chrome-fill);
  border-color: var(--chrome-line-strong);
  color: var(--text-inverse);
  backdrop-filter: blur(6px);
}
.btn--ghost:hover { background: var(--chrome-fill-hover); color: var(--text-inverse); }

.btn--outline { border-color: var(--border-strong); color: var(--text); background: var(--bg-raised); }
.btn--outline:hover { border-color: var(--accent); color: var(--accent-ink); }

.btn--sm { padding: 0.45rem 0.8rem; font-size: var(--step--1); }

/* --------------------------------------------------------------- 7. cards */

.grid { display: grid; gap: var(--sp-4); }
.grid--3 { grid-template-columns: repeat(auto-fill, minmax(min(100%, 19rem), 1fr)); }
.grid--4 { grid-template-columns: repeat(auto-fill, minmax(min(100%, 14rem), 1fr)); }

/* Cards and person tiles are the same object: a bordered, rounded surface
   that lifts on hover. One rule, two names. */
.card,
.person {
  display: flex;
  flex-direction: column;
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.card:hover,
.person:hover { border-color: var(--border-strong); box-shadow: var(--shadow-md); }
.card__media {
  position: relative;
  aspect-ratio: 16 / 10;
  background: var(--bg-sunken);
  border-bottom: 1px solid var(--border);
  overflow: hidden;
}
.card__media img, .card__media video {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform var(--dur-slow) var(--ease);
}
.card:hover .card__media img { transform: scale(1.03); }
.card__body {
  padding: var(--sp-5);
  display: flex; flex-direction: column; gap: var(--sp-3);
  flex: 1;
}
.card__meta {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-3);
  font-size: var(--step--1); color: var(--text-faint);
}
.card__title { font-size: var(--step-1); margin: 0; }
.card__title a { color: var(--text); text-decoration: none; }
.card__title a:hover { color: var(--accent-ink); }
.card__text { color: var(--text-soft); font-size: var(--step--1); }
.card__text > :last-child { margin-bottom: 0; }

/* Category chips */
.chip {
  display: inline-flex;
  align-items: center;
  padding: 0.18rem 0.6rem;
  border-radius: var(--radius-pill);
  font-size: var(--step--2);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  background: var(--c-news-bg);
  color: var(--c-news-fg);
  white-space: nowrap;
}
.chip--paper { background: var(--c-paper-bg); color: var(--c-paper-fg); }
.chip--preprint { background: var(--c-preprint-bg); color: var(--c-preprint-fg); }
.chip--group { background: var(--c-group-bg); color: var(--c-group-fg); }
.chip--event { background: var(--c-event-bg); color: var(--c-event-fg); }
.chip--funding { background: var(--c-funding-bg); color: var(--c-funding-fg); }
.chip--positions { background: var(--c-positions-bg); color: var(--c-positions-fg); }

/* ----------------------------------------------------------- 8. news feed */

.newsfeed { display: flex; flex-direction: column; }

.newsitem {
  display: grid;
  grid-template-columns: 9rem 1fr;
  gap: var(--sp-5);
  padding-block: var(--row-y);
  border-top: 1px solid var(--border);
}
.newsitem:last-child { border-bottom: 1px solid var(--border); }
.newsitem[hidden] { display: none; }
.newsitem__aside { display: flex; flex-direction: column; gap: var(--sp-2); align-items: flex-start; }
.newsitem__date {
  font-family: var(--font-mono);
  font-size: var(--step--1);
  font-weight: 500;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.newsitem__body > :last-child { margin-bottom: 0; }
.newsitem__media { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-top: var(--sp-3); }
.newsitem__media figure { margin: 0; }
.newsitem__media img, .newsitem__media video {
  height: 12rem;
  width: auto;
  max-width: 100%;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  object-fit: cover;
}
.newsitem__media figcaption {
  margin-top: var(--sp-2);
  font-size: var(--step--2);
  color: var(--text-faint);
  max-width: 22rem;
}

@media (max-width: 44rem) {
  .newsitem { grid-template-columns: 1fr; gap: var(--sp-3); }
  .newsitem__aside { flex-direction: row; align-items: center; gap: var(--sp-3); }
  .newsitem__media img, .newsitem__media video { height: 9rem; }}

/* Filter bar */
.filters { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-bottom: var(--sp-5); }
.filter {
  padding: 0.35rem 0.8rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--bg-raised);
  color: var(--text-soft);
  font: inherit;
  font-size: var(--step--1);
  font-weight: 500;
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease),
              color var(--dur-fast) var(--ease);
}
.filter:hover { border-color: var(--border-strong); color: var(--text); }
.filter[aria-pressed="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-contrast);
}

/* -------------------------------------------------------------- 9. people */

.person__photo { aspect-ratio: 1; background: var(--bg-sunken); overflow: hidden; }
.person__photo img { width: 100%; height: 100%; object-fit: cover; object-position: center 18%; }
.person__photo--empty {
  display: grid;
  place-items: center;
  font-family: var(--font-display);
  font-size: var(--step-4);
  font-weight: 700;
  color: var(--accent);
  background: var(--accent-soft);
}
.person__body {
  padding: var(--sp-4) var(--sp-4) var(--sp-5);
  display: flex; flex-direction: column; gap: var(--sp-2);
  flex: 1;
}
.person__name { font-size: var(--step-1); margin: 0; }
.person__years {
  font-family: var(--font-mono);
  font-size: var(--step--2);
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}
.person__bio { font-size: var(--step--1); color: var(--text-soft); }
.person__bio p { margin-bottom: var(--sp-3); }
.person__links { margin-top: auto; padding-top: var(--sp-3); }

details.person__more > summary {
  cursor: pointer;
  font-size: var(--step--1);
  font-weight: 600;
  color: var(--accent-ink);
  list-style: none;
  padding: var(--sp-1) 0;
}
details.person__more > summary::-webkit-details-marker { display: none; }
details.person__more > summary::after { content: " \2193"; }
details.person__more[open] > summary::after { content: " \2191"; }
details.person__more[open] > summary { margin-bottom: var(--sp-2); }

.role-head {
  display: flex;
  align-items: baseline;
  gap: var(--sp-3);
  margin: var(--sp-6) 0 var(--sp-3);
}
.role-head:first-child { margin-top: 0; }
.role-head h3 { margin: 0; font-size: var(--step-1); }
.role-head::after { content: ""; flex: 1; height: 1px; background: var(--border); }
.role-head .count { font-family: var(--font-mono); font-size: var(--step--2); color: var(--text-faint); }

/* The alumni band is a <details> that starts shut, so the whole section head
   is the control. It has to read as clickable without looking like a button
   glued under a heading, so the affordance lives in the pill on the right and
   the head itself only shifts colour on hover. */
.alumni__summary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  cursor: pointer;
  list-style: none;
  border-radius: var(--radius);
}
.alumni__summary::-webkit-details-marker { display: none; }
/* The head carries its own bottom margin for the un-collapsed sections; inside
   a summary the flex gap already spaces it. */
.alumni__summary .section-head { margin-bottom: 0; }
.alumni__summary h2 { transition: color var(--dur-fast) var(--ease); }
.alumni__summary:hover h2 { color: var(--accent-ink); }

.alumni__toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 0.45rem 0.8rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--bg-raised);
  font-size: var(--step--1);
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
  transition: border-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.alumni__summary:hover .alumni__toggle { border-color: var(--accent); color: var(--accent-ink); }
.alumni__toggle::after {
  content: "";
  width: 0.45em; height: 0.45em;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: translateY(-0.15em) rotate(45deg);
  transition: transform var(--dur-fast) var(--ease);
}
.alumni[open] .alumni__toggle::after { transform: translateY(0.1em) rotate(-135deg); }

/* Both labels are in the markup and CSS shows one, so the state is real text a
   screen reader can read, not generated ::after content. */
.alumni__label--open,
.alumni[open] .alumni__label--shut { display: none; }
.alumni[open] .alumni__label--open { display: inline; }

.alumni__body { margin-top: var(--sp-5); }

/* ------------------------------------------------------- 10. publications */

.pub {
  display: grid;
  /* The graphic is capped by height, not width, so the column has to be wide
     enough for a typical 2:1 table-of-contents figure to reach that height.
     Nine rem was showing them at roughly half the size the old site did. */
  grid-template-columns: minmax(0, 1fr) clamp(11rem, 19vw, 17rem);
  gap: var(--sp-5);
  padding-block: var(--row-y);
  border-top: 1px solid var(--border);
  align-items: start;
}
.pub:last-child { border-bottom: 1px solid var(--border); }
.pub__num { font-family: var(--font-mono); font-size: var(--step--2); color: var(--accent); font-weight: 600; }
.pub__title { font-size: var(--step-0); margin: 0.1rem 0 0.3rem; line-height: var(--lh-snug); }
.pub__title a { color: var(--text); text-decoration: none; }
.pub__title a:hover { color: var(--accent-ink); text-decoration: underline; }
.pub__authors { font-size: var(--step--1); color: var(--text-soft); margin-bottom: 0.25rem; }
.pub__authors u {
  text-decoration: none;
  font-weight: 700;
  color: var(--text);
  box-shadow: inset 0 -0.4em 0 var(--accent-soft);
}
.pub__cite { font-size: var(--step--1); color: var(--text-faint); }
.pub__cite i { color: var(--text-soft); font-style: italic; }

/* The compact list used on the homepage: the same publication type as the full
   list above, without the TOC column or the numbering. */
.publist { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.publist__item { padding-block: var(--row-y); border-top: 1px solid var(--border); }
.publist__item .pub__title { margin: 0 0 0.35rem; }
.publist__item .pub__cite { margin: 0; }
.pub__toc {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--panel);
  padding: var(--sp-2);
  overflow: hidden;
}
/* Height-capped and auto-width, as on the old site, so a wide graphic fills
   the column and a squarer one is not stretched to match it. */
.pub__toc img {
  display: block;
  margin-inline: auto;
  max-width: 100%;
  max-height: 10rem;
  width: auto;
  height: auto;
}

@media (max-width: 48rem) {
  .pub { grid-template-columns: 1fr; }
  .pub__toc { max-width: 17rem; order: -1; }}

.year-head {
  position: sticky;
  top: var(--header-h);
  z-index: var(--z-sticky);
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin: var(--sp-5) 0 0;
  padding-block: var(--sp-2);
  background: var(--bg);
  font-family: var(--font-display);
  font-size: var(--step-2);
  font-weight: 700;
}
.year-head::after { content: ""; flex: 1; height: 2px; background: var(--accent-soft); }

/* ------------------------------------------------ 11. composition helpers */

.logo-row { display: flex; flex-wrap: wrap; gap: var(--sp-6); align-items: center; justify-content: center; }
.logo-row img { max-height: 4.5rem; width: auto; }

.split {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 24rem), 1fr));
  gap: var(--sp-7);
  align-items: start;
}

.lead { font-size: var(--step-1); line-height: var(--lh-prose); color: var(--text-soft); }

/* ------------------------------------------------------------- 12. footer */

.site-footer {
  background: var(--ink-900);
  color: var(--text-inverse-soft);
  padding-block: var(--sp-6) var(--sp-4);
  margin-top: var(--sp-6);
  font-size: var(--step--1);
}
.site-footer a { color: var(--text-inverse-soft); text-decoration: none; }
.site-footer a:hover { color: var(--text-inverse); text-decoration: underline; }
.site-footer h2 {
  font-size: var(--step--2);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent-glow);
  margin-bottom: var(--sp-3);
}
.footer__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  gap: var(--sp-6);
  padding-bottom: var(--sp-6);
}
.footer__grid p { margin-bottom: var(--sp-2); line-height: var(--lh-prose); }
/* Each column is a flex column so the wordmark, which sits last in the first
   of them, can take `margin-top: auto` and drop to the foot of the row. Grid
   items stretch to the tallest column, so that lands its bottom edge level
   with the last link in the Site list. */
.footer__grid > * { display: flex; flex-direction: column; }
.footer__grid > * > :last-child { margin-bottom: 0; }
.footer__logo { margin: auto 0 0; padding-top: var(--sp-4); }
.footer__logo img {
  /* Block, not inline: an inline image sits on the baseline and leaves a
     descender's worth of space below it, which would drop the wordmark clear
     of the line it is meant to finish level with. */
  display: block;
  width: 11rem;
  max-width: 100%;
  height: auto;
  opacity: 0.92;
}

.footer__bottom {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
  justify-content: space-between;
  align-items: center;
  padding-top: var(--sp-5);
  border-top: 1px solid var(--chrome-line);
  font-size: var(--step--2);
  color: var(--text-inverse-faint);
}
.social {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: 0.45rem 0.85rem;
  background: var(--chrome-fill);
  border: 1px solid var(--chrome-line);
  border-radius: var(--radius-pill);
  font-weight: 500;
  text-decoration: none;
}
.social:hover { background: var(--chrome-fill-hover); }
.social svg { width: 1em; height: 1em; flex: none; }

.kv { display: grid; grid-template-columns: auto 1fr; gap: var(--sp-1) var(--sp-3); margin: 0; }
.kv dt { color: var(--accent-glow); font-weight: 600; font-size: var(--step--2); }
.kv dd { margin: 0; }

/* Theme toggle */
.theme-toggle {
  display: inline-grid;
  place-items: center;
  width: 2.1rem; height: 2.1rem;
  background: var(--chrome-fill);
  border: 1px solid var(--chrome-line);
  border-radius: var(--radius);
  color: var(--text-inverse);
  cursor: pointer;
  flex: none;
}
.theme-toggle:hover { background: var(--chrome-fill-hover); }
.theme-toggle svg { width: 1.05rem; height: 1.05rem; }
.theme-toggle .icon-sun { display: none; }
:root[data-theme="dark"] .theme-toggle .icon-sun { display: block; }
:root[data-theme="dark"] .theme-toggle .icon-moon { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .icon-sun { display: block; }
  :root:not([data-theme="light"]) .theme-toggle .icon-moon { display: none; }}

/* ------------------------------------------------------- 13. prose pages */

/* Research, Facilities, Positions and Dr Goodwin. Each is its own template in
   src/, with its own layout, so what follows is grouped by page rather than by
   a shared block system. Only the small pieces below the page sections —
   .prose--lead, .sec-title, .block__cta — are shared between them. */

/* An opening paragraph or two, set larger than body copy. Every paragraph in
   the group, not only the first: `ch` scales with font size, so a larger
   opening paragraph above a smaller one would wrap at two different widths and
   leave a visible step down the right-hand edge. */
.prose--lead > p {
  font-size: var(--step-1);
  line-height: var(--lh-prose);
}

/* A section heading that carries a short accent rule instead of an eyebrow —
   the same signal for a fraction of the ink, and no extra words. */
.sec-title {
  margin: 0 0 var(--sp-4);
  font-size: var(--step-2);
  line-height: var(--lh-heading);
  text-wrap: balance;
}
.sec-title::before {
  content: "";
  display: block;
  width: 2.25rem;
  height: 2px;
  margin-bottom: var(--sp-4);
  border-radius: 2px;
  background: var(--accent);
}
/* Repeated down one page — the three CV tables — each needs air above it to
   separate one run of rows from the next. */
.record .sec-title + .cv { margin-bottom: var(--sp-7); }
.record .cv + .sec-title { margin-top: var(--sp-7); }

.block__cta { margin-top: var(--sp-4); }
/* A button that opens a band has nothing above it to be spaced from. */
.cta-band { margin: 0; }

.prose .note { color: var(--text-soft); font-style: italic; }
.prose li::marker { color: var(--accent); }

/* -- research ------------------------------------------------------------ */

/* Each research thread is a band of its own: several paragraphs and a list of
   papers, which is more than a column in a three-across grid can hold without
   becoming a wall of small text. */
.thread__grid { padding-block: var(--section-y); }
.thread + .thread .thread__grid { border-top: 1px solid var(--border); }
.thread__body > h2 {
  margin: 0 0 var(--sp-4);
  font-size: var(--step-2);
  line-height: var(--lh-heading);
  text-wrap: balance;
}
.thread__body > p { max-width: var(--measure); }

@media (min-width: 62rem) {
  .thread__grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 24rem;
    column-gap: var(--sp-7);
    align-items: start;
  }
  /* The figures swap sides down the page, so the threads read as three
     separate things rather than one long article. Placement, not `order`:
     `order` would move the figures into the wide column and push the prose
     into the 24rem rail, which is the opposite of what is wanted. */
  .thread--flip .thread__grid { grid-template-columns: 24rem minmax(0, 1fr); }
  .thread--flip .thread__body { grid-area: 1 / 2; }
  .thread--flip .thread__figs { grid-area: 1 / 1; }
}

/* Stacked, never side by side. These are molecular structures and reaction
   schemes: half a rail each is not enough width to read one. */
.thread__figs {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--sp-3);
  margin-bottom: var(--sp-5);
}
@media (min-width: 62rem) {
  .thread__figs { margin-bottom: 0; }
}

/* A fixed frame with the image contained inside it. The structures, the
   crystal photographs and the wide reaction scheme have nothing like the same
   proportions, and this is what lets them share a grid without any of them
   being cropped, stretched, or given a hand-set height. */
.thread__fig,
.kit__fig {
  margin: 0;
  display: grid;
  place-items: center;
  aspect-ratio: 4 / 3;
  padding: var(--sp-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}
/* Structures and schemes are line art drawn on white, so they sit on the light
   plate. Laboratory photographs are not — on the plate they would be framed in
   a white matte that reads as part of the picture. */
.thread__fig { background: var(--panel); }
.kit__fig { background: var(--bg-raised); }
.thread__fig img,
.kit__fig img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
}

.thread__papers { margin-top: var(--sp-5); }
.thread__papers-head {
  margin: 0 0 var(--sp-2);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
}

/* Names, not sentences: a grid reads them at a glance where a bulleted list
   runs them down the page in a single thin strip. */
.namegrid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 16rem), 1fr));
  gap: var(--sp-2) var(--sp-5);
}
.namegrid li {
  padding-block: var(--sp-2);
  border-top: 1px solid var(--border);
  font-size: var(--step--1);
  color: var(--text-soft);
}

/* -- facilities ---------------------------------------------------------- */

/* A tour of a room, so the photographs lead and the text explains them. Each
   piece of kit is one card: its pictures on top, its description below. */
.kit {
  display: grid;
  gap: var(--sp-6);
  align-items: start;
}
@media (min-width: 48rem) {
  .kit--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 62rem) {
  .kit--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.kit__figs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 9rem), 1fr));
  gap: var(--sp-2);
  margin-bottom: var(--sp-4);
}
/* Six small items — the Dewar, fridge, freezer and three ovens — read better
   as a tight block of thumbnails than as six full-size frames. */
.kit__figs--dense { grid-template-columns: repeat(3, minmax(0, 1fr)); }
/* The gloveboxes are the centrepiece of the room, so they take the full width
   rather than sitting in a card in a row. */
.kit__figs--wide {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
  gap: var(--sp-4);
  margin-bottom: var(--sp-5);
}
.kit__figs--wide .kit__fig { aspect-ratio: 3 / 2; }

.kit__body > h3 {
  margin: 0 0 var(--sp-3);
  font-size: var(--step-1);
  line-height: var(--lh-flat);
  text-wrap: balance;
}
.kit__body > p { color: var(--text-soft); }

/* -- positions ----------------------------------------------------------- */

/* The three routes are a career sequence, not three equivalent options, so
   they run down the page in order rather than side by side. */
.route__grid { padding-block: var(--section-y); }
.route + .route .route__grid { border-top: 1px solid var(--border); }

@media (min-width: 62rem) {
  .route__grid {
    display: grid;
    grid-template-columns: 16rem minmax(0, 1fr);
    column-gap: var(--sp-7);
    align-items: start;
  }
  /* The sections are long, so the heading follows you down its own one and it
     stays obvious which route you are reading. */
  .route__rail { position: sticky; top: calc(var(--header-h) + var(--sp-5)); }
}

.route__title {
  margin: 0 0 var(--sp-4);
  font-size: var(--step-2);
  line-height: var(--lh-heading);
  text-wrap: balance;
}
.route__title::before {
  content: "";
  display: block;
  width: 2.25rem;
  height: 2px;
  margin-bottom: var(--sp-4);
  border-radius: 2px;
  background: var(--accent);
}
@media (min-width: 62rem) {
  .route__title { margin-bottom: 0; }
}

/* Funding routes are things to go and look at, so they are rows to scan, not
   prose to read. */
.fundlist {
  list-style: none;
  margin: var(--sp-5) 0 0;
  padding: 0;
  border-top: 1px solid var(--border);
}
.fundlist li {
  padding-block: var(--row-y);
  border-bottom: 1px solid var(--border);
  font-size: var(--step--1);
  color: var(--text-soft);
  max-width: var(--measure);
}

/* -- Dr Goodwin ---------------------------------------------------------- */

/* Source order is portrait, biography, links. On a wide screen the links move
   back up beside the biography, under the portrait, by explicit grid placement
   — so the visual order changes without the reading order following it. */
.profile { display: grid; gap: var(--sp-6); align-items: start; }
@media (min-width: 62rem) {
  .profile {
    grid-template-columns: 20rem minmax(0, 1fr);
    grid-template-rows: auto 1fr;
    column-gap: var(--sp-7);
    row-gap: var(--sp-5);
  }
  .profile__portrait { grid-area: 1 / 1; }
  .profile__links    { grid-area: 2 / 1; }
  .profile__bio      { grid-area: 1 / 2 / span 2; }
}

.profile__portrait {
  margin: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--bg-raised);
  box-shadow: var(--shadow-sm);
}
.profile__portrait img { display: block; width: 100%; height: auto; }

.profile__links-head {
  margin: 0 0 var(--sp-3);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.linklist { list-style: none; margin: 0; padding: 0; }
.linklist li {
  padding-block: var(--sp-2);
  border-top: 1px solid var(--border);
  font-size: var(--step--1);
  color: var(--text-soft);
}

/* Date/description tables for the CV listings. */
.cv {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--step--1);
}
.cv th,
.cv td {
  padding: var(--row-y) var(--sp-3) var(--row-y) 0;
  border-top: 1px solid var(--border);
  vertical-align: baseline;
  text-align: left;
  transition: background-color var(--dur-fast) var(--ease);
}
.cv th {
  width: 8rem;
  white-space: nowrap;
  font-family: var(--font-mono);
  font-size: var(--step--2);
  font-weight: 500;
  color: var(--text-soft);
  font-variant-numeric: tabular-nums;
}
/* A whole-row tint makes a long list of dates easier to read across. */
.cv tbody tr:hover :is(th, td) { background: var(--bg-sunken); }
.cv__logo { width: 6rem; text-align: right; }
.cv__logo img { max-height: 2rem; max-width: 100%; width: auto; vertical-align: middle; }

@media (max-width: 40rem) {
  .cv th { width: 5.5rem; white-space: normal; }}


/* -------------------------------------------------------------- 14. print */

@media print {
  .site-header, .site-footer, .filters, .skip-link, .theme-toggle, .hero__actions {
    display: none !important;
  }
  body { color: #000; background: #fff; font-size: 11pt; }
  a { color: #000; text-decoration: underline; }
  .pub, .newsitem, .person { break-inside: avoid; }
}