/* Nihal Singh — v7 "Paper".
   Warm paper, navy ink, one brick accent. Newsreader (one weight, 300) for display,
   Geist for reading, Geist Mono for labels. One 12-column grid; desktop splits are 5 + 7. */

:root {
  color-scheme: light;

  /* Palette — warm paper, navy ink, slate, one brick accent */
  --paper: #f7f4ee;
  --panel: #efeae1;
  --ink: #0e1b2e;
  --ink-soft: #243047;
  --muted: #4b5870;
  --spin: #7e8aa1;     /* up-spins in Fig. 1 (the apps' light slate); down-spins are bare paper */
  --spin-r: 0.24;      /* up-spin dot radius, as a fraction of one lattice cell */
  --rule: #d8d2c6;
  --accent: #b72c26;
  --select: #ecd0ca;
  /* What I offer: one tint per layer, lightest (AI/ML) to deepest (Devices) */
  --layer-1: #f3efe7;
  --layer-2: #efeae1;
  --layer-3: #ebe5da;
  --layer-4: #e7e0d3;
  --layer-5: #e2dacb;

  --serif: "Newsreader", "Iowan Old Style", "Palatino Linotype", Georgia, serif;
  --sans: "Geist", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono: "Geist Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  /* Type scale: 12 · 15 · 17 · 22 · 30 · 48 · name (px at desktop).
     The name is also capped by viewport height, so the CV button stays in the first screen on laptops. */
  --fs-hero: min(clamp(4.25rem, 2.4rem + 7.4vw, 8.5rem), 15vh);
  --fs-h2: clamp(2.125rem, 1.6rem + 1.6vw, 3rem);
  --fs-lg: clamp(1.5rem, 1.3rem + 0.75vw, 1.875rem);
  --fs-md: clamp(1.25rem, 1.18rem + 0.3vw, 1.375rem);
  --fs-body: 1.0625rem;
  --fs-sm: 0.9375rem;
  --fs-xs: 0.75rem;

  /* Space — 8px rhythm */
  --s1: 0.5rem;
  --s2: 1rem;
  --s3: 1.5rem;
  --s4: 2rem;
  --s5: 3rem;
  --s6: 4rem;
  --section-top: clamp(2.25rem, 1.5rem + 2.5vw, 4rem);
  --section: clamp(3rem, 1.5rem + 4.5vw, 6rem);
  --h2-gap: clamp(1.5rem, 0.75rem + 2.5vw, 3rem);

  /* Layout — one container, one 12-column grid */
  --max: 76rem;
  --gutter: clamp(1rem, 4vw, 3rem);
  --gap: clamp(1rem, 0.5rem + 1.6vw, 2rem);
  --radius: 4px;
  --bleed: clamp(0.5rem, 2vw, 1.25rem);   /* how far tinted bands and hover tiles reach past their text */
  --target: 1.75rem;   /* minimum height of small text links; 44px on touch screens */
}

@media (pointer: coarse) {
  :root { --target: 2.75rem; }
}

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

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

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--fs-body);
  line-height: 1.65;
  font-optical-sizing: auto;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img { display: block; max-width: 100%; height: auto; }
a { color: inherit; }
::selection { background: var(--select); color: var(--ink); }

/* Line breaks: balanced headings; no lone last word in running text. */
h1, h2, h3 { text-wrap: balance; }
p, li, dd, figcaption { text-wrap: pretty; }

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

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

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

/* Inline SVG icons (arrows, pause, play): 1em, drawn in the text colour. */
.i {
  flex: none;
  width: 1em;
  height: 1em;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.4;
  stroke-linecap: round;
  stroke-linejoin: round;
  vertical-align: -0.125em;
  transition: transform 0.2s ease, color 0.2s ease;
}

.nowrap { white-space: nowrap; }

.skip {
  position: absolute;
  top: 0;
  left: max(var(--gutter), (100% - var(--max)) / 2);
  z-index: 10;
  padding: 0.625rem 0.875rem;
  border-radius: var(--radius);
  background: var(--ink);
  color: var(--paper);
  font: 500 var(--fs-sm) / 1 var(--sans);
  text-decoration: none;
  transform: translateY(-150%);
}
.skip:focus { transform: translateY(1rem); }

/* ---------- Container ---------- */
.site-header,
.hero,
.section,
.elsewhere,
.site-footer {
  width: min(100% - 2 * var(--gutter), var(--max));
  margin-inline: auto;
}

/* ---------- Shared text styles ---------- */
.h2 {
  margin: 0 0 var(--h2-gap);
  font-family: var(--serif);
  font-size: var(--fs-h2);
  font-weight: 300;
  line-height: 1.04;
  letter-spacing: -0.02em;
  text-wrap: balance;
}
.h2:has(+ .deck) { margin-bottom: var(--s2); }

.deck {
  max-width: 44rem;
  margin: 0 0 var(--h2-gap);
  color: var(--muted);
  text-wrap: balance;
}

.label {
  margin: 0 0 var(--s2);
  font: 400 var(--fs-xs) / 1.4 var(--mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}

/* Hairline rows: a rule above the list and between rows, none after the last row
   (the next section's rule closes it, so rules never double up). */
.rows {
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--rule);
}
.rows > li,
.rows > div {
  padding-block: 0.625rem;
  border-bottom: 1px solid var(--rule);
}
.rows > :last-child { border-bottom: 0; padding-bottom: 0; }

/* Focus areas: with a mouse, the hovered row rises as a soft paper plate, the same way the What I offer
   layers do. The plate sits behind the row, covers its hairlines and reaches a little past the text. */
.focus .rows > li {
  position: relative;
  isolation: isolate;
  transition: transform 0.25s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.focus .rows > li::before {
  content: "";
  position: absolute;
  inset: -1px calc(-1 * var(--bleed));
  z-index: -1;
  border-radius: var(--radius);
  background: var(--layer-3);
  opacity: 0;
  transition: opacity 0.25s ease, box-shadow 0.25s ease;
}
.focus .rows > li:last-child::before { bottom: -0.625rem; }   /* the last row has no bottom padding */

/* Quiet text links: muted, hairline underline, brick on hover. Tall enough to tap. */
.quiet-links a,
.more a,
.elsewhere a,
.site-footer a {
  display: inline-flex;
  align-items: center;
  gap: 0.375em;
  min-height: var(--target);
  color: var(--muted);
  text-decoration: underline;
  text-decoration-color: var(--rule);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.3em;
  transition: color 0.2s ease, text-decoration-color 0.2s ease;
}

/* ---------- Header ---------- */
.site-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0 var(--s4);
  padding-top: clamp(0.75rem, 3.5vh - 0.25rem, 1.75rem);
}

.wordmark {
  display: inline-flex;
  align-items: center;
  min-height: var(--target);
  font-family: var(--serif);
  font-size: var(--fs-md);
  font-weight: 300;
  line-height: 1;
  letter-spacing: -0.01em;
  text-decoration: none;
  transition: color 0.2s ease;
}

/* On the homepage the nav is the header's only item (the hero name sits just below), so it keeps itself to the right. */
.nav { margin-left: auto; }

.nav ul {
  display: flex;
  flex-wrap: wrap;
  column-gap: clamp(1rem, 0.2rem + 2.4vw, 2rem);
  margin: 0;
  padding: 0;
  list-style: none;
}
.nav a {
  display: inline-flex;
  align-items: center;
  min-height: max(var(--target), 2rem);
  font: 400 var(--fs-xs) / 1 var(--mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--muted);
  transition: color 0.2s ease;
}

/* Phones: the nav gets its own full-width row. */
@media (max-width: 31.99rem) {
  .nav { flex: 1 1 100%; }
}
/* The four links sit in one row where they fit (368px and up); narrower phones get two rows of two. */
@media (max-width: 31.99rem) {
  .nav ul {
    display: grid;
    grid-template-columns: repeat(2, auto);
    justify-content: space-between;
  }
  .nav a { white-space: nowrap; }
}
@media (min-width: 23rem) and (max-width: 31.99rem) {
  .nav ul {
    grid-template-columns: repeat(4, auto);
    column-gap: 0.75rem;
  }
}

/* ---------- Hero ---------- */
.hero {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gap);
  row-gap: clamp(2rem, 1rem + 3vw, 3rem);
  padding-block: clamp(1.5rem, 6vh - 0.75rem, 4rem) clamp(2.5rem, 1.5rem + 4vw, 5rem);
}
.hero-copy,
.hero-fig { grid-column: 1 / -1; min-width: 0; }

.hero-name {
  margin: 0 0 clamp(1rem, 3.2vh, 2rem) -0.035em;
  font-family: var(--serif);
  font-size: var(--fs-hero);
  font-weight: 300;
  line-height: 0.9;
  letter-spacing: -0.03em;
}
.hero-name span { display: block; }

.hero-role {
  margin: 0 0 0.375rem;
  font-family: var(--serif);
  font-size: var(--fs-lg);
  font-weight: 300;
  line-height: 1.2;
  letter-spacing: -0.01em;
  text-wrap: balance;
}

.hero-cred {
  margin: 0 0 var(--s3);
  font-size: var(--fs-sm);
  line-height: 1.5;
  color: var(--ink-soft);
  text-wrap: balance;
}
.hero-cred strong { font-weight: 500; color: var(--ink); }
.sep { margin-inline: 0.2em; color: var(--muted); }

.hero-lede {
  max-width: 31rem;
  margin: 0;
  color: var(--ink-soft);
  text-wrap: pretty;
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s2) var(--s4);
  margin-top: clamp(1.5rem, 4.5vh - 0.25rem, 2.5rem);
}

.button {
  display: inline-flex;
  align-items: center;
  gap: 0.625rem;
  min-height: 3rem;
  padding: 0 1.375rem;
  border-radius: var(--radius);
  background: var(--ink);
  color: var(--paper);
  font: 500 var(--fs-sm) / 1 var(--sans);
  text-decoration: none;
  transition: background-color 0.2s ease;
}

.quiet-links {
  display: flex;
  flex-wrap: wrap;
  column-gap: 1.25rem;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--fs-sm);
}

/* Fig. 1 — the live p-bit lattice: lattice on top, caption below; the pause control sits on the
   caption's first line, so the caption text can use the full width. */
.hero-fig {
  display: grid;
  grid-template-rows: auto auto;
  margin: 0;
}

/* Soft-edged plate: two linear fades intersected, so the lattice dissolves into the paper. */
.lattice {
  position: relative;
  aspect-ratio: 2 / 1;
  --fade: linear-gradient(90deg, transparent, #000 14%, #000 86%, transparent),
          linear-gradient(180deg, transparent, #000 14%, #000 86%, transparent);
  -webkit-mask-image: var(--fade);
  -webkit-mask-composite: source-in;
  mask-image: var(--fade);
  mask-composite: intersect;
}
.lattice canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transition: opacity 0.6s ease;
}
/* Hidden only while the script burns the lattice in, then faded in. A stale or missing script never hides it. */
.lattice canvas.is-warming { opacity: 0; }

.caption {
  margin-top: 0.75rem;
  font: 400 var(--fs-xs) / 1.6 var(--mono);
  color: var(--muted);
}
.caption-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s2);
  margin-bottom: 0.25rem;
}
.caption-state {
  margin: 0;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.caption-state .sep { margin-inline: 0.35em; }
.fig-no { color: var(--ink); }
.caption-text { max-width: 72ch; margin: 0; text-wrap: pretty; }

.fig-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: max(var(--target), 2rem);
  padding: 0 0.75rem;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: transparent;
  color: var(--ink);
  font: 400 var(--fs-xs) / 1 var(--mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  cursor: pointer;
  transition: border-color 0.2s ease, color 0.2s ease;
}
.fig-toggle[hidden] { display: none; }
.fig-toggle .i { width: 0.75rem; height: 0.75rem; }
.fig-toggle .i-play,
.fig-toggle.is-paused .i-pause { display: none; }
.fig-toggle.is-paused .i-play { display: inline; }

/* ---------- Sections ---------- */
.section {
  padding-block: var(--section-top) var(--section);
  border-top: 1px solid var(--rule);
}

/* About */
.about { display: flow-root; }
.portrait {
  float: right;
  width: clamp(5.5rem, 24vw, 10rem);
  margin: 0.375rem 0 var(--s2) var(--s3);
}
.portrait img {
  width: 100%;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--panel);
}
.prose { color: var(--ink-soft); }
.prose p {
  max-width: 38rem;
  margin: 0 0 1em;
}
.prose p:last-child { margin-bottom: 0; }
.prose strong { font-weight: 500; color: var(--ink); }

.about-meta {
  display: grid;
  gap: var(--s5);
  margin-top: var(--s5);
}

.edu-rows > div {
  display: grid;
  row-gap: 0.125rem;
  align-items: baseline;
}
.edu-rows dt {
  font-family: var(--serif);
  font-size: var(--fs-md);
  font-weight: 300;
  line-height: 1.3;
}
.edu-rows dd { margin: 0; }
.edu-school {
  display: block;
  font-size: var(--fs-sm);
  color: var(--muted);
}

/* What I offer — five layers, from AI/ML down to devices. Each layer is a tinted band, lightest at the
   top (models) and deepest at the bottom (devices). The band is drawn behind the row and reaches past
   the text, so the text stays on the page grid. With a mouse, the hovered band lifts slightly. */
.stack {
  display: grid;
  grid-template-columns: minmax(0, 1fr);   /* a long line can never widen the bands past the page */
  gap: 4px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.stack-row {
  position: relative;
  isolation: isolate;
  display: grid;
  gap: 0.375rem var(--gap);
  padding: clamp(0.875rem, 0.4rem + 1.4vw, 1.75rem) var(--band-inset, 0);
  transition: transform 0.25s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.stack-row::before {
  content: "";
  position: absolute;
  inset: 0 calc(-1 * var(--bleed));
  z-index: -1;
  border-radius: var(--radius);
  background: var(--layer, var(--panel));
  transition: box-shadow 0.25s ease;
}
/* Keeps the pointer over a lifted row, so its bottom edge never flickers between hover states. */
.focus .rows > li::after,
.stack-row::after {
  content: "";
  position: absolute;
  right: 0;
  bottom: -2px;
  left: 0;
  height: 2px;
}
.stack-row:nth-child(1) { --layer: var(--layer-1); }
.stack-row:nth-child(2) { --layer: var(--layer-2); }
.stack-row:nth-child(3) { --layer: var(--layer-3); }
.stack-row:nth-child(4) { --layer: var(--layer-4); }
.stack-row:nth-child(5) { --layer: var(--layer-5); }
@media (max-width: 47.99rem) {
  .stack { --band-inset: 0.5rem; }   /* phones: a little more room inside each band */
}
.stack-domain {
  display: flex;
  align-items: baseline;
  margin: 0;
  font-family: var(--serif);
  font-size: var(--fs-lg);
  font-weight: 300;
  line-height: 1.15;
  letter-spacing: -0.01em;
}
.stack-index {
  flex: none;
  width: 3rem;
  font: 400 var(--fs-xs) / 1 var(--mono);
  letter-spacing: 0.06em;
  color: var(--muted);
}
.stack-lines {
  margin: 0;
  padding: 0 0 0 3rem;
  list-style: none;
  line-height: 1.5;
  color: var(--ink-soft);
}
.stack-lines li { text-wrap: balance; }   /* short skill lines break at phrases, never on a lone word */
.stack-lines li + li { margin-top: 0.375rem; }

/* Publications */
.pubs {
  margin: 0;
  padding: 0;
  list-style: none;
}
.pub { border-bottom: 1px solid var(--rule); }
.pub:first-child { border-top: 1px solid var(--rule); }

/* Title (an h3 holding the link) under its mono venue line; the link covers the whole text block. */
.pub-text {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  column-gap: var(--s3);
  row-gap: 0.375rem;
  padding-block: var(--s2);
}
.pub-meta {
  grid-row: 1;
  grid-column: 1;
  margin: 0;
  font: 400 var(--fs-xs) / 1.4 var(--mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  transition: color 0.2s ease;
}
.pub-title {
  grid-row: 2;
  grid-column: 1;
  margin: 0;
  font-family: var(--serif);
  font-size: var(--fs-md);
  font-weight: 300;
  line-height: 1.3;
  text-wrap: balance;
}
.pub-title a {
  text-decoration: none;
  transition: color 0.2s ease;
}
.pub-title a::after {
  content: "";
  position: absolute;
  inset: 0;
}
.pub-arrow {
  grid-row: 1 / span 2;
  grid-column: 2;
  margin-top: 0.125rem;
  color: var(--muted);
}

/* Phones: each paper's figure at full column width but limited height, never cropped.
   The inset is padding on the image, never on the box: on tablets and desktops the box keeps
   its shape with aspect-ratio, which WebKit applies inside the padding, so a padded box grew
   taller there and the figure spilled past the plate. */
.pub-fig {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  height: clamp(9.5rem, 42vw, 13rem);
  margin: 0 0 1.25rem;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--panel);
}
.pub-fig img {
  width: 100%;
  height: 100%;
  padding: 0.5rem;
  object-fit: contain;
  mix-blend-mode: multiply;
}
/* Copyright line for figures from IEEE papers, set in the image's bottom padding so it never touches the figure. */
.pub-credit {
  position: absolute;
  right: 0.5rem;
  bottom: 0.3125rem;
  font: 400 0.625rem / 1 var(--mono);
  letter-spacing: 0.04em;
  color: var(--muted);
}
@media (max-width: 47.99rem) {
  .pub-fig:has(.pub-credit) img { padding-bottom: 1.25rem; }   /* phones: the usual 0.5rem is too thin for it */
}

.more {
  margin: var(--s3) 0 0;
  font-size: var(--fs-sm);
}

/* Elsewhere: one quiet line between Publications and Contact, pointing to the notebook site */
.elsewhere {
  margin-block: 0;
  padding-block: clamp(1rem, 0.5rem + 1.5vw, 1.75rem);
  border-top: 1px solid var(--rule);
  font: 400 var(--fs-xs) / 1.6 var(--mono);
}

/* Contact */
#contact { padding-bottom: var(--s5); }

.link-list {
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--rule);
}
.link-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  column-gap: var(--s3);
  align-items: baseline;
  padding-block: clamp(0.875rem, 0.5rem + 1vw, 1.5rem);
  border-bottom: 1px solid var(--rule);
  text-decoration: none;
}
.link-list li:last-child .link-row { border-bottom: 0; }
.link-name {
  font-family: var(--serif);
  font-size: var(--fs-lg);
  font-weight: 300;
  line-height: 1.15;
  letter-spacing: -0.01em;
  transition: color 0.2s ease;
}
.link-meta {
  grid-row: 2;
  margin-top: 0.25rem;
  font: 400 var(--fs-sm) / 1.5 var(--mono);
  letter-spacing: -0.01em;
  color: var(--muted);
  overflow-wrap: anywhere;
}
.link-arrow {
  grid-column: 2;
  grid-row: 1 / span 2;
  align-self: center;
  color: var(--muted);
}

/* ---------- Footer ---------- */
.site-footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s1) var(--s4);
  padding-block: var(--s3) var(--s4);
  border-top: 1px solid var(--rule);
  font: 400 var(--fs-xs) / 1.5 var(--mono);
  letter-spacing: 0.04em;
  color: var(--muted);
}
.site-footer p { margin: 0; }
.site-footer ul {
  display: flex;
  flex-wrap: wrap;
  column-gap: var(--s3);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* ---------- Hover (pointer devices only) ---------- */
@media (hover: hover) {
  .wordmark:hover,
  .nav a:hover,
  .quiet-links a:hover,
  .more a:hover,
  .elsewhere a:hover,
  .site-footer a:hover {
    color: var(--accent);
    text-decoration-color: currentColor;
  }
  .button:hover { background: var(--accent); }
  .button:hover .i { transform: translateY(2px); }
  .fig-toggle:hover { border-color: var(--ink); }
  .pub-text:hover .pub-title a,
  .pub-text:hover .pub-arrow { color: var(--accent); }
  .pub-text:hover .pub-arrow { transform: translate(2px, -2px); }
  .more a:hover .i,
  .elsewhere a:hover .i { transform: translate(2px, -2px); }
  .link-row:hover .link-name,
  .link-row:hover .link-arrow { color: var(--accent); }
  .link-row:hover .link-arrow { transform: translateX(3px); }
  /* Focus areas and What I offer share one hover: the plate lifts 2px onto a soft shadow. */
  .focus .rows > li:hover,
  .stack-row:hover { z-index: 1; transform: translateY(-2px); }
  .focus .rows > li:hover::before { opacity: 1; }
  .focus .rows > li:hover::before,
  .stack-row:hover::before {
    box-shadow: 0 14px 28px -16px rgba(14, 27, 46, 0.4), 0 2px 6px -2px rgba(14, 27, 46, 0.12);
  }
}

/* Whole-row focus rings for the stretched links (the link's own ring is replaced). */
@supports selector(:has(a:focus-visible)) {
  .pub-title a:focus-visible { outline: none; }
  .pub-text:has(a:focus-visible) {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: 2px;
  }
  .pub-text:has(a:focus-visible) .pub-title a { color: var(--accent); }
}

/* ---------- Small tablets and up ---------- */
@media (min-width: 30rem) {
  .edu-rows > div {
    grid-template-columns: 7rem minmax(0, 1fr);
    column-gap: var(--s3);
  }
}

@media (min-width: 48rem) {
  .about-meta,
  .stack-row,
  .link-row {
    grid-template-columns: repeat(12, minmax(0, 1fr));
    column-gap: var(--gap);
  }
  .about-meta { margin-top: var(--s6); }
  .focus { grid-column: 1 / span 5; }
  .edu { grid-column: 6 / -1; }

  .stack-row { align-items: baseline; }
  .stack-domain { grid-column: 1 / span 5; }
  .stack-lines { grid-column: 6 / -1; padding-left: 0; }

  /* Publications on tablets and touch screens: each paper beside its own figure. */
  .pub {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    column-gap: var(--gap);
    align-items: start;
    padding-block: var(--s3);
  }
  .pub-text { grid-column: 1 / span 5; padding-block: 0; }
  .pub-fig {
    grid-column: 6 / -1;
    height: auto;
    aspect-ratio: 2 / 1;
    margin: 0;
  }
  .pub-fig img { padding: var(--s2); }
  .pub-credit { right: var(--s2); bottom: 0.1875rem; }

  .link-name { grid-column: 1 / span 5; }
  .link-meta { grid-column: 6 / span 6; grid-row: 1; margin: 0; }
  .link-arrow { grid-column: 12; grid-row: 1; justify-self: end; }
}

/* ---------- Desktop ---------- */
@media (min-width: 64rem) {
  /* Copy in five columns, Fig. 1 in seven. The figure stretches to the height of the copy,
     so the lattice never pushes the CV button below the fold. */
  .hero { align-items: stretch; }
  .hero-copy { grid-column: 1 / span 5; align-self: center; }
  .hero-fig {
    grid-column: 6 / -1;
    grid-template-rows: minmax(16rem, 1fr) auto;
  }
  .lattice { aspect-ratio: auto; }

  .about {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    column-gap: var(--gap);
    align-items: start;
  }
  .portrait { float: none; grid-column: 1 / span 5; width: 15rem; max-width: 100%; margin: 0; }
  .prose { grid-column: 6 / -1; }
}

/* Publications with a pointer: the list in five columns, one figure plate in the other seven.
   The plate (::before) stays put; only the active paper's figure is shown on it.
   Touch screens keep the tablet layout (each paper beside its own figure). */
@media (min-width: 64rem) and (hover: hover) {
  .pub { display: block; padding-block: 0; }
  .pub-text { padding-block: var(--s3); }

  .pubs {
    --plate: 1.6;   /* the plate's width / height: 16:10 suits the figures, which are all 1.7 to 2 times wider than tall */
    position: relative;
    padding-right: calc((100% - 11 * var(--gap)) / 12 * 7 + 7 * var(--gap));
    /* never shorter than the plate, however few papers are listed */
    min-height: calc(((min(100vw - 2 * var(--gutter), var(--max)) - 11 * var(--gap)) / 12 * 7 + 6 * var(--gap)) / var(--plate));
  }
  .pubs::before,
  .pub-fig {
    position: absolute;
    top: 0;
    right: 0;
    width: calc((100% - 11 * var(--gap)) / 12 * 7 + 6 * var(--gap));
    height: auto;
    aspect-ratio: var(--plate);
  }
  .pubs::before {
    content: "";
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    background: var(--panel);
  }
  .pub-fig {
    display: none;
    margin: 0;
    border: 0;
    background: none;
  }
  .pub-fig img { padding: var(--s4); }
  .pub-credit { right: var(--s4); bottom: 0.6875rem; }
  .pub.is-active .pub-fig { display: flex; }
  .pub.is-active .pub-meta { color: var(--accent); }
  /* Fade the image in once the visitor is using the list (never on load or on breakpoint changes). */
  .pubs.is-live .pub.is-active .pub-fig img,
  .pubs.is-live .pub.is-active .pub-credit { animation: plate-in 0.25s ease both; }
}

@keyframes plate-in { from { opacity: 0; } }

/* ---------- Motion ---------- */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition-duration: 0.01ms !important;
    animation: none !important;
  }
  .focus .rows > li:hover,
  .stack-row:hover { transform: none; }   /* the plate still appears with its shadow, without moving */
}
