/* ============================================================
   Malhar Bagi — Portfolio
   "Objects" variant: projects share one stage of interactive hairline figures.

   One grid runs the page. The content column is a whole number of square
   cells (12 on desktop, 8 on tablet, 6 on phone) and the background draws
   exactly those cells, so every column edge is a visible line. Section
   paddings are whole cells, and grid.js rounds each section's height up to
   a whole cell, so every section starts on a horizontal line.
   ============================================================ */

:root {
  --bg: #FAFAFA;
  --surface: #FFFFFF;
  --ink: #0A0A0A;
  --ink-2: #3A3A3A;   /* lede, nav */
  --ink-3: #5A5A5A;   /* body copy */
  --ink-4: #737373;   /* labels, inactive titles (4.6:1 on --bg) */
  --line: rgba(10, 10, 10, 0.09);
  --line-strong: rgba(10, 10, 10, 0.18);
  --grid-line: rgba(10, 10, 10, 0.05);
  --accent: #3f80c8;
  --accent-link: #316cae;

  --sans: 'Geist', -apple-system, BlinkMacSystemFont, Helvetica, sans-serif;
  --mono: 'Geist Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  --serif: 'STIX Two Text', 'Times New Roman', serif;

  /* type scale: seven steps, nothing in between */
  --fs-title: 40px;
  --fs-heading: 18px;
  --fs-lede: 18px;
  --fs-body: 15px;
  --fs-ui: 14px;
  --fs-label: 12px;

  --r: 12px;
  --shadow: 0 1px 2px rgba(10, 10, 10, 0.04), 0 18px 40px -24px rgba(10, 10, 10, 0.28);
  --ease: cubic-bezier(.2, .8, .2, 1);
}
@supports (color: oklch(0.62 0.13 250)) {
  :root { --accent: oklch(0.62 0.13 250); --accent-link: oklch(0.55 0.12 250); }
}

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

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--fs-body);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

a { color: inherit; text-decoration: none; }
h1, h2, h3, p, figure { margin: 0; }
::selection { background: var(--ink); color: var(--bg); }

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

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: 10px 16px;
  background: var(--ink);
  color: var(--bg);
  font-size: var(--fs-ui);
  border-radius: 0 0 8px 0;
}
.skip:focus { left: 0; }

/* ---------- shared type ---------- */

.label {
  font-family: var(--mono);
  font-size: var(--fs-label);
  line-height: 1.4;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-4);
  font-variant-numeric: tabular-nums;
}

/* ---------- the grid ---------- */

.page {
  position: relative;
  min-height: 100vh;
  overflow-x: clip;
  container-type: inline-size;

  --cells: 12;
  --gutter: 40px;
  --max: 1184px;
  /* one cell, in whole pixels so the background lines stay crisp */
  --cell: calc((min(100cqw, var(--max)) - 2 * var(--gutter)) / var(--cells));
  --shell: calc(var(--cell) * var(--cells));
  /* how far text hangs below the grid line it starts from */
  --inset: calc(var(--cell) * 0.18);
}
@supports (width: round(down, 10.5px, 1px)) {
  .page { --cell: round(down, (min(100cqw, var(--max)) - 2 * var(--gutter)) / var(--cells), 1px); }
}

.shell {
  width: var(--shell);
  margin-inline: auto;
}

/* the background draws the cells: a tile's left edge sits on the page centre,
   which is a column edge at every cell count */
.grid-field {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    linear-gradient(to right, var(--grid-line) 1px, transparent 1px),
    linear-gradient(to bottom, var(--grid-line) 1px, transparent 1px);
  background-size: var(--cell) var(--cell);
  background-position: calc(50% + var(--cell) / 2) 0;
}

/* every section opens on a grid line; no rule of its own, the grid is the rule */
.section {
  position: relative;
  padding-bottom: var(--cell);
}

/* eyebrow + title fill exactly one cell: the eyebrow hangs from the top line,
   the title stands on the bottom one, both the same inset away. Content starts
   on that bottom line. text-box trims the leading so the inset is measured to
   the letters themselves. */
.section-head {
  min-height: var(--cell);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 8px;
  padding-block: var(--inset);
}
.section-head > * { text-box: trim-both cap alphabetic; }
.section-title {
  font-size: var(--fs-title);
  line-height: 1;
  letter-spacing: -0.035em;
  font-weight: 600;
}

/* ---------- floating nav ---------- */

.nav {
  position: fixed;
  top: 20px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 50;
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 6px;
  border-radius: 999px;
  background: linear-gradient(to bottom, rgba(255, 255, 255, 0.72), rgba(255, 255, 255, 0.44));
  backdrop-filter: blur(22px) saturate(200%);
  -webkit-backdrop-filter: blur(22px) saturate(200%);
  border: 1px solid rgba(255, 255, 255, 0.7);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.9),
    0 1px 2px rgba(10, 10, 10, 0.05),
    0 12px 34px -8px rgba(10, 10, 10, 0.18);
}

.nav-pill {
  position: absolute;
  top: 6px;
  bottom: 6px;
  left: 6px;
  width: 0;
  opacity: 0;
  border-radius: 999px;
  background: rgba(10, 10, 10, 0.06);
  pointer-events: none;
  transition: left .34s var(--ease), width .34s var(--ease), opacity .2s ease;
}

.nav-link {
  position: relative;
  z-index: 1;
  padding: 8px 14px;
  border-radius: 999px;
  font-size: var(--fs-ui);
  line-height: 1.3;
  color: var(--ink-2);
  transition: color .2s ease;
  white-space: nowrap;
}
.nav-link:hover { color: var(--ink); }

.nav-link--brand {
  font-weight: 500;
  background: var(--ink);
  color: var(--bg);
  transition: opacity .2s ease;
}
.nav-link--brand:hover { opacity: .86; color: var(--bg); }

/* ---------- hero ---------- */

/* copy in columns 1–5, the plot in 6–12: a 6 wide × 5 tall cell plot plus
   one cell of margin on the left and below for the axis labels, so its axes
   and corners land on grid lines. The copy is exactly as tall as the plot and
   shares its top line: the title's cap height starts where the y-axis does
   and the now-block fills the last cell, its rule on line 4. The lede sits
   centred between the foot of the title and that rule. */
.hero {
  position: relative;
  padding-top: calc(var(--cell) * 2);
  display: grid;
  grid-template-columns: repeat(var(--cells), minmax(0, 1fr));
  align-items: start;
  /* grid.js rounds the hero up to whole cells; the slack goes below, not between rows */
  align-content: start;
  cursor: crosshair;
}
.hero a, .hero-copy { cursor: auto; }
.hero a { cursor: pointer; }

.hero-copy {
  grid-column: 1 / 6;
  grid-row: 1;
  height: calc(var(--cell) * 5);
  display: flex;
  flex-direction: column;
}

/* one cell per em, so the type scales with the grid */
.hero-title {
  font-size: max(48px, var(--cell));
  line-height: 0.9;
  letter-spacing: -0.05em;
  font-weight: 600;
  text-box: trim-both cap alphabetic;
}

.hero-lede {
  /* auto margins share the space above and below it equally */
  margin-block: auto;
  max-width: calc(var(--cell) * 4);
  font-size: var(--fs-lede);
  line-height: 1.55;
  color: var(--ink-2);
  text-wrap: pretty;
  text-box: trim-both cap alphabetic;
}

.hero-now {
  flex: none;
  height: var(--cell);
  padding-top: var(--inset);
  border-top: 1px solid var(--line-strong);
  width: calc(var(--cell) * 5);
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: var(--fs-lede);
  color: var(--ink-3);
}
.hero-now a { font-weight: 500; color: var(--ink); transition: color .2s ease; }
.hero-now a:hover { color: var(--accent-link); }

/* ---------- indifference field ---------- */

.field {
  grid-column: 6 / 13;
  grid-row: 1;
  position: relative;
  touch-action: pan-y;
  user-select: none;
  -webkit-user-select: none;
  --plot-cells: 5;
  --plot-cols: 6;
}
.field-svg { display: block; width: 100%; aspect-ratio: 1; height: auto; overflow: visible; }
.field-serif { font-family: var(--serif); }
.field-accent-stroke { stroke: var(--accent); }
.field-accent-fill { fill: var(--accent-link); }
#fieldHalo { fill: var(--accent); }

/* the readout card sits in the plot's top-right cells, its corner on the grid
   corner. While the pointer, the point or the portrait is under it, hero.js
   sets .is-tucked and it folds into a one-line chip in the same corner. */
.field-card {
  position: absolute;
  right: 0;
  top: 0;
  width: calc(var(--cell) * 2);
  min-width: max-content;
  min-height: var(--cell);
  padding: 10px 14px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 7px;
  border-radius: var(--r);
  border: 1px solid var(--line-strong);
  background: rgba(255, 255, 255, 0.94);
  font-family: var(--serif);
  color: var(--ink);
  pointer-events: none;
  transform-origin: top right;
  transition: opacity .25s ease, transform .35s var(--ease);
}
.field-chip {
  position: absolute;
  right: 0;
  top: 0;
  padding: 5px 10px;
  border-radius: var(--r);
  border: 1px solid var(--line-strong);
  background: rgba(255, 255, 255, 0.94);
  font-family: var(--serif);
  font-size: 13px;
  line-height: 1.35;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transform: scale(1.4);
  transform-origin: top right;
  transition: opacity .2s ease, transform .35s var(--ease);
}
.field.is-tucked .field-card { opacity: 0; transform: scale(0.3); }
.field.is-tucked .field-chip { opacity: 1; transform: none; transition-delay: .08s; }
.field-eq { font-size: 16px; line-height: 1.2; white-space: nowrap; }
.field-eq sup { font-size: 10px; }
.field-vals {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding-top: 7px;
  border-top: 1px solid var(--line);
  font-size: 13px;
  line-height: 1.35;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.field-vals sub { font-size: 9px; }

/* the portrait rides the chosen bundle; hero.js sets left/top to the point and flips it near the edges */
.field-me {
  position: absolute;
  left: 0;
  top: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  pointer-events: none;
  transform: translate(18px, calc(-100% - 18px));
}
.field-me.is-left { flex-direction: row-reverse; transform: translate(calc(-100% - 18px), calc(-100% - 18px)); }
.field-me.is-below { transform: translate(18px, 18px); }
.field-me.is-left.is-below { transform: translate(calc(-100% - 18px), 18px); }
.field-me img {
  display: block;
  width: 64px;
  height: 64px;
  border-radius: 999px;
  object-fit: cover;
  border: 2px solid var(--surface);
  box-shadow: 0 0 0 1px var(--line-strong), 0 8px 18px -8px rgba(10, 10, 10, 0.4);
}

/* ---------- lists (projects and background share one row style) ---------- */

/* Rows run exactly from one column line to another, so the separator (the
   row's own top border, bent away at both ends by the rounded corners) never
   reaches past the grid. Text sits 16px in; the first column is a cell less
   that inset, so the titles still start on a column line. */
.row {
  position: relative;
  display: grid;
  grid-template-columns: calc(var(--cell) - 16px) minmax(0, 1fr) auto;
  align-items: baseline;
  align-content: start;
  /* one cell, the title (~23px) centred in it, like a project row */
  padding: calc((var(--cell) - 23px) / 2) 16px 16px;
  min-height: var(--cell);
  border-radius: var(--r);
  border-top: 1px solid var(--line);
  transition: background .25s ease, box-shadow .25s ease, border-color .2s ease, min-height .38s var(--ease);
}
:is(.proj-list li:first-child .proj, .row:first-child) { border-top-color: var(--line-strong); }

.item-title {
  font-size: var(--fs-heading);
  line-height: 1.3;
  letter-spacing: -0.015em;
  font-weight: 500;
}
.item-text {
  font-size: var(--fs-body);
  line-height: 1.55;
  color: var(--ink-3);
  text-wrap: pretty;
}

/* ---------- work ---------- */

/* the list takes columns 1–6, the stage 7–12. The section plays itself: each
   project gets one demo lap of its figure, then the next comes up. Pointer or
   focus in the section pauses it. */
.projects {
  display: grid;
  grid-template-columns: repeat(var(--cells), minmax(0, 1fr));
  align-items: stretch;
  align-content: start;
}

.proj-list {
  grid-column: 1 / 7;
  display: flex;
  flex-direction: column;
  list-style: none;
  margin: 0;
  padding: 0;
}

.proj {
  all: unset;
  box-sizing: border-box;
  cursor: pointer;
  position: relative;
  width: 100%;
  display: grid;
  /* number in the first column, year in the last, both starting on a column line */
  grid-template-columns: calc(var(--cell) - 16px) minmax(0, 1fr) calc(var(--cell) - 16px);
  align-items: baseline;
  /* the title (~23px) centred in the first cell */
  padding: calc((var(--cell) - 23px) / 2) 16px 16px;
  /* rows are one cell, the open one two, so every separator is a grid line */
  min-height: var(--cell);
  border-radius: var(--r);
  border-top: 1px solid var(--line);
  transition: background .25s ease, box-shadow .25s ease, min-height .38s var(--ease), border-color .2s ease;
}
.proj[aria-pressed="true"] { min-height: calc(var(--cell) * 2); }
/* same lifted card as a background row on hover */
.proj:hover { background: var(--surface); box-shadow: var(--shadow); }
.proj:hover,
.proj-list li:hover + li .proj { border-top-color: transparent; }
.proj:focus-visible { outline: 2px solid var(--ink); outline-offset: -2px; }

.proj-n,
.proj-year,
.row-when,
.row-place { transition: color .25s ease; }

.proj-title {
  color: var(--ink-4);
  text-wrap: balance;
  transition: color .25s ease;
}
.proj[aria-pressed="true"] .proj-title,
.proj:hover .proj-title { color: var(--ink); }
.proj[aria-pressed="true"] .proj-n { color: var(--accent-link); }

.proj-main { display: flex; flex-direction: column; min-width: 0; }
.proj-year { white-space: nowrap; }
.proj-more {
  display: grid;
  grid-template-rows: 0fr;
  opacity: 0;
  transition: grid-template-rows .38s var(--ease), opacity .25s ease;
}
.proj-more > span { overflow: hidden; display: flex; flex-direction: column; }
.proj[aria-pressed="true"] .proj-more {
  grid-template-rows: 1fr;
  opacity: 1;
  transition: grid-template-rows .38s var(--ease), opacity .3s ease .1s;
}
.proj-blurb { padding-top: 8px; max-width: 50ch; }

/* the cycle's progress: a hairline under the active row */
.proj-progress {
  position: absolute;
  left: 16px;
  right: 16px;
  bottom: 0;
  height: 1.5px;
  background: var(--ink);
  transform-origin: left;
  transform: scaleX(0);
  opacity: 0;
  pointer-events: none;
}
.proj-progress.run { opacity: 1; animation: proj-fill var(--lap, 7000ms) linear forwards; }
.cycle-paused .proj-progress.run { opacity: 0.18; animation-play-state: paused; }
@keyframes proj-fill { to { transform: scaleX(1); } }

/* the stage fills columns 7–12 and the block's whole height (a whole number of cells);
   each figure keeps its 5:4 box, centred in it */
.stage-col { grid-column: 7 / 13; display: flex; flex-direction: column; min-width: 0; }
.stage {
  position: relative;
  flex: 1;
  width: 100%;
  min-height: calc(var(--cell) * 5);
  border-radius: var(--r);
  overflow: hidden;
  container-type: size;
  border: 1px solid var(--line-strong);
  background: var(--surface);
  box-shadow: var(--shadow);
  --hairline-stroke: 1;
}
.stage-layer {
  position: absolute !important;
  inset: 0;
  margin: auto;
  width: min(100cqw, 125cqh);
  height: min(80cqw, 100cqh);
  aspect-ratio: auto !important;
  opacity: 0;
  visibility: hidden;
  transition: opacity .45s var(--ease), visibility 0s linear .45s;
}
.stage-layer.on { opacity: 1; visibility: visible; transition: opacity .45s var(--ease) .08s, visibility 0s; }

.stage-tag {
  position: absolute;
  left: 20px;
  right: 20px;
  bottom: 16px;
  z-index: 3;
  pointer-events: none;
  display: flex;
  justify-content: space-between;
  gap: 12px;
  transition: opacity .25s ease;
}
.stage-tag.swap { opacity: 0; }
.stage-tag span { white-space: nowrap; }
.stage-tag span:first-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; }

/* ---------- about ---------- */

/* rows in columns 1–8, tools in 10–12. The block keeps one spare cell for
   the row that opens on hover, and that cell is the section's bottom space. */
.about { padding-bottom: 0; }
.about-body {
  display: grid;
  grid-template-columns: repeat(var(--cells), minmax(0, 1fr));
  align-content: start;
}
.rows { grid-column: 1 / 9; display: flex; flex-direction: column; }

.row:hover,
.row:focus-visible,
.row:focus-within {
  background: var(--surface);
  box-shadow: var(--shadow);
  outline: none;
  /* an open row grows by exactly one cell, so the rows under it stay on the
     grid (important: it beats the min-height grid.js writes inline) */
  min-height: calc(var(--cell) * 2) !important;
}
.row:hover,
.row:focus-within,
.row:hover + .row,
.row:focus-within + .row { border-top-color: transparent; }


.row-more {
  /* opens the way a project's blurb does */
  display: grid;
  grid-template-rows: 0fr;
  opacity: 0;
  transition: grid-template-rows .38s var(--ease), opacity .25s ease;
}
.row-more > div { overflow: hidden; }
.row-more p { padding-top: 8px; max-width: 56ch; }
.row:hover .row-more,
.row:focus-visible .row-more,
.row:focus-within .row-more {
  grid-template-rows: 1fr;
  opacity: 1;
  transition: grid-template-rows .38s var(--ease), opacity .3s ease .1s;
}
.row-when { white-space: nowrap; letter-spacing: 0; }
/* At rest the place column names the organisation; an open row swaps the
   name for its logo and one line on who they are. Both fold the way the
   blurb does, so the row grows only by what it shows. */
.row-place {
  width: calc(var(--cell) * 2);
  box-sizing: border-box;
  padding: 5px 0 0 16px;
  display: grid;
  /* pinned to the top, not the baseline: the logo's top meets the title's
     cap height (5px into its line), and the name's baseline meets the title's */
  align-self: start;
}
.row-org > span { padding-top: 1px; }
.row-org,
.row-about {
  display: grid;
  transition: grid-template-rows .38s var(--ease), opacity .25s ease;
}
.row-org { grid-template-rows: 1fr; }
.row-about { grid-template-rows: 0fr; opacity: 0; }
.row-org > span,
.row-about > span { overflow: hidden; min-height: 0; }
.row-about > span { display: flex; flex-direction: column; align-items: flex-start; gap: 10px; }
.row-about-text {
  font-size: var(--fs-ui);
  line-height: 1.4;
  color: var(--ink-3);
  text-wrap: pretty;
}
/* logos are flattened to one grey so they read as a quiet mark, not branding */
.row-logo {
  display: block;
  width: auto;
  filter: brightness(0);
  opacity: .75;
}
.row-logo.logo-torggler { height: 16px; }
.row-logo.logo-nude { height: 24px; }
.row-logo.logo-aalto { height: 28px; }
/* on touch the name never folds away: the detail is always open there */
@media (hover: hover) {
  .row:hover .row-org,
  .row:focus-visible .row-org,
  .row:focus-within .row-org { grid-template-rows: 0fr; opacity: 0; }
}
.row:hover .row-about,
.row:focus-visible .row-about,
.row:focus-within .row-about {
  grid-template-rows: 1fr;
  opacity: 1;
  transition: grid-template-rows .38s var(--ease), opacity .3s ease .1s;
}

.kit {
  grid-column: 10 / 13;
  padding-top: calc((var(--cell) - 23px) / 2);
  border-top: 1px solid var(--line-strong);
}
.tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 14px 0 0;
  padding: 0;
  list-style: none;
}
.tags li {
  padding: 6px 12px;
  border-radius: 999px;
  border: 1px solid var(--line-strong);
  background: var(--bg);
  color: var(--ink-3);
}

/* ---------- footer ---------- */

.footer-inner {
  min-height: var(--cell);
  display: flex;
  flex-wrap: wrap;
  align-content: center;
  align-items: last baseline;
  justify-content: space-between;
  gap: 24px;
}

.footer-mail {
  display: inline-block;
  font-size: var(--fs-lede);
  color: var(--ink-2);
  border-bottom: 1px solid var(--line-strong);
  transition: color .2s ease, border-color .2s ease;
}
.footer-mail:hover { color: var(--ink); border-color: var(--ink); }

.footer-links { display: flex; gap: 24px; }
.footer-links a { transition: color .2s ease; }
.footer-links a:hover { color: var(--ink); }

/* ---------- project paper ---------- */

html.paper-lock { overflow: hidden; }
html.paper-lock body { padding-right: var(--scrollbar, 0px); }

/* the paper lies over a quieter copy of the grid, as wide as the page's
   twelve columns, so its edges sit on column lines. paper.js copies the
   page's cell. */
.paper {
  --cell: 92px;
  position: fixed;
  inset: 0;
  z-index: 60;
  background: rgba(242, 242, 241, 0.86);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  outline: none;
  opacity: 0;
  transition: opacity .24s ease;
}
.paper.is-open { opacity: 1; }
.paper[hidden] { display: none; }
.paper-scroll {
  position: absolute;
  inset: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  background-image:
    linear-gradient(to right, var(--grid-line) 1px, transparent 1px),
    linear-gradient(to bottom, var(--grid-line) 1px, transparent 1px);
  background-size: var(--cell) var(--cell);
  background-position: calc(50% + var(--cell) / 2) 0;
  background-attachment: local;
}

.sheet {
  position: relative;
  width: calc(var(--cell) * 12);
  margin: var(--cell) auto;
  padding: var(--cell) 0;
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  align-items: start;
  background: var(--surface);
  box-shadow: 0 0 0 1px rgba(10, 10, 10, 0.08), 0 1px 2px rgba(10, 10, 10, 0.04), 0 30px 60px -30px rgba(10, 10, 10, 0.3);
  opacity: 0;
  transform: translateY(40px) scale(.985);
  transition: transform .22s ease-in, opacity .2s ease;
}
.paper.is-open .sheet {
  opacity: 1;
  transform: none;
  transition: transform .5s var(--ease), opacity .35s ease;
}

.sheet-margin {
  grid-column: 1;
  grid-row: 1 / span 2;
  justify-self: center;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  white-space: nowrap;
}

.sheet-main { grid-column: 2 / 9; padding-right: 48px; min-width: 0; }
.sheet-side { grid-column: 9 / 12; padding-top: var(--cell); min-width: 0; height: 100%; }
.sheet-side-in { position: sticky; top: 24px; }

.sheet-title {
  margin-top: 14px;
  font-size: var(--fs-title);
  line-height: 1.05;
  letter-spacing: -0.035em;
  font-weight: 600;
  text-wrap: balance;
}
.sheet-org { margin-top: 18px; }
.sheet-year { margin-top: 4px; }
.sheet-eyebrow { color: var(--ink); }
.sheet-org + .sheet-year + .sheet-eyebrow { margin-top: 28px; }
.sheet-abstract {
  margin-top: 8px;
  font-size: var(--fs-lede);
  line-height: 1.55;
  color: var(--ink-2);
  text-wrap: pretty;
}
.sheet-jel {
  margin-top: 20px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--ink-3);
}
.sheet-jel .sheet-eyebrow { margin-right: 6px; }
.sheet-jel-code {
  display: inline-flex;
  align-items: center;
  height: 28px;
  padding: 0 10px;
  border-radius: 6px;
  background: var(--ink);
  color: var(--bg);
  font-family: var(--mono);
  font-size: var(--fs-label);
}

.sheet-body { margin-top: 40px; border-top: 1px solid var(--line-strong); }
.sheet-sec { padding-top: 28px; scroll-margin-top: 24px; }
.sheet-h { display: flex; gap: 14px; align-items: baseline; margin-bottom: 12px; }
.sheet-h-n { color: var(--accent-link); }
.sheet-p {
  margin-bottom: 14px;
  line-height: 1.65;
  color: var(--ink-2);
  max-width: 68ch;
  text-wrap: pretty;
}
.sheet-p strong { font-weight: 500; color: var(--ink); }

.sheet-fig { display: flex; flex-direction: column; gap: 12px; }
.sheet-fig--body { margin: 24px 0 28px; }
.sheet-fig-box {
  display: flex;
  align-items: center;
  justify-content: center;
  border-top: 1px solid rgba(10, 10, 10, 0.2);
  border-bottom: 1px solid rgba(10, 10, 10, 0.2);
}
.sheet-fig-art { width: 100%; --hairline-stroke: 1; }
.sheet-fig-art svg { display: block; width: 100%; height: 100%; }
.sheet-fig-media { padding: 16px 0; }
.sheet-fig-media img {
  display: block;
  max-width: 100%;
  max-height: 560px;
  width: auto;
  height: auto;
}
.sheet-fig-chart { display: block; }
.sheet-fig-chart svg { display: block; width: 100%; height: auto; font-family: var(--sans); }
.sheet-cap { font-size: 13px; line-height: 1.5; color: var(--ink-3); }
.sheet-cap .label { color: var(--ink); margin-right: 8px; }

.sheet-table { margin: 24px 0 28px; }
.sheet-table-scroll { overflow-x: auto; margin-top: 8px; }
.sheet-table table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13.5px;
  line-height: 1.4;
  font-variant-numeric: tabular-nums;
  border-top: 1.5px solid var(--ink);
  border-bottom: 1.5px solid var(--ink);
}
.sheet-table th {
  font-weight: 500;
  text-align: left;
  vertical-align: bottom;
  padding: 9px 14px 8px 0;
  border-bottom: 1px solid rgba(10, 10, 10, 0.4);
}
.sheet-table td { padding: 8px 14px 8px 0; color: var(--ink-2); vertical-align: top; }
.sheet-table tr + tr td { border-top: 1px solid var(--line); }
.sheet-note { margin: -16px 0 24px; font-size: 12.5px; line-height: 1.5; color: var(--ink-4); }

.sheet-eq {
  margin: 20px 0 24px;
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  font-family: var(--serif);
  font-style: italic;
  font-size: 18px;
}
.sheet-eq span:first-child { text-align: center; white-space: nowrap; overflow-x: auto; }
.sheet-list { margin: 0 0 16px; padding-left: 22px; color: var(--ink-2); line-height: 1.65; max-width: 66ch; }
.sheet-list li { margin-bottom: 4px; padding-left: 4px; }

.sheet-cite { margin-top: 32px; }
.sheet-btn {
  height: 44px;
  padding: 0 18px;
  border-radius: 999px;
  border: 1px solid var(--line-strong);
  background: var(--surface);
  font: inherit;
  font-size: var(--fs-ui);
  color: var(--ink);
  cursor: pointer;
  transition: border-color .2s ease;
}
.sheet-btn:hover { border-color: rgba(10, 10, 10, 0.4); }
.sheet-bib {
  margin: 14px 0 0;
  padding: 14px 16px;
  border-radius: 8px;
  background: #F5F5F4;
  font-family: var(--mono);
  font-size: var(--fs-label);
  line-height: 1.6;
  color: var(--ink-2);
  overflow-x: auto;
}

.sheet-pager {
  margin-top: 48px;
  padding-top: 16px;
  border-top: 1px solid var(--line-strong);
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 24px;
}
.sheet-pg { display: flex; flex-direction: column; gap: 6px; padding: 10px 0; }
.sheet-pg[hidden] { display: none; }
.sheet-pg--next { grid-column: 2; text-align: right; }
.sheet-pg-title { font-weight: 500; color: var(--ink); transition: color .2s ease; }
.sheet-pg:hover .sheet-pg-title { color: var(--accent-link); }

.sheet-toc { margin-top: 32px; }
.sheet-toc ol { list-style: none; margin: 10px 0 0; padding: 0; border-top: 1px solid var(--line-strong); }
.sheet-toc li { border-bottom: 1px solid var(--line); }
.sheet-toc a {
  display: grid;
  grid-template-columns: 28px minmax(0, 1fr);
  gap: 6px;
  align-items: baseline;
  padding: 9px 0;
  font-size: var(--fs-ui);
  line-height: 1.3;
  color: var(--ink-4);
  transition: color .2s ease;
}
.sheet-toc a .label { transition: color .2s ease; }
.sheet-toc a:hover,
.sheet-toc a[aria-current] { color: var(--ink); }
.sheet-toc a[aria-current] .label { color: var(--accent-link); }

/* narrower desktops: one column, the figure above the text */
@media (max-width: 1000px) {
  .sheet-main { grid-column: 2 / 12; grid-row: 2; padding-right: 0; }
  .sheet-side { grid-column: 2 / 12; grid-row: 1; padding-top: 0; height: auto; margin-bottom: 32px; }
  .sheet-fig-art { max-width: 360px; }
  .sheet-side-in { position: static; }
  .sheet-toc { display: none; }
}
/* tablet and phone: the sheet takes the width, less a thin margin */
@media (max-width: 860px) {
  .sheet {
    width: auto;
    margin: 72px 12px 12px;
    padding: 40px 24px;
    grid-template-columns: minmax(0, 1fr);
  }
  .sheet-margin { display: none; }
  .sheet-main, .sheet-side { grid-column: 1; }
  .sheet-eq { font-size: 16px; gap: 8px; }
  .sheet-fig-art { max-width: 240px; }
}

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

/* narrower desktops: cells shrink, so blurbs wrap to more lines and the open
   row takes a third cell, and the lede widens and steps down a size to stay
   inside its two cells */
@media (max-width: 1180px) {
  .proj[aria-pressed="true"] { min-height: calc(var(--cell) * 3); }
}
/* smaller cells: the copy takes its whole five columns so the lede keeps to its two cells */
@media (max-width: 1120px) {
  .hero-lede { width: calc(var(--cell) * 5); max-width: none; }
}
@media (max-width: 1000px) {
  .hero-lede, .hero-now { font-size: var(--fs-body); }
  .section-head { gap: 4px; padding-block: calc(var(--cell) * 0.15); }
  /* the list gets the full width under the stage, so titles stay on one line */
  .proj-list { grid-column: 1 / -1; grid-row: 2; padding: var(--cell) 0 0; }
  .proj[aria-pressed="true"] { min-height: calc(var(--cell) * 2); }
  .proj-blurb { max-width: none; }
  .row:hover, .row:focus-visible, .row:focus-within { min-height: calc(var(--cell) * 3) !important; }
  .stage-col { grid-column: 1 / -1; grid-row: 1; }
  .stage { flex: none; min-height: 0; height: calc(var(--cell) * 6); }
}

/* tablet: 8 cells. The copy stacks above a 6-cell plot in columns 1–7. */
@media (max-width: 860px) {
  .page { --cells: 8; --gutter: 28px; }
  .hero { padding-top: calc(var(--cell) * 2); }
  .hero-copy { grid-column: 1 / -1; }
  .hero-lede, .hero-now { max-width: none; width: calc(var(--cell) * 5); }
  .hero-lede, .hero-now { font-size: var(--fs-lede); }
  .field { grid-column: 1 / 8; grid-row: 2; margin-top: var(--cell); --plot-cells: 6; --plot-cols: 6; }
  .rows { grid-column: 1 / -1; }
  /* full-width rows: the detail fits back in one extra cell */
  .row:hover, .row:focus-visible, .row:focus-within { min-height: calc(var(--cell) * 2) !important; }
  .row-more p { max-width: none; }
  .kit { grid-column: 1 / 6; margin-top: var(--cell); }
}

/* narrow tablet windows with a mouse: the detail needs a second extra cell */
@media (max-width: 740px) {
  .row:hover, .row:focus-visible, .row:focus-within { min-height: calc(var(--cell) * 3) !important; }
}

/* phone: 6 cells. The plot spans all six, a 5 × 5 cell plot plus its label margin. */
@media (max-width: 620px) {
  .page { --cells: 6; --gutter: 20px; }
  .nav { gap: 0; padding: 5px; top: 14px; }
  .nav-link { padding: 7px 11px; font-size: 13px; }
  .hero { padding-top: max(104px, round(up, 104px, var(--cell))); }
  .field { grid-column: 1 / -1; --plot-cells: 5; --plot-cols: 5; }
  /* the lede wraps to more lines than two cells hold, so the copy stacks freely */
  .hero-copy { display: block; height: auto; }
  .hero-now { height: auto; }
  .hero-lede { margin-top: var(--cell); }
  .hero-now { margin-top: calc(var(--cell) / 2); }
  .hero-lede, .hero-now { width: auto; }
  /* the card sits under the plot here, so it never needs to tuck away */
  .field-card { position: static; width: auto; margin-top: 16px; }
  .field.is-tucked .field-card { opacity: 1; transform: none; }
  .field-chip { display: none; }
  .field-me img { width: 44px; height: 44px; }
  .stage { height: calc(var(--cell) * 5); }
  .proj, .row { grid-template-columns: minmax(0, 1fr) auto; row-gap: 4px; padding-block: 16px; }
  .row { min-height: 0; }
  .proj { min-height: calc(var(--cell) * 2); }
  .proj[aria-pressed="true"] { min-height: calc(var(--cell) * 4); }
  .proj-n, .row-when { grid-column: 1; grid-row: 1; }
  .proj-year, .row-place { grid-column: 2; grid-row: 1; }
  .proj-main, .row-main { grid-column: 1 / -1; grid-row: 2; }
  /* the name stays beside the year; who they are runs under the text */
  .row-place { display: contents; }
  .row-org { grid-column: 2; grid-row: 1; padding-left: 16px; }
  .row-about { grid-column: 1 / -1; grid-row: 3; }
  .row-about > span { flex-direction: row; align-items: center; gap: 12px; padding-top: 10px; }
  .row:hover .row-org, .row:focus-visible .row-org, .row:focus-within .row-org { grid-template-rows: 1fr; opacity: 1; }
  .kit { grid-column: 1 / -1; }
  :root { --fs-title: 32px; }
}

/* On touch devices there is no hover, so the detail text is always shown. */
@media (hover: none) {
  .row-more { grid-template-rows: 1fr; opacity: 1; }
  .row-about { grid-template-rows: 1fr; opacity: 1; }
  .row-about > span { padding-top: 10px; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  .proj-progress.run { animation: none; opacity: 0; }
}
